Skip to content

security: externalize policy bundle authority input - #21

Merged
stacknil merged 4 commits into
mainfrom
stacknil/external-policy-root-v1
Sep 16, 2026
Merged

stacknil merged 4 commits into
mainfrom
stacknil/external-policy-root-v1

Conversation

@stacknil

@stacknil stacknil commented Sep 16, 2026 •

Copy link
Copy Markdown
Owner

Problem The v1 controller compiled the expected policy-bundle digest into controller source. Protecting that controller in a v2 bundle would create a digest cycle: text controller bytes -> protected manifest -> bundle digest -> controller constant This PR introduces only the non-self-referential policy-input protocol and v2 compatibility plumbing. Production authority remains inactive. ## Invariant - The controller fixes selector v2, epoch repo-sentinel-authority-v2, and relative root policy/repo-sentinel-authority/v2. - The only externally supplied policy identity is an exact 64-character lowercase hexadecimal digest. - The same validated digest flows unchanged through worker construction, bundle verification, worker-result validation, and the controller envelope. - Callers cannot choose a policy path, schema, mirror root, mandatory-control set, scanner identity, or selector-to-epoch mapping. - AUTHORITY_RESULT is semantic evaluation evidence, not authenticated publication authorization. ## Design decision An immutable PolicyBundleContract registry defines exactly two supported contracts: historical v1 and candidate-compatible v2. The v2 contract keeps bundle schema 1, portable-v1, commit-authoritative-v1, and the pinned repo-sentinel-lite 0.8.1 artifact while changing only epoch, mirror root, mandatory controls, and controller protocol. The worker resolves a reviewed selector and derives mirror, protected-control, and coverage behavior from the verified contract. No final v2 bundle or digest is created here. ## Threat / failure model The implementation fails closed on malformed or unknown selectors, arbitrary selector/path composites, v1/v2 cross-wiring, wrong or modified bundle bytes, missing mandatory controls, unreviewed workflow/action members, wrong mirror roots, and worker result digest/epoch disagreement. The controller does not authenticate whether the supplied digest is authorized for production publication. A future dedicated signer must bind it through an immutable signer registry and server-side evaluation admission record before publishing a Commit Status. ## Rejected alternatives 1. Hardcode the v2 digest in controller source. Rejected because it recreates the protected-source self-reference cycle. 2. Accept arbitrary epoch/root pairs. Rejected because policy selection would become caller-controlled path selection. 3. Discover a latest policy directory. Rejected because filesystem ordering would become an authority decision. 4. Ignore all policy/** content. Rejected because it would hide historical or unexpected policy artifacts from coverage. 5. Put workflow, OIDC, ticket, or expiry fields in P_v(H). Rejected because those are operational authorization evidence, not commit-intrinsic policy. ## Compatibility - policy/repo-sentinel-authority/v1/** is byte-identical to trusted main. - The v1 bundle independently reproduces 6f25ebb773ce1453e8de623bca5aaecc936f1f188288f8df20aedeadb3bf4612. - The v1 CLI default and public compatibility aliases remain intact. - Acquisition, reader, materializer, scanner semantics, report schemas, workflows, bootstrap, and branch/rules configuration are unchanged. - No policy/repo-sentinel-authority/v2/** directory exists in this PR. ## Validation Focused suites under WSL CPython 3.12.3: text policy contracts: 7 passed controller: 21 passed worker + provenance: 42 passed acquisition: 13 passed reader + materializer: 39 passed full repository: 178 run, 3 skipped, 0 failed Additional validation: text Ruff check: passed Ruff format --check: passed pre-commit configured hooks: passed Markdown/frontmatter: 157 files passed taxonomy render: current README snapshot: current pattern library: 8 stable / 13 total passed synthetic scanner PASS: passed synthetic scanner FAIL: passed scanner redaction: passed scanner import isolation: passed git diff --check: passed required mutation campaign: 10 / 10 killed The existing changed-file Repo Sentinel gate reports 55 high-entropy findings in the seven changed files. Manual review classifies all 55 as false positives: policy paths, schema field names, deterministic test placeholders, and long test identifiers. No credential, token, key, or private identifier was found. The base baseline uses location-sensitive fingerprints, so line movement reopens these historical identifiers. This PR does not change .reposentinel.toml, the root baseline, or the protected v1 policy bundle merely to suppress that known gate limitation; independent Business B review remains required. The registry lifecycle review finding is closed by the normative design record. Future signer requirement: evaluations freeze the exact immutable registry revision at admission; later registry changes may reject but never reinterpret an issued evaluation. This PR does not implement or test that future signer service. ## Rollback Before authority activation, rollback is a normal revert of this PR. There is no signer, GitHub App, production workflow, status, branch-rule change, final v2 bundle, or production v2 digest to coordinate. After any future activation, rollback must be a new externally reviewed signer registry revision rather than silent fallback or directory discovery.

@stacknil
stacknil marked this pull request as ready for review September 16, 2026 10:38
@stacknil
stacknil merged commit 8e9e4c5 into main Sep 16, 2026
6 of 7 checks passed
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