|
| 1 | +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. |
| 2 | +// |
| 3 | +// ADR-0056 D10 — Authorization Conformance Matrix. |
| 4 | +// |
| 5 | +// The durable encoding of the ADR-0056 audit: one row per authorization |
| 6 | +// primitive, each in EXACTLY ONE honest state (enforced / experimental / |
| 7 | +// removed). `enforced` rows name their runtime enforcement site; high-risk |
| 8 | +// enforced rows additionally reference an end-to-end dogfood proof. The |
| 9 | +// companion test (`authz-conformance.test.ts`) asserts the matrix is complete |
| 10 | +// and that every referenced proof file exists — so "the permission model is |
| 11 | +// landed" is a CHECKED artifact, not a one-time scan. A new fail-open (a |
| 12 | +// declared-but-unenforced primitive) or a deleted proof breaks CI. |
| 13 | + |
| 14 | +export type AuthzState = 'enforced' | 'experimental' | 'removed'; |
| 15 | + |
| 16 | +export interface AuthzPrimitive { |
| 17 | + id: string; |
| 18 | + summary: string; |
| 19 | + state: AuthzState; |
| 20 | + /** Runtime enforcement site (required when state === 'enforced'). */ |
| 21 | + enforcement?: string; |
| 22 | + /** Dogfood proof filename in this directory (required for high-risk enforced). */ |
| 23 | + proof?: string; |
| 24 | + /** Why it is experimental/removed, or a roadmap pointer. */ |
| 25 | + note?: string; |
| 26 | +} |
| 27 | + |
| 28 | +export const AUTHZ_CONFORMANCE: AuthzPrimitive[] = [ |
| 29 | + // ── Enforced + end-to-end proven ─────────────────────────────────────── |
| 30 | + { id: 'rls-read', summary: 'RLS `using` read filter', state: 'enforced', |
| 31 | + enforcement: 'plugin-security/security-plugin.ts computeRlsFilter (AND-injected)', proof: 'rls-fixture.dogfood.test.ts' }, |
| 32 | + { id: 'rls-by-id-write', summary: 'by-id write enforcement (#1994)', state: 'enforced', |
| 33 | + enforcement: 'plugin-security/security-plugin.ts pre-image re-read', proof: 'rls-fixture.dogfood.test.ts' }, |
| 34 | + { id: 'owd-private', summary: 'OWD private (owner-only)', state: 'enforced', |
| 35 | + enforcement: 'plugin-sharing/sharing-service.ts effectiveSharingModel=private', proof: 'showcase-private-owd.dogfood.test.ts' }, |
| 36 | + { id: 'owd-public-read', summary: 'OWD public_read (everyone reads, owner writes)', state: 'enforced', |
| 37 | + enforcement: 'plugin-sharing/sharing-service.ts (read model + canEdit)', proof: 'showcase-public-read-owd.dogfood.test.ts' }, |
| 38 | + { id: 'controlled-by-parent', summary: 'master-detail controlled_by_parent', state: 'enforced', |
| 39 | + enforcement: 'plugin-security/security-plugin.ts computeControlledByParentFilter + assertControlledByParentWrite', proof: 'controlled-by-parent.dogfood.test.ts' }, |
| 40 | + { id: 'multi-tenant', summary: 'organization isolation', state: 'enforced', |
| 41 | + enforcement: 'plugin-org-scoping + wildcard tenant RLS', proof: 'rls-multitenant.dogfood.test.ts' }, |
| 42 | + { id: 'anonymous-deny', summary: 'secure-by-default anonymous posture (capability)', state: 'enforced', |
| 43 | + enforcement: 'rest/rest-server.ts enforceAuth (requireAuth)', proof: 'showcase-anonymous-deny.dogfood.test.ts' }, |
| 44 | + { id: 'default-profile', summary: 'app-declared default profile (isDefault)', state: 'enforced', |
| 45 | + enforcement: 'plugin-security/security-plugin.ts fallback resolution', proof: 'showcase-default-profile.dogfood.test.ts' }, |
| 46 | + |
| 47 | + // ── Enforced (unit-proven; e2e proof is a follow-on) ─────────────────── |
| 48 | + { id: 'object-crud', summary: 'object CRUD permissions', state: 'enforced', |
| 49 | + enforcement: 'plugin-security/security-plugin.ts checkObjectPermission (fail-closed 403)' }, |
| 50 | + { id: 'fls', summary: 'field-level security (read mask + write deny)', state: 'enforced', |
| 51 | + enforcement: 'plugin-security/field-masker.ts + detectForbiddenWrites' }, |
| 52 | + { id: 'ownership-stamp', summary: 'owner_id auto-stamp on insert', state: 'enforced', |
| 53 | + enforcement: 'plugin-security/security-plugin.ts (insert owner_id inject)' }, |
| 54 | + { id: 'record-share', summary: 'manual record shares (sys_record_share)', state: 'enforced', |
| 55 | + enforcement: 'plugin-sharing/sharing-service.ts buildReadFilter/canEdit' }, |
| 56 | + { id: 'sharing-rules', summary: 'criteria/owner sharing rules', state: 'enforced', |
| 57 | + enforcement: 'plugin-sharing/sharing-rule-service.ts (materialized into sys_record_share)' }, |
| 58 | + { id: 'role-hierarchy', summary: 'role-hierarchy widening (role_and_subordinates)', state: 'enforced', |
| 59 | + enforcement: 'plugin-sharing/role-graph.ts RoleGraphService (sys_role.parent)' }, |
| 60 | + { id: 'rls-compiler-fail-closed', summary: 'uncompilable RLS predicate is surfaced/denied, not dropped', state: 'enforced', |
| 61 | + enforcement: 'plugin-security/rls-compiler.ts isSupportedRlsExpression + warn' }, |
| 62 | + { id: 'system-permissions', summary: 'systemPermissions / tab-app gating', state: 'enforced', |
| 63 | + enforcement: 'rest/rest-server.ts filterAppForUser' }, |
| 64 | + |
| 65 | + // ── Experimental — declared, NOT enforced (ADR-0049/0056 D8) ─────────── |
| 66 | + { id: 'compliance-configs', summary: 'GDPR/HIPAA/PCI configs', state: 'experimental', note: 'no runtime consumer; marked [EXPERIMENTAL] (D8)' }, |
| 67 | + { id: 'field-encryption', summary: 'at-rest field encryption', state: 'experimental', note: 'no crypto provider reads the config; marked [EXPERIMENTAL] (D8)' }, |
| 68 | + { id: 'data-masking', summary: 'role-based data masking', state: 'experimental', note: 'FLS is the enforced field-visibility path; marked [EXPERIMENTAL] (D8)' }, |
| 69 | + { id: 'rls-config-global', summary: 'global RLSConfig / RLSAuditEvent', state: 'experimental', note: 'not read by the RLS path; marked [EXPERIMENTAL] (D8)' }, |
| 70 | + { id: 'requireAuth-default-flip', summary: 'flip the global requireAuth default to secure-by-default', state: 'experimental', |
| 71 | + note: 'D2 warn landed; the flip is release-gated. Pre-req: built-in guest_portal so public forms survive (share-links already read as SYSTEM after token validation, so they are safe).' }, |
| 72 | + |
| 73 | + // ── Removed — by ADR-0049 (roadmap M2) ───────────────────────────────── |
| 74 | + { id: 'allow-transfer-restore-purge', summary: 'transfer/restore/purge ops', state: 'removed', note: 'ADR-0049 → roadmap M2' }, |
| 75 | + { id: 'flow-run-as', summary: 'flow runAs', state: 'removed', note: 'ADR-0049 → roadmap M2' }, |
| 76 | +]; |
0 commit comments