diff --git a/.aiwg/AIWG.md b/.aiwg/AIWG.md index 39e1a80..5e37c22 100644 --- a/.aiwg/AIWG.md +++ b/.aiwg/AIWG.md @@ -28,7 +28,7 @@ When a user asks whether AIWG is active or engaged in this project, run or read ### Tracker Authority Protocol -- Source of truth: [.aiwg/aiwg.config](./.aiwg/aiwg.config) +- Source of truth: [.aiwg/aiwg.config](./aiwg.config) - Internal/canonical tracker: `origin` (github; https://github.com/elder-plinius/OBLITERATUS.git) - Customer issue tracker: not configured - Primary repo remote: `origin`; CI remote: `origin` diff --git a/.aiwg/aiwg.config b/.aiwg/aiwg.config index a138a11..74aa68c 100644 --- a/.aiwg/aiwg.config +++ b/.aiwg/aiwg.config @@ -49,16 +49,16 @@ "bt6-maintainer": { "version": "0.3.0", "source": "project-local", - "installedAt": "2026-08-21T22:00:58.629Z", + "installedAt": "2026-08-22T14:56:47.190Z", "deployedTo": { "codex": { "agents": 5, "commands": 0, - "skills": 6, + "skills": 7, "rules": 1 } }, - "manifestHash": "sha256:d14e8bdea0e1f845155d35a74251651ace95ee65a052eeb303e6a8148d8d9948", + "manifestHash": "sha256:870a24c7c362c7e71884381a4bc171deef54139ae50e9c76cac3aa967a9fc368", "localPath": ".aiwg/plugins/bt6-maintainer/", "localType": "plugin", "manifestVersion": "1", @@ -68,13 +68,14 @@ "agents/bt6-pr-auditor.md": "4d0b3f19e70a0406f0ace424f281a2444c98677d05fe7875ee0b389b75985e3e", "agents/bt6-provider-assessor.md": "39cc61c35cea9be9dd7f9330ec82d7cef99d9a1f8a384f9313e8df9aafc98b30", "agents/bt6-release-integrator.md": "e66bd1bf158d53265600c3a96240865dd716ff947a1be0a3a1bd384ca9a0bce7", - "rules/bt6-maintainer-guardrails.md": "68baf7dd88b856615377edbba51530c6d001421d4fc6fbcfbe3c8caf0d5c8014", + "rules/bt6-maintainer-guardrails.md": "081d398443b7f1c6e37e75b7bd0b9a68a24195eee7b96cc60d34d3febd62c694", "skills/bt6-issue-steward/SKILL.md": "187e6cb41e71cc3811dfcf3aa8dcb5e49429aaa5087dbb0c3fd8816751b4f02e", "skills/bt6-merge-train/SKILL.md": "87e2cfd9a84c6f2d1ddb3d054ff794d1afe242f67dd2803caaeea9e39a3242ba", "skills/bt6-pr-audit/SKILL.md": "38be15ba6c6c12f958c7ced0bf6152654dc6df53ddc17156fda84083ae990ea9", "skills/bt6-provider-review/SKILL.md": "a95ac6d2be20847626bb94e5038358148d4a19c25e00ade6049526f8a16d0c15", "skills/bt6-queue-audit/SKILL.md": "aaa77f2e14b46a2f8329025923ed54745152cea6896c947580f7a1babff81312", - "skills/bt6-release-validation/SKILL.md": "e38c817001aecf9e0ab695875a41ad1a7ef55f6ffd7641e2646a3189f202b964" + "skills/bt6-release-readiness/SKILL.md": "b51881662f27604c518c67e009187b3b0bad1d0755116efae1b0d1505dbb3dfe", + "skills/bt6-release-validation/SKILL.md": "3ecf342ad12cd1eed2f38ed8eb5b7fb4e396a4e25c79b54e5f649eef0c10c866" }, "deployedArtifactHashes": { "codex": { @@ -83,13 +84,14 @@ "agents/bt6-pr-auditor.md": "541754bb5acf433e4bd2b85a93cfbb40f3f28d3c84ed577f92242f9041b9252b", "agents/bt6-provider-assessor.md": "716c78830e8d5c987683b2ff240eb0f04eefddd628d763a3c5adaf371d2ec8dd", "agents/bt6-release-integrator.md": "5cadf095ef64c24dbcab36c991f7c9a26d793eddc20be28fe6b73435253d9df1", - "rules/bt6-maintainer-guardrails.md": "68baf7dd88b856615377edbba51530c6d001421d4fc6fbcfbe3c8caf0d5c8014", + "rules/bt6-maintainer-guardrails.md": "081d398443b7f1c6e37e75b7bd0b9a68a24195eee7b96cc60d34d3febd62c694", "skills/bt6-issue-steward/SKILL.md": "1889afb3c068765806d895949d38f1b0888f72e59a5dedee1bc9b728910561f2", "skills/bt6-merge-train/SKILL.md": "2e01a84f578b53d4cc1c7dbf0ae2395004fab45b8175b104ccc31d74f3d9aa3b", "skills/bt6-pr-audit/SKILL.md": "9a1e55bfd6972f3168f884d54cd6ede3673b541940b54352120ed4c0a4c49f2c", "skills/bt6-provider-review/SKILL.md": "2de8b37f546dda852bee88d023caf82877baab988aebc219fd83a784c2bf58a3", "skills/bt6-queue-audit/SKILL.md": "e0bdb36c8f8f85a2e9dff0180de2f502972bb8af9b7b13c4661be065354ef893", - "skills/bt6-release-validation/SKILL.md": "c25e1600aea5102374616f89efb7f28b0cefd0d52f346414012560776cbb5407" + "skills/bt6-release-readiness/SKILL.md": "e609a2f2197fd8c65239f563a0f8cc594ad0d420e4d18da5ba8362f26574ff52", + "skills/bt6-release-validation/SKILL.md": "942cd70729c5c13c384532214ebfff1763fd9374a85abda18925932b6dc79167" } } } diff --git a/.aiwg/bt6-maintainer.yaml b/.aiwg/bt6-maintainer.yaml index 5105c19..8e4b8a6 100644 --- a/.aiwg/bt6-maintainer.yaml +++ b/.aiwg/bt6-maintainer.yaml @@ -25,18 +25,28 @@ validation: - "python scripts/check_coverage_thresholds.py test-results/coverage-pr-core.json --min-line 0 --min-branch 0 --min-changed 50 --base-ref origin/main" - "python scripts/check_conditional_policy.py && python scripts/check_test_risk_map.py" full: - - "python -m pytest" + - "mkdir -p test-results && python -m pytest -m 'not slow and not gpu and not mps and not mlx and not network and not download and not remote and not operator_ui' --cov-branch --cov-fail-under=0 --cov-report=json:test-results/coverage-release.json" + - "python scripts/check_coverage_thresholds.py test-results/coverage-release.json --min-line 75 --min-branch 60 --min-file obliteratus/device.py=70 --min-file obliteratus/models/loader.py=70 --min-file obliteratus/architecture_profiles.py=70 --min-file obliteratus/cli.py=70 --min-file obliteratus/mlx_backend.py=70 --min-file obliteratus/evaluation/metrics.py=70 --min-file obliteratus/evaluation/advanced_metrics.py=70 --min-file obliteratus/reporting/report.py=70 --min-file obliteratus/community.py=70 --min-file obliteratus/telemetry.py=70" + - "python scripts/check_quality_policy.py --policy ci/test-quality-policy.json --coverage test-results/coverage-release.json && python scripts/check_conditional_policy.py && python scripts/check_test_risk_map.py" - "python -m build --sdist --wheel" - "python -c 'import obliteratus; print(obliteratus.__version__)'" - "python -m obliteratus --help" qualityPolicy: pullRequestChangedLineCoverageFloor: 50 requireBehaviorTests: true - fullSuiteTrigger: "tagged-release" + fullSuiteTrigger: "release-readiness-and-tagged-validation" documentation: - "python -m ruff check --select F app.py obliteratus tests scripts/check_coverage_thresholds.py scripts/check_supply_chain_policy.py scripts/gemma4_12b_recursive_loop.py" researchIntegrity: - "python -m pytest tests/test_advanced_metrics.py tests/test_breakthrough_modules.py tests/test_community.py" +releaseEvidence: + hashAlgorithm: "sha256" + provenanceFormat: "slsa-v1" + attestationFormat: "in-toto" + signingMode: "sigstore-keyless" + sbomFormat: "cyclonedx" + buildOnce: true + verifyBeforePromotion: true riskSurfaces: - id: "model-loading" paths: ["obliteratus/models/**", "obliteratus/device.py", "scripts/**"] diff --git a/.aiwg/generated/project-quickref/aiwg-project-obliteratus-quickref/SKILL.md b/.aiwg/generated/project-quickref/aiwg-project-obliteratus-quickref/SKILL.md index f735e9a..5fc8858 100644 --- a/.aiwg/generated/project-quickref/aiwg-project-obliteratus-quickref/SKILL.md +++ b/.aiwg/generated/project-quickref/aiwg-project-obliteratus-quickref/SKILL.md @@ -15,7 +15,7 @@ Use project-local capabilities before generic AIWG workflows when they apply. ## bt6-maintainer -Cross-repository maintenance, external-provider review, and tagged-release validation for BT6 research and support tooling. +Cross-repository maintenance, release readiness, and exact-tag validation for BT6 research and support tooling. - Discover: `aiwg discover "bt6-maintainer"` - Discover: `aiwg discover "bt6"` diff --git a/.aiwg/generated/project-quickref/definition.json b/.aiwg/generated/project-quickref/definition.json index 5039c7e..30d817a 100644 --- a/.aiwg/generated/project-quickref/definition.json +++ b/.aiwg/generated/project-quickref/definition.json @@ -9,7 +9,7 @@ "entries": [ { "title": "bt6-maintainer", - "summary": "Cross-repository maintenance, external-provider review, and tagged-release validation for BT6 research and support tooling.", + "summary": "Cross-repository maintenance, release readiness, and exact-tag validation for BT6 research and support tooling.", "discover": [ "bt6-maintainer", "bt6", diff --git a/.aiwg/plugins/bt6-maintainer/README.md b/.aiwg/plugins/bt6-maintainer/README.md index bf8a1fa..975f5d8 100644 --- a/.aiwg/plugins/bt6-maintainer/README.md +++ b/.aiwg/plugins/bt6-maintainer/README.md @@ -2,8 +2,8 @@ Cross-repository maintenance for BT6 research and support tooling. The plugin provides queue audit, pull-request audit, external-provider assessment, issue -stewardship, conservative merge-train workflows, and exact-tag release -validation that adapt to each repository's configured tracker, delivery policy, +stewardship, conservative merge-train workflows, pre-tag release hardening, and +exact-tag release validation that adapt to each repository's configured tracker, delivery policy, validation commands, and research/data risk surfaces. ## What this is @@ -70,9 +70,11 @@ the profile's `validation.quick` core suite, require relevant tests for behavior changes, and enforce a 50% changed-line coverage floor where coverage is measurable. Genuine but incomplete tests may be completed through `maintainer-assist`; behavior changes with zero relevant tests remain blocked. -The exhaustive `validation.full` suite runs through `bt6-release-validation` -against an exact tag and blocks artifact promotion until the release gate is -green. +Before tagging, `bt6-release-readiness` inventories merged risk, runs the +exhaustive locally applicable gates, and repairs test, coverage, correctness, +documentation, and policy gaps. After tagging, `bt6-release-validation` binds +the same higher bar plus hosted and platform evidence to the exact immutable +tag. Readiness never substitutes for tagged certification. Inspect health: ```bash diff --git a/.aiwg/plugins/bt6-maintainer/manifest.json b/.aiwg/plugins/bt6-maintainer/manifest.json index b49b8bd..4fa65a9 100644 --- a/.aiwg/plugins/bt6-maintainer/manifest.json +++ b/.aiwg/plugins/bt6-maintainer/manifest.json @@ -3,7 +3,7 @@ "type": "plugin", "name": "bt6-maintainer", "version": "0.3.0", - "description": "Cross-repository maintenance, external-provider review, and tagged-release validation for BT6 research and support tooling.", + "description": "Cross-repository maintenance, release readiness, and exact-tag validation for BT6 research and support tooling.", "manifestVersion": "1", "platforms": { "claude": "full", @@ -19,6 +19,8 @@ "external-providers", "trust-boundaries", "merge-train", + "release-readiness", + "release-validation", "plugin", "repository-operations" ], diff --git a/.aiwg/plugins/bt6-maintainer/payload/README.md b/.aiwg/plugins/bt6-maintainer/payload/README.md index 5148bf6..463548c 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/README.md +++ b/.aiwg/plugins/bt6-maintainer/payload/README.md @@ -13,10 +13,12 @@ support codebases with consistent evidence and safety gates. triage. - `bt6-merge-train` — explicitly authorized, one-at-a-time merges with queue refresh and linked-issue reconciliation. +- `bt6-release-readiness` — pre-tag audit and repair from the bounded PR bar to + the exhaustive release bar. +- `bt6-release-validation` — exact-tag certification before artifact promotion. -Five matching agents orchestrate those skills. Five declarative capability -flows describe queue audit, PR audit, provider review, issue stewardship, and -merge train contracts. +The release integrator orchestrates both release workflows. Declarative +capability flows describe every workflow contract. ## Repository profile diff --git a/.aiwg/plugins/bt6-maintainer/payload/capabilities/bt6-release-readiness-flow.yaml b/.aiwg/plugins/bt6-maintainer/payload/capabilities/bt6-release-readiness-flow.yaml new file mode 100644 index 0000000..257916e --- /dev/null +++ b/.aiwg/plugins/bt6-maintainer/payload/capabilities/bt6-release-readiness-flow.yaml @@ -0,0 +1,52 @@ +apiVersion: ops.aiwg.io/v1 +kind: OpsCapability +metadata: + name: bt6-release-readiness-flow + labels: + category: release-management + scope: cross-repository + annotations: + blast-radius: "repository-local repairs only; tagging and publication are out of scope" +spec: + description: Audit and harden an untagged candidate from the bounded PR bar to the exhaustive BT6 release bar. + version: "0.3.0" + inputs: + - name: candidate + type: string + required: true + description: Exact candidate commit to harden. + - name: comparison_base + type: string + required: true + description: Previous release or configured exact base used to inventory merged change. + outputs: + - name: gap_inventory + type: list + description: Failed gates, coverage regressions, untested behavior, and unavailable evidence. + - name: repairs + type: list + description: Authorized code, test, documentation, and policy corrections with verification. + - name: decision + type: string + description: ready-to-tag, not-ready, or hold. + target_requirements: + os: [linux, macos] + capabilities: [git] + agent: bt6-release-integrator + idempotent: true + steps: + - name: resolve-candidate + description: Bind repository authority, candidate, comparison base, profile, and authorization. + - name: inventory-merged-risk + description: Map merged production changes to relevant tests, owners, public contracts, and risk surfaces. + - name: run-pre-tag-gates + description: Run the full locally applicable release suite, coverage, quality-depth, packaging, and integrity checks. + - name: repair-gaps + description: Add outcome-oriented tests and correct underlying implementation or policy defects without weakening thresholds. + - name: rerun-complete-gate + description: Re-run focused checks and then the complete applicable pre-tag suite. + - name: decide + description: Declare ready-to-tag only with green pre-tag evidence; exact-tag validation remains mandatory. + verification: + command: "git rev-parse --verify ^{commit} >/dev/null" + expect: "report binds the gap inventory, repairs, and final evidence to the exact candidate and comparison base" diff --git a/.aiwg/plugins/bt6-maintainer/payload/config/repository-profile.schema.json b/.aiwg/plugins/bt6-maintainer/payload/config/repository-profile.schema.json index 2c7d362..6bcad15 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/config/repository-profile.schema.json +++ b/.aiwg/plugins/bt6-maintainer/payload/config/repository-profile.schema.json @@ -91,13 +91,35 @@ "properties": { "pullRequestChangedLineCoverageFloor": { "const": 50 }, "requireBehaviorTests": { "const": true }, - "fullSuiteTrigger": { "const": "tagged-release" } + "fullSuiteTrigger": { "const": "release-readiness-and-tagged-validation" } } }, "documentation": { "$ref": "#/$defs/commands" }, "researchIntegrity": { "$ref": "#/$defs/commands" } } }, + "releaseEvidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "hashAlgorithm", + "provenanceFormat", + "attestationFormat", + "signingMode", + "sbomFormat", + "buildOnce", + "verifyBeforePromotion" + ], + "properties": { + "hashAlgorithm": { "const": "sha256" }, + "provenanceFormat": { "const": "slsa-v1" }, + "attestationFormat": { "const": "in-toto" }, + "signingMode": { "enum": ["sigstore-keyless", "project-defined"] }, + "sbomFormat": { "enum": ["cyclonedx", "spdx"] }, + "buildOnce": { "const": true }, + "verifyBeforePromotion": { "const": true } + } + }, "riskSurfaces": { "type": "array", "items": { diff --git a/.aiwg/plugins/bt6-maintainer/payload/manifest.json b/.aiwg/plugins/bt6-maintainer/payload/manifest.json index 9abb86e..e6bcd44 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/manifest.json +++ b/.aiwg/plugins/bt6-maintainer/payload/manifest.json @@ -3,7 +3,7 @@ "type": "addon", "name": "bt6-maintainer", "version": "0.3.0", - "description": "Cross-repository queue, review, issue, provider-trust, merge, and tagged-release validation for BT6 research and support tooling.", + "description": "Cross-repository queue, review, issue, provider-trust, merge, release-readiness, and exact-tag validation for BT6 research and support tooling.", "manifestVersion": "1", "platforms": { "claude": "full", @@ -20,6 +20,8 @@ "external-providers", "trust-boundaries", "merge-train", + "release-readiness", + "release-validation", "provenance" ], "deployment": { diff --git a/.aiwg/plugins/bt6-maintainer/payload/rules/bt6-maintainer-guardrails.md b/.aiwg/plugins/bt6-maintainer/payload/rules/bt6-maintainer-guardrails.md index e75b02d..67f72b0 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/rules/bt6-maintainer-guardrails.md +++ b/.aiwg/plugins/bt6-maintainer/payload/rules/bt6-maintainer-guardrails.md @@ -35,8 +35,8 @@ report. 11. Apply the shared two-tier quality model consistently. Pull requests run the profile's fast `validation.quick` core-system commands and must reach at least 50% changed-line coverage for measurable production-code changes. - Tagged-release validation runs `validation.full`; do not make that - exhaustive suite an ordinary contributor PR requirement. + Pre-tag readiness and tagged-release validation run `validation.full`; do + not make that exhaustive suite an ordinary contributor PR requirement. 12. Every behavior change needs a relevant outcome-oriented test. A material behavior change with zero relevant tests is never merge-ready, regardless of aggregate coverage. Documentation-only, metadata-only, and other @@ -51,3 +51,7 @@ report. profile's `validation.full` commands and applicable documentation, research-integrity, risk-surface, packaging, and platform checks pass for that exact tagged commit. +15. After merges and before tagging, run `bt6-release-readiness` from the + previous release or configured comparison base. Audit merged behavior, + repair release-depth gaps without weakening thresholds, and then run + `bt6-release-validation` after the immutable tag is created. diff --git a/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-readiness/SKILL.md b/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-readiness/SKILL.md new file mode 100644 index 0000000..838218b --- /dev/null +++ b/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-readiness/SKILL.md @@ -0,0 +1,72 @@ +--- +namespace: bt6-maintainer +name: bt6-release-readiness +platforms: [all] +description: Harden an untagged BT6 release candidate to the exhaustive release bar after pull requests were accepted through the bounded contributor gate. +triggers: + - prepare a BT6 release + - harden a BT6 release candidate + - audit merged PRs for release + - improve coverage before release +requires: + - candidate-reference: an exact candidate commit and comparison base + - repository-context: canonical repository, CI remote, and validation profile resolvable from project state +ensures: + - release-gaps-audited: merged behavior and risk surfaces are checked against the full release policy + - maintainer-gaps-repaired: authorized test and correctness gaps are fixed before tagging + - candidate-not-certified: readiness evidence never substitutes for exact-tag validation +--- + +# BT6 Release Readiness + +Prepare a release candidate after normal pull requests have passed the bounded +`validation.quick` contributor gate. Apply `bt6-maintainer-guardrails`. This +workflow may improve code, tests, documentation, and repository-owned release +policy when the operator authorizes implementation. It does not create or +promote a tag. + +## Required context + +1. Resolve the canonical repository, base branch, CI remote, profile, candidate + commit, comparison base, and current authorization. +2. Require a clean or explicitly understood working tree. Preserve unrelated + work and use an isolated checkout when validation could overwrite it. +3. Inventory merged changes since the previous release or configured comparison + base. Map production changes to behavior tests, ownership, and risk surfaces. +4. Treat PR acceptance as evidence of reviewability only. Do not infer release + readiness from quick checks, aggregate coverage, or merge status. + +## Hardening loop + +1. Run `validation.full` plus applicable documentation, research-integrity, + risk-surface, packaging, compatibility, supply-chain, repeat, mutation, and + conditional-platform checks that can run before tagging. +2. Measure repository line and branch coverage, configured mature/critical + scope, changed or touched-module regression, and new-module floors. Record + skipped, unavailable, or stale evidence explicitly. +3. Prioritize failures and coverage gaps by release risk, recent change, public + contract, trust boundary, and defect history—not by raw uncovered-line count. +4. For each blocking gap, add outcome-oriented tests and correct the underlying + implementation or policy defect. Never weaken a release threshold to make a + candidate pass. +5. Re-run focused checks after each repair, then re-run the complete applicable + pre-tag gate. Stop when all locally executable hard gates pass or a required + external/platform gate remains unresolved. +6. When `releaseEvidence` is configured, require one canonical SHA-256 manifest + for the build-once release set, a bound SBOM, SLSA/in-toto provenance, and + the configured signature mechanism. Downstream gates must consume the same + artifact bytes rather than rebuilding them. + +## Decision + +- `ready-to-tag` only when every applicable pre-tag hard gate passes and all + unavailable evidence is intentionally deferred to an exact-tag hosted gate. +- `not-ready` when any required check fails or a correctness, security, + integrity, compatibility, or coverage gap remains. +- `hold` when the candidate, comparison base, authority, profile, or required + environment cannot be resolved safely. + +Use `templates/bt6-release-readiness-report.md`. A `ready-to-tag` result becomes +stale on any candidate commit, dependency lock, policy, test, platform, or +release-configuration change. After tagging, always run `bt6-release-validation` +against the exact immutable tag; readiness is never release certification. diff --git a/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-validation/SKILL.md b/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-validation/SKILL.md index 1a20fd5..fefebff 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-validation/SKILL.md +++ b/.aiwg/plugins/bt6-maintainer/payload/skills/bt6-release-validation/SKILL.md @@ -53,6 +53,10 @@ and does not publish a release without separate explicit authorization. 5. Treat warnings, flakes, skips, coverage changes, and conditional-gate gaps according to repository release policy; do not inherit the relaxed PR turnaround budget as a release exemption. +6. When `releaseEvidence` is configured, verify every artifact against the + canonical checksum manifest, authenticate its SLSA/in-toto attestation, + validate the SBOM binding, and prove promotion uses the tested build-once + bytes. A checksum without authenticated provenance is incomplete evidence. ## Decision diff --git a/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-release-readiness-report.md b/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-release-readiness-report.md new file mode 100644 index 0000000..cc3b56c --- /dev/null +++ b/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-release-readiness-report.md @@ -0,0 +1,44 @@ +--- +title: BT6 Release Readiness Report +description: Pre-tag audit and hardening report for moving a candidate from the bounded PR bar to the exhaustive release bar. +--- + +# BT6 release readiness: `` + +## Context + +- Repository: `` +- Candidate commit: `` +- Comparison base: `` +- Profile: `` +- Authorization: `` + +## Merged-risk inventory + +| Surface | Changed behavior | Relevant tests/evidence | Risk | Status | +| --- | --- | --- | --- | --- | +| `` | `` | `` | `` | `` | + +## Release-depth gates + +| Gate | Threshold or expectation | Result | Evidence | +| --- | --- | --- | --- | +| Full validation | `` | `` | `` | +| Coverage and regression | `` | `` | `` | +| Quality depth | `` | `` | `` | +| Packaging and supply chain | `` | `` | `` | +| Conditional/platform checks | `` | `` | `` | + +## Repairs + +| Finding | Correction | Verification | Residual risk | +| --- | --- | --- | --- | +| `` | `` | `` | `` | + +## Decision + +`` + +This report is pre-tag evidence only. Any candidate, dependency, test, policy, +platform, or release-configuration change invalidates it. Exact-tag +`bt6-release-validation` remains required before artifact promotion. diff --git a/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-repository-profile.yaml b/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-repository-profile.yaml index c350abf..2f309c5 100644 --- a/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-repository-profile.yaml +++ b/.aiwg/plugins/bt6-maintainer/payload/templates/bt6-repository-profile.yaml @@ -29,11 +29,19 @@ validation: qualityPolicy: pullRequestChangedLineCoverageFloor: 50 requireBehaviorTests: true - fullSuiteTrigger: "tagged-release" + fullSuiteTrigger: "release-readiness-and-tagged-validation" documentation: - "" researchIntegrity: - "" +releaseEvidence: + hashAlgorithm: "sha256" + provenanceFormat: "slsa-v1" + attestationFormat: "in-toto" + signingMode: "sigstore-keyless" + sbomFormat: "cyclonedx" + buildOnce: true + verifyBeforePromotion: true riskSurfaces: - id: "ingestion" paths: [""] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3354cbd..ec1ebc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,6 +28,11 @@ jobs: if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest timeout-minutes: 15 + permissions: + artifact-metadata: write + attestations: write + contents: read + id-token: write env: BUILD_TOOLS: /tmp/obliteratus-ci-tools @@ -90,7 +95,31 @@ jobs: run: | mkdir -p package-evidence "$BUILD_TOOLS/bin/python" -m twine check dist/* | tee package-evidence/twine-check.txt - sha256sum dist/* | tee package-evidence/SHA256SUMS + + - name: Generate and bind CycloneDX SBOM + run: | + uv --preview-features sbom-export export \ + --locked \ + --format cyclonedx1.5 \ + --all-extras \ + --no-dev \ + --no-editable \ + --output-file package-evidence/obliteratus.cdx.unbound.json + mapfile -t wheels < <(find dist -maxdepth 1 -type f -name '*.whl' -print) + if [ "${#wheels[@]}" -ne 1 ]; then + echo "expected exactly one wheel, found ${#wheels[@]}" + exit 1 + fi + python scripts/check_supply_chain_policy.py sbom \ + --input package-evidence/obliteratus.cdx.unbound.json \ + --wheel "${wheels[0]}" \ + --output package-evidence/obliteratus.cdx.json + rm package-evidence/obliteratus.cdx.unbound.json + + - name: Generate canonical release checksums + run: >- + sha256sum dist/* package-evidence/obliteratus.cdx.json | + tee package-evidence/SHA256SUMS - name: Verify installed wheel contract run: | @@ -154,6 +183,27 @@ jobs: "$sdist_env/bin/python" -I -m obliteratus --help > "$GITHUB_WORKSPACE/package-evidence/sdist-module-help.txt" "$sdist_env/bin/obliteratus" --help > "$GITHUB_WORKSPACE/package-evidence/sdist-console-help.txt" + - name: Attest release-set SLSA provenance + id: provenance + uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + with: + subject-checksums: package-evidence/SHA256SUMS + + - name: Attest wheel SBOM + id: sbom-attestation + uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + with: + subject-path: dist/*.whl + sbom-path: package-evidence/obliteratus.cdx.json + + - name: Retain Sigstore attestation bundles + run: | + cp "${{ steps.provenance.outputs.bundle-path }}" \ + package-evidence/slsa-provenance.sigstore.json + cp "${{ steps.sbom-attestation.outputs.bundle-path }}" \ + package-evidence/sbom-attestation.sigstore.json + sha256sum -c package-evidence/SHA256SUMS + - name: Upload distributions and package evidence if: always() uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -706,6 +756,7 @@ jobs: supply-chain: name: Supply chain if: github.event_name == 'workflow_dispatch' || startsWith(github.ref, 'refs/tags/v') + needs: package runs-on: ubuntu-latest timeout-minutes: 30 env: @@ -719,6 +770,12 @@ jobs: - name: Check out repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Download attested release set + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: distributions-py3.12 + path: /tmp/supply-chain-evidence/release + - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -784,27 +841,19 @@ jobs: echo "$status" > "$EVIDENCE/uv-audit-py${version}.status" done - - name: Build wheel and bind CycloneDX SBOM + - name: Verify attested release set and bound CycloneDX SBOM run: | - mkdir -p "$EVIDENCE/dist" - "$SUPPLY_TOOLS/bin/python" -m build --wheel --outdir "$EVIDENCE/dist" - uv --preview-features sbom-export export \ - --locked \ - --format cyclonedx1.5 \ - --all-extras \ - --no-dev \ - --no-editable \ - --output-file "$EVIDENCE/obliteratus.cdx.unbound.json" - mapfile -t wheels < <(find "$EVIDENCE/dist" -maxdepth 1 -type f -name '*.whl' -print) + cd "$EVIDENCE/release" + sha256sum -c package-evidence/SHA256SUMS + mapfile -t wheels < <(find dist -maxdepth 1 -type f -name '*.whl' -print) if [ "${#wheels[@]}" -ne 1 ]; then echo "expected exactly one wheel, found ${#wheels[@]}" exit 1 fi - python scripts/check_supply_chain_policy.py sbom \ - --input "$EVIDENCE/obliteratus.cdx.unbound.json" \ + python "$GITHUB_WORKSPACE/scripts/check_supply_chain_policy.py" sbom \ + --input package-evidence/obliteratus.cdx.json \ --wheel "${wheels[0]}" \ - --output "$EVIDENCE/obliteratus.cdx.json" - sha256sum "${wheels[0]}" > "$EVIDENCE/distribution.SHA256SUM" + --output "$EVIDENCE/verified-obliteratus.cdx.json" - name: Collect packaged-dependency license inventory run: >- diff --git a/WORKSPACE.md b/WORKSPACE.md index dc5271d..845e5e3 100644 --- a/WORKSPACE.md +++ b/WORKSPACE.md @@ -59,6 +59,12 @@ regression and 80%/75% new-module floors; 94%/84% mature CPU-scope coverage; selective mutation at 85%; repeat and duration budgets; Windows checkpoint contracts; packaging; and supply-chain certification. +Before a tag is created, run the BT6 release-readiness workflow against the +previous release or configured comparison base. It inventories merged behavior, +runs all locally applicable release-depth gates, and repairs coverage, +correctness, documentation, packaging, and policy gaps. After tagging, run +exact-tag release validation; pre-tag readiness is never promotion evidence. + Canonical integrations must retain a verifiable commit signature. The repository profile permits merge integration, not GitHub rebase integration, because rebase can recreate an audited signed head as an unsigned canonical commit. Verify the @@ -69,6 +75,12 @@ in an independent environment outside the checkout, exercises both CLI entry paths, and retains the distributions plus evidence. Immutable CI action/tool pins are recorded in [ci/digests.txt](ci/digests.txt). +The package job is the sole release-artifact producer. It binds wheel, sdist, +and CycloneDX SBOM digests into `SHA256SUMS`, creates keyless Sigstore-backed +SLSA and SBOM attestations, and retains their bundles. Downstream supply-chain +and publication jobs must verify and reuse those exact bytes rather than +rebuilding equivalent-looking artifacts. + The source-to-test ownership graph is versioned in [ci/test-risk-map.json](ci/test-risk-map.json). Coverage, JUnit, repeat, and mutation trends are normalized into project-owned JSON and retained for 90 diff --git a/ci/digests.txt b/ci/digests.txt index 1d34d26..c093c40 100644 --- a/ci/digests.txt +++ b/ci/digests.txt @@ -2,6 +2,8 @@ action actions/checkout 3d3c42e5aac5ba805825da76410c181273ba90b1 v7.0.1 2026-08-14 baseline pin (#59) action actions/setup-python 5fda3b95a4ea91299a34e894583c3862153e4b97 v7.0.0 2026-08-14 baseline pin (#59) action actions/upload-artifact 043fb46d1a93c77aae656e7c1c64a875d1fc6a0a v7.0.1 2026-08-14 test/package evidence (#64, #65) +action actions/download-artifact 3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c v8.0.1 2026-03-11 immutable release-set reuse (#142) +action actions/attest 1e69f48acb82d1966a394da916b4c1698aa569d6 v4.2.2 2026-08-04 SLSA provenance and SBOM attestations (#142) tool rhysd/actionlint sha256:8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8 v1.7.12 2026-08-14 workflow syntax/policy gate (#65) tool astral-sh/uv pypi:0.12.4 v0.12.4 2026-08-14 locked dependency and SBOM engine (#66) tool gitleaks/gitleaks sha256:551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb v8.30.1 2026-08-14 redacted checkout secret scan (#66) diff --git a/docs/SUPPLY_CHAIN_POLICY.md b/docs/SUPPLY_CHAIN_POLICY.md index 932c030..b1229b0 100644 --- a/docs/SUPPLY_CHAIN_POLICY.md +++ b/docs/SUPPLY_CHAIN_POLICY.md @@ -9,6 +9,36 @@ CI uses exact Python tool versions and checksum-pinned standalone binaries. `ci/digests.txt` records executable and GitHub Action pins; build, test, and license-tool transitive dependencies are covered by `uv.lock`. +## Digest-bound release evidence + +Release artifacts use a build-once evidence chain. The release package job is +the sole producer of the wheel and source distribution. It also emits a bound +CycloneDX SBOM and a canonical `SHA256SUMS` manifest covering both distributions +and the SBOM. + +GitHub's keyless Sigstore-backed attestation service signs two in-toto +statements for that release set: + +- SLSA build provenance for every subject named by `SHA256SUMS`; +- an SBOM attestation binding the CycloneDX document to the wheel digest. + +The supply-chain job downloads the package job's retained artifact, verifies +`SHA256SUMS`, and revalidates the SBOM binding. It must not rebuild a substitute +wheel. Publication must use these same tested and attested bytes. A commit, +dependency lock, build instruction, artifact, checksum manifest, SBOM, or +release-policy change invalidates the evidence. + +Consumers can perform the portable integrity check with: + +```bash +sha256sum --check SHA256SUMS +``` + +For authenticity and provenance, verify each distribution against the canonical +repository with GitHub's attestation verifier. A checksum without its signed +provenance proves byte integrity only; it does not prove who built the artifact +or which source and build instructions produced it. + ## Required evidence The Supply chain job retains these artifacts for 14 days: diff --git a/tests/test_aiwg_workspace_contracts.py b/tests/test_aiwg_workspace_contracts.py index 1f44fc3..efa7fdc 100644 --- a/tests/test_aiwg_workspace_contracts.py +++ b/tests/test_aiwg_workspace_contracts.py @@ -56,7 +56,7 @@ def test_bt6_maintainer_installation_matches_project_plugin(): assert installation["deployedTo"]["codex"] == { "agents": 5, "commands": 0, - "skills": 6, + "skills": 7, "rules": 1, } assert "skills/bt6-release-validation/SKILL.md" in installation["artifactHashes"] @@ -113,3 +113,32 @@ def test_delivery_profile_preserves_signed_canonical_history(): assert profile["delivery"]["defaultMergeMethod"] == "merge" assert profile["delivery"]["allowedMergeMethods"] == ["merge"] + + +def test_release_profile_enforces_cpu_coverage_without_collecting_hardware_gates(): + profile = yaml.safe_load( + (ROOT / ".aiwg" / "bt6-maintainer.yaml").read_text(encoding="utf-8"), + ) + commands = "\n".join(profile["validation"]["full"]) + + assert "--cov-branch" in commands + assert "--min-line 75" in commands + assert "--min-branch 60" in commands + assert "scripts/check_quality_policy.py" in commands + assert "scripts/check_conditional_policy.py" in commands + assert "scripts/check_test_risk_map.py" in commands + for marker in ("gpu", "mps", "mlx", "network", "download", "remote", "operator_ui"): + assert f"not {marker}" in commands + + assert profile["validation"]["qualityPolicy"]["fullSuiteTrigger"] == ( + "release-readiness-and-tagged-validation" + ) + assert profile["releaseEvidence"] == { + "hashAlgorithm": "sha256", + "provenanceFormat": "slsa-v1", + "attestationFormat": "in-toto", + "signingMode": "sigstore-keyless", + "sbomFormat": "cyclonedx", + "buildOnce": True, + "verifyBeforePromotion": True, + } diff --git a/tests/test_ci_policy.py b/tests/test_ci_policy.py index aa3adfc..a819c11 100644 --- a/tests/test_ci_policy.py +++ b/tests/test_ci_policy.py @@ -41,6 +41,28 @@ def test_every_external_action_is_sha_pinned_and_manifested(): assert entries[("action", name)] == (pin, version) +def test_release_artifacts_are_built_once_attested_and_reused(): + workflow = WORKFLOW.read_text(encoding="utf-8") + package = workflow.split(" package:\n", maxsplit=1)[1].split( + " lint:\n", maxsplit=1, + )[0] + supply_chain = workflow.split(" supply-chain:\n", maxsplit=1)[1] + + assert "artifact-metadata: write" in package + assert "attestations: write" in package + assert "id-token: write" in package + assert "package-evidence/SHA256SUMS" in package + assert "package-evidence/obliteratus.cdx.json" in package + assert package.count("uses: actions/attest@") == 2 + assert "subject-checksums: package-evidence/SHA256SUMS" in package + assert "sbom-path: package-evidence/obliteratus.cdx.json" in package + + assert "needs: package" in supply_chain + assert "uses: actions/download-artifact@" in supply_chain + assert "sha256sum -c package-evidence/SHA256SUMS" in supply_chain + assert "-m build" not in supply_chain + + def test_actionlint_version_and_checksum_match_manifest(): workflow = WORKFLOW.read_text(encoding="utf-8") pin, version = _manifest_entries()[("tool", "rhysd/actionlint")]