Skip to content

P0.4: Access/PolicySurface grammar access-policy/1 (proposal for #17) - #19

Merged
sinkog merged 3 commits into
develfrom
feat/p0-4-access-grammar
Oct 18, 2026
Merged

sinkog merged 3 commits into
develfrom
feat/p0-4-access-grammar

Conversation

@sinkog

@sinkog sinkog commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Proposal for the normative closure of #17 (P0.4). Nothing here is an accepted rule until this PR is reviewed and merged. It does not close #17 by itself.

What it contains

  • proposals/atom-grammar/P0-4-ACCESS-GRAMMAR.md: versioned spec access-policy/1.
  • P0-4-MIGRATION.md: compatibility and migration rules, downstream consequences.
  • p0-4-contradiction-matrix.md: declared type, default, documented behavior, real corpus use, proposed rule, per element; findings F1-F4.
  • access_policy.py (reference model), access-vectors/ (187 positive and negative golden vectors), check_access_vectors.py (gate with 50 seeded faults), wired into make grammar.local.
  • schemas/atomic/access.yaml, schemas/aggregate/policy-surface.yaml: types and descriptions brought in line; instance-grammar.schema.yaml and check_grammar.py: typed node-level access and 4 self-test fixtures.
  • ai/DECISIONS.md D-018: amendment, D-010/D-011/D-012 text unchanged.

Design decisions made here (not proven by earlier text)

  • InheritanceMode = inherit | no-inherit | reset, spelled true | false | 0 in grammar 1 (existing documents, read as before) and by name in grammar 2. No mixing, no coercion, explicit lossless migration.
  • no-inherit stops the carrier field's rule but keeps the PolicySurface chain; reset cuts rule, chain and system default and denies without an explicit local base. Demonstrated on one parent/child pair (resolution.diff-field-*: deny / allow / deny) and enforced as a gate rule.
  • Resolution is a fixed priority list, explicit [] is terminal, open/owner are system-layer defaults that never shadow a declared ancestor rule, unknown context is an error, a missing or untrusted owner grants no write.
  • The corpus has no field-level inherit and no inherit_policy other than true, so the false/0 difference is a design checked by vectors, not a measurement.

Finding outside this repo

Nine current cic-schema-registry schemas (34 occurrences with versioned ones) write modify: [OU=adapters, O=cic]. YAML parses that as two OR patterns, so any O=cic certificate would match. The intended value is "OU=adapters,O=cic". Needs its own fix there.

Not changed

cic-primitive-forms and cic-primitive-engine code, the 6-key recognition rule, where conformance lives, runtime enforcement. Downstream adoption needs a new grammar pin, manifest, corpus and ADR compatibility check.

Evidence

make grammar.local: 187 vectors green, 50/50 seeded faults detected, grammar self-test 53/53; make validate.local and pytest tests (153) green. Model and vectors have one author; the independent check is a second implementation.

Gábor Z Sinkó added 3 commits October 18, 2026 22:34
---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEQCIDNL/nlzeksKYK5Z9AF4bhKSvNWgSDKfUYuPt+ND+5dzAiAIAquBVbfzmHeXl/hLVRsBr3rUV+gQL4/rP7x5mWtYYg==
hash-algorithm = sha256
digest = 1uUujdb5VuX1Q1uwjS/FudiEww57aI6MKzDCd0TrGZ8=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
…and gate (proposal, #17)

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEYCIQDyEjCSiuDrDqxbbJVjonms1ld4YSM+uw513VzkDm2hxAIhAPFQzRe3+b4lAU7xb1kQWYCJTbftv97AQOL+ibxXPwyf
hash-algorithm = sha256
digest = +p0ZQUs8noATyXa4eGue8YMiSZIERY1GCPB3CrlB2uQ=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
… grammar version binding, request-context authority (PR #19 review)

---
[signing-metadata]
key = cic-my-sign-key
signature = vault:v1:MEUCIQDnrEmN330Fb2g+qq2q0TfquOHak4P0eQvGz4lluo4YwgIgQnlQ3Mj5AW/a0vwhZn9p6oBsPiZwQSMJenjKdozqOqw=
hash-algorithm = sha256
digest = lS/+Mcsdo18KgcdwR+ntMBNxF74Zp6hZxP+ZORmgZt0=

[certificate]
-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIUSnRMR6RPnEbg296XWPOqq/u5PCwwCgYIKoZIzj0EAwIw
QzELMAkGA1UEBhMCSFUxGTAXBgNVBAoMEENlbnRyYWxJbmZyYUNvcmUxGTAXBgNV
BAMMEENJQyBEZXZlbG9wZXIgQ0EwHhcNMjYwMzIwMTMyMjU5WhcNMjYxMjMxMTMy
MjU5WjBFMQswCQYDVQQGEwJIVTEZMBcGA1UECgwQQ2VudHJhbEluZnJhQ29yZTEb
MBkGA1UEAwwSR2Fib3IgWm9sdGFuIFNpbmtvMFkwEwYHKoZIzj0CAQYIKoZIzj0D
AQcDQgAEIG2CVmTfmLB9pLLclj7YmP2eedAjklpy4LGrU2ijoiy6Xqpuybv7OgJe
i+ez31s65NEV8+X/ByeX1cstR988z6N8MHowCQYDVR0TBAIwADAdBgNVHQ4EFgQU
yZN6AIX/TNnIJ9GwAa/NRN3ujHAwHwYDVR0jBBgwFoAUXn6CHYzPUqU4JVP8g+OS
WeDYjhcwDgYDVR0PAQH/BAQDAgeAMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEF
BQcDBDAKBggqhkjOPQQDAgNIADBFAiEA+bFzXRoJ4PCQbhAAtpkcMjt0vNj5rEW0
lOMBGDNyaWkCIB1vmM7PcZzv/c9bIrxF5kqv6QXomouhByUfeNUTbpKW
-----END CERTIFICATE-----
@sinkog

sinkog commented Oct 18, 2026

Copy link
Copy Markdown
Member Author

Targeted fixes for the review (commit 8551622, gate green).

Counterexamples, old vs new result (both reproduced on 0b00bf3 first)

Case Old New
trusted owner without identity, requestor without identity, modify allow, layer system (None == None) deny, OWNER_IDENTITY_INVALID
child inherit_policy: 0 (grammar 1) / reset (grammar 2), no local rule, parent carrier access: [O=acme], matching requestor allow, layer field_inherited deny, RESET_NO_LOCAL_RULE

Fixes

  1. owner needs two valid identities (non-empty string, no surrounding whitespace) that are equal. Codes OWNER_IDENTITY_INVALID, REQUESTOR_IDENTITY_INVALID, OWNER_MISMATCH.
  2. An object-level reset is applied before any carrier rule. Local rules (layers 1-3) are never cut; the carrier rule on the reset object's own field still reaches its sub-object; an unknown policy on an object whose carrier rule would be read is an error.
  3. Grammar version: a property of the pinned schema (access.yaml, spec.access_grammar.version: 1) and of the processing context, never a document key, so no seventh key in the Access representation. They must agree; missing is GRAMMAR_VERSION_MISSING (no default), unknown is UNKNOWN_GRAMMAR_VERSION, difference is GRAMMAR_VERSION_CONFLICT. One context binds one version for the whole document (read_document). Changing the version is a new schema version and a new grammar identity downstream.
  4. Request context authority is now in the spec and enforced in shape by the resolver: authenticated is a boolean, an authenticated subject is a concrete DN without wildcards, owner.trust is trusted|untrusted, op is access|modify; otherwise outcome error, INVALID_REQUEST_CONTEXT. A document cannot supply these.
  5. The access.yaml example is now modify: ["OU=adapters,O=cic"], with a note on the unquoted form. The nine registry schemas need their own security PR. The D-011 history text carries the same hazard; left as history, noted in D-018.

New vectors (access-vectors/): resolution.owner-both-identities-missing, owner-identity-{null,empty,int,whitespace,list}, requestor-identity-{missing,null,empty,int}, owner-identity-same-int-not-an-identity, owner-explicit-symbol-no-identities, owner-identity-equal-valid, owner-identity-different-valid, request-* (8), object-reset-cuts-carrier-rule-g1/g2, object-reset-local-rule-wins-g1/g2, object-reset-own-field-rule-wins-g1/g2, object-reset-surface-rule-wins-g1/g2, object-reset-above-cuts-higher-carrier, object-reset-above-keeps-lower-carrier, object-no-inherit-keeps-carrier-rule, unknown-policy-above-carrier; migration.bind-* (9), migration.document-* (5).

New seeded faults (all detected, 50/50 total): owner-none-equals-none (restores the old behavior), owner-identity-unchecked, requestor-identity-unchecked, identity-allows-empty, request-context-unchecked, object-reset-after-carrier, unknown-above-carrier-ignored, grammar-binding-ignores-pin, grammar-binding-defaults-to-1, schema-grammar-version.

Results: make grammar.local 187 vectors, 50/50 faults, grammar self-test 53/53; make validate.local green; pytest tests 153 passed; GitHub gate success on 8551622. The earlier 139 vectors and decisions are unchanged; the 48 added vectors are all additions. Not merged, #17 stays open.

@sinkog
sinkog merged commit aa0f8c8 into devel Oct 18, 2026
1 check passed
sinkog added a commit that referenced this pull request Oct 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant