Replaces the original APAC-vs-all 2-user demo (vpduser_a/b on KR_ANALYSTS/GLOBAL_ADMINS groups) with a 2x2 source-access matrix: vpduser_my -> MY_ONLY group -> MySQL view only vpduser_pg -> PG_ONLY group -> Postgres view only vpduser_both -> BOTH_SOURCES group -> both views vpduser_none -> (no group) -> nothing (default deny) Why: source-level segmentation is the more common production permission story than region-level filtering. Region filtering remains available as an opt-in variant via commented UPDATE in sql/adb/03_seed.sql. Key changes: - 03_seed.sql, 07_end_users.sql, 00_cleanup.sql, .env.example, run.sh updated for the new 4-user model. All 4 users get identical view GRANTs; the only differentiator is the permission table (proves the model is "data-driven, not GRANT-driven"). - 08-11 split into one file per user: my (+ 5 bypass attempts), pg, both, none (default-deny verification). - 12_tests_admin_audit.sql uses LEFT JOIN so vpduser_none shows up as NULL permissions, and filters by object_owner=USER to exclude cross-schema policies. - Removed inline "-- comment" after ";" lines in 03_seed.sql: SQL*Plus silently skipped the inserts (documented gotcha). - README.md + docs/01,02 updated for the 4-user matrix. docs/03 detailed guide keeps the region-filter example but now has a preface explaining it's a variant of the default 4-user model. - docs/04: db_type='mysql_community' note added (RDS MySQL). E2E verified: PG=0/MY=17, PG=12/MY=0, PG=12/MY=17, PG=0/MY=0 plus all 5 bypass attempts blocked. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
2.5 KiB
SQL
84 lines
2.5 KiB
SQL
-- ============================================================
|
|
-- 12_tests_admin_audit.sql
|
|
-- Run as ADMIN to audit / verify policy attachment and the
|
|
-- 4-user access matrix.
|
|
-- ============================================================
|
|
SET FEEDBACK ON
|
|
SET LINESIZE 220
|
|
SET PAGESIZE 100
|
|
COL object_name FORMAT a20
|
|
COL policy FORMAT a25
|
|
COL pf_owner FORMAT a15
|
|
COL package FORMAT a15
|
|
COL function FORMAT a25
|
|
COL sel FORMAT a3
|
|
COL enable FORMAT a6
|
|
|
|
PROMPT
|
|
PROMPT === Attached VPD policies (expect rows for V_CUSTOMERS_PG and V_CUSTOMERS_MY) ===
|
|
SELECT object_name,
|
|
policy_name AS policy,
|
|
pf_owner,
|
|
package,
|
|
function,
|
|
sel,
|
|
enable
|
|
FROM dba_policies
|
|
WHERE object_owner = USER
|
|
AND object_name IN ('V_CUSTOMERS_PG','V_CUSTOMERS_MY')
|
|
ORDER BY object_name, policy_name;
|
|
|
|
PROMPT
|
|
PROMPT === Attached Data Redaction policies ===
|
|
COL object_name FORMAT a20
|
|
COL policy_name FORMAT a20
|
|
COL expression FORMAT a80 WORD_WRAPPED
|
|
SELECT object_name,
|
|
policy_name,
|
|
expression
|
|
FROM redaction_policies
|
|
WHERE object_owner = USER
|
|
ORDER BY object_name, policy_name;
|
|
|
|
PROMPT
|
|
PROMPT === Redacted columns ===
|
|
COL object_name FORMAT a20
|
|
COL column_name FORMAT a15
|
|
COL function_type FORMAT a15
|
|
COL regexp_pattern FORMAT a25
|
|
COL regexp_replace_string FORMAT a15
|
|
SELECT object_name,
|
|
column_name,
|
|
function_type,
|
|
regexp_pattern,
|
|
regexp_replace_string
|
|
FROM redaction_columns
|
|
WHERE object_owner = USER
|
|
ORDER BY object_name, column_name;
|
|
|
|
PROMPT
|
|
PROMPT === 4-user access matrix (from permission table) ===
|
|
PROMPT === Expected: ===
|
|
PROMPT === VPDUSER_MY -> V_CUSTOMERS_MY '*' ===
|
|
PROMPT === VPDUSER_PG -> V_CUSTOMERS_PG '*' ===
|
|
PROMPT === VPDUSER_BOTH -> V_CUSTOMERS_PG '*' + V_CUSTOMERS_MY '*' ===
|
|
PROMPT === VPDUSER_NONE -> (no rows — fail-closed by absence) ===
|
|
COL db_username FORMAT a14
|
|
COL group_name FORMAT a14
|
|
COL source_name FORMAT a14
|
|
COL object_name FORMAT a16
|
|
COL allowed_regions FORMAT a16
|
|
SELECT u.db_username,
|
|
g.group_name,
|
|
s.source_name,
|
|
p.object_name,
|
|
p.allowed_regions
|
|
FROM app_user u
|
|
LEFT JOIN user_group ug ON ug.user_id = u.user_id
|
|
LEFT JOIN app_group g ON g.group_id = ug.group_id
|
|
LEFT JOIN permission p ON p.group_id = g.group_id
|
|
LEFT JOIN db_source s ON s.source_id = p.source_id
|
|
ORDER BY u.db_username, p.object_name NULLS LAST;
|
|
|
|
EXIT;
|