Test plan
Role × matter test matrix
For each role we run an identical query and record the row count and whether rows were filtered by policy.
| Query | ATTORNEY (Matter A) | ATTORNEY (Matter B) | AUDITOR |
|---|---|---|---|
| Select clauses for Matter A | Rows returned | 0 rows (policy) | Rows returned |
| Select clauses for Matter B | 0 rows (policy) | Rows returned | Rows returned |
| Select client contact email | Masked | Masked | Visible |
| Read GOV audit views | Denied | Denied | Allowed |
Key point
A policy-filtered query returns zero rows, not an error. Verification therefore
records row counts alongside the query ID, and confirms the policy is attached via
INFORMATION_SCHEMA.POLICY_REFERENCES.Evidence
Where the proof comes from
SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORY— who ran what, as which role, and when (note: ~45 min latency).SNOWFLAKE.ACCOUNT_USAGE.ACCESS_HISTORY— which columns/tables were touched.INFORMATION_SCHEMA.POLICY_REFERENCES— which policy is attached to which column/table.SNOWFLAKE.ACCOUNT_USAGE.ROW_ACCESS_POLICIES— policy definitions in effect.
SELECT query_id, user_name, role_name, start_time, query_text
FROM snowflake.account_usage.query_history
WHERE role_name IN ('ATTORNEY','AUDITOR')
AND query_text ILIKE '%fact_clause%'
ORDER BY start_time DESC;
Full queries: sql/05_audit_queries.sql.
Deliverable
Unresolved high-risk clauses by authorized matter
The closing artifact of the demo: for the signed-in role, list high-risk clauses on the matters they are authorized to see, with the contract, clause category, and score.
SELECT matter_id, matter_name, contract_type, clause_category,
risk_score, risk_band
FROM marts.mart_matter_risk
WHERE risk_band = 'High'
ORDER BY risk_score DESC;
Run as ATTORNEY_A and ATTORNEY_B, the same statement yields
two different, correctly scoped reports — the single clearest demonstration of the wall.
Ongoing
Continuous governance
- Alerts on policy changes (
POLICY_REFERENCESdiffs) and on unexpected role grants. - A weekly access-review report listing authorizations expiring within 30 days.
- Row-access tests re-run on a schedule so regressions are caught, not hoped for.