Not affiliated with JPMorgan Chase.

Access controls · live on Postgres

Try to see what you shouldn't.

Pick a persona and a purpose. The database decides what comes back, the same way for this screen, the API and the AI analyst. Every request is logged.

506 of 506 policy checks pass24 persona-purpose contexts × 5 data products, run live on Postgres · Oct 31, 01:50 AM UTC
1 · Act as

External analyst at the co-brand partner. No cardholder rows; any cell under 25 cardholders is suppressed. Personas are switched here for demonstration; in production they come from signed identity claims.

2 · For which purpose

granted to this persona. Pick one that is not to see the database refuse.

3 · Which data product
What the database returned
…of … rows

Asking the database…

What the partner actually receives

Contracted aggregates, small cells suppressed

Each metric maps to a contract clause. The database hides any cell with fewer than 25 cardholders, value and count both.

Customer 360 · first rowsquerying…
No rows: the partner contract grants aggregates only. See what the partner receives above.

Why this result

Every layer the database applied to this request, in order.

  1. PassPurpose grant (RLS)The stated purpose is granted to this persona.
  2. BlocksConsumption grant (View)Aggregate-only under the partner contract: no cardholder rows.
  3. FiltersProgram scope (RLS)Partner persona: only its own program's rows.
  4. MasksColumn masking (View)Email and phone masked.
  5. LogsAccess log (Audit)Request recorded in the hash-chained access log.

Independent check

A second implementation of the same rules re-judges every row the database returned. Drift would show here in red.

checking…

Your access log

Every read is recorded and hash-chained. You see your own events only.

  • Your reads will appear here.
The policy SQL3 policies · show
cust_basepermissive · OR
create policy cust_base on atlas.customers
  for select to public using (true);

Baseline visibility for cardholder rows.

cust_purpose_grantedrestrictive · AND
create policy cust_purpose_granted on atlas.customers
  as restrictive for select to public
  using ((select atlas.ctx_purpose_granted()));

No cardholder rows unless the stated purpose is granted to the persona.

cust_partner_scoperestrictive · AND
create policy cust_partner_scope on atlas.customers
  as restrictive for select to public
  using ((select atlas.ctx_partner_scope()) is null
         or partner_scope = (select atlas.ctx_partner_scope()));

A partner persona only ever reaches its own program's cardholders.

Masking and the rows-versus-aggregates grant live in the security-barrier views every read goes through, including the AI analyst.

How it is enforcedtechnical detail

One door, least privilege

The public API key can read catalog metadata and nothing else. Every read of cardholder data is a database function that only the server can call. Each function runs as a role that cannot bypass Row Level Security, so the key that authorises the call does not decide what it sees.

Rows in policy, columns in views

Program scope, purpose grants and the fraud-detail gate are restrictive RLS policies on every fact table. Masking and the rows-versus-aggregates grant live in security-barrier views that are the only row-level read surface, for the simulator and the AI analyst alike.

Purpose-bound unmasking

A persona sees clear contact data only when its role AND the stated purpose allow it. The platform admin never does. A purpose that is not granted returns nothing at all, for every table.

Tested every time, logged every time

A self-test asserts the rules for every persona, purpose and data product against the live database (the badge above). Every read writes a hash-chained log row; recomputing the chain detects any edited row.