Skip to content

Add production trust v2 contracts and offline authority - #16

Merged
abrichr merged 18 commits into
mainfrom
codex/public-trust-v2
Aug 28, 2026
Merged

Add production trust v2 contracts and offline authority#16
abrichr merged 18 commits into
mainfrom
codex/public-trust-v2

Conversation

@abrichr

@abrichr abrichr commented Aug 27, 2026

Copy link
Copy Markdown
Member

What this draft contains

This branch replaces URL-based trust decisions with content-addressed v2 references. A consumer verifies the repository and registry commit, raw object bytes, object size, semantic identity, adjacent signature bundle, signed issuer, active signer registry, authority state, revocation state, and validity window.

The branch also defines the seven Production release profiles and the separate Support release family. Support admissions cannot enter the seven-target Production projection. The registry contains 34 fixed regular and bundle kinds.

The new offline public-trust profile checks canonical object and bundle bytes, v2 references, current state identities, the selected registry key, the signed profile, and the signature. The policy marks this profile inactive until every consumer pins the exact verifier.

No workflow in this draft changes a live setting or publishes a release.

Checks

  • python -m pytest -q tests: 129 passed, with 177 schema subtests
  • actionlint .github/workflows/*.yml
  • Focused Ruff checks for all changed Python files
  • Python AST parse for all scripts and tests
  • git diff --check

Retained v1 files

This first draft keeps nine v1 files. The follow-up will delete them after Web, Evals, Ops, Internal, and each release caller passes against the same v2 head. Git history remains the recovery source.

Retained v1 file v2 replacement
production-lifecycle-admissions.json evidence-registry.json plus the signed lifecycle feed and checkpoint chain
scripts/validate_production_lifecycle.py scripts/production_trust.py and scripts/validate_production_lifecycle_ref.py
scripts/prepare_lifecycle_change.py the content-addressed registry and protected lifecycle-ref update path
tests/test_production_lifecycle.py tests/test_production_trust.py and the full-chain reference tests
tests/test_governance_workflows.py v2 workflow and registry contract tests
schemas/production-lifecycle-admissions.schema.json the v2 reference, release, admission, feed, and checkpoint schemas
.github/workflows/production-lifecycle-activation.yml .github/workflows/production-lifecycle-ref.yml
.github/workflows/qualification-authority-state.yml signed authority-state receipt references in the checkpoint chain
.github/workflows/qualification-revocation-state.yml signed revocation-state receipt references in the checkpoint chain

The retained v1 tests use a private test fixture for their own closed contract. The v2 runtime does not accept a v1 fallback.

Draft limits

The new trust profile stays inactive. Existing publication and lifecycle paths must fail closed until the required roots and pinned consumers exist.

@abrichr

abrichr commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

Triaged during the 2026-08-27 queue drain. This PR is parked with its cluster, not queue debt.

Two of its three checks pass. The failing one is a real defect, and it is now tracked separately as #17: scripts/validate_production_lifecycle.py still enforces the v1 policy key set (maximum_admission_days, summary_authority) after this branch migrated the policy JSON and its schema to v2. The data and the schema agree; the imperative validator is the straggler, and POLICY_SCHEMA at line 39 is still pinned to /v1.

It was deliberately not fixed here. summary_authority is absent from v2 rather than renamed, and its 12-key block is consumed again at lines 1536, 1548 and 1601 to drive the certificate identity check and the admission expiry window. Editing only the key set would yield a validator that passes and verifies nothing. The three questions that need the v2 author's intent are in the issue.

validate_production_lifecycle.py still enforced the v1 policy contract while
production-lifecycle-policy.json and its schema moved to v2, so check_profile.py
refused the repository. Two v1 anchors had to go together: the pinned
POLICY_SCHEMA, and a closed key set naming maximum_admission_days and
summary_authority. Neither key exists in v2.

summary_authority was not renamed. v2 moved the certificate identity that signs
Production evidence into production-evidence-policy.json, keyed by evidence
kind, for v2 objects. The ledger this module reads is the retained v1 ledger, so
its records stay verifiable only against the authority, target map, policy
revision and policy digest that issued them. Those move from policy data to
pinned module constants, and _validate_summary_authority keeps every check the
v1 policy path ran, now applied to the pinned trust root. Deleting the field
without that replacement would have left the validator reporting success while
nothing checked who signed the evidence.

maximum_admission_days split in two. production_trust.validate_release enforces
30 days on openadapt.qualification-release/v1 and
validate_qualification_admission enforces 7 days on
openadapt.qualification-admission/v3. The retained ledger holds release
admissions on the production channel, so maximum_release_admission_days governs
its expiry. Both maximums keep the 1-to-30 bound and must now equal the window
the trust core actually applies, so neither number can drift unnoticed.

The v2 target contract is cross-checked against production_trust.TARGET_CONTRACTS
for claim scope, source repository and repository id, and a target may not
require an artifact kind that contract does not define.

The tests now read the published policy instead of a fixture mirroring the
validator's own constants, which is why 135 tests passed while check_profile
failed. New tests cover the published document, both admission windows, and the
certificate-identity binding: a refactor that empties the authority or removes
the verification path fails rather than passing quietly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abrichr
abrichr marked this pull request as ready for review August 28, 2026 04:03
@abrichr
abrichr merged commit 345f3c7 into main Aug 28, 2026
3 checks passed
@abrichr
abrichr deleted the codex/public-trust-v2 branch August 28, 2026 04:03
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