mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-30 06:30:37 +02:00
Merge pull request #143 from elder-plinius/feat/142-attest-release-artifacts
CI: bind release evidence to artifact hashes
This commit is contained in:
+1
-1
@@ -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`
|
||||
|
||||
+9
-7
@@ -49,16 +49,16 @@
|
||||
"bt6-maintainer": {
|
||||
"version": "0.3.0",
|
||||
"source": "project-local",
|
||||
"installedAt": "2026-08-21T22:00:58.629Z",
|
||||
"installedAt": "2026-08-22T15:28:11.760Z",
|
||||
"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": "26c65c1f64ce29f947be8a90987489a499814c360f4789ed80ef35f711c3d4e0",
|
||||
"skills/bt6-release-validation/SKILL.md": "9c0dfe72690bdcae273624be730751951b42bab36b538989a8708c0fb48f76d1"
|
||||
},
|
||||
"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": "db317a00f8f4198e93e0666a00af29ad645d4c3d50de2e42141d84d6e7c16eb1",
|
||||
"skills/bt6-release-validation/SKILL.md": "e94720ea230a8206d7acf5b3c514c6bdf1b7f81865580b7b2c6df11472bdb384"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
- "python -m build --sdist --wheel"
|
||||
- "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 -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:
|
||||
artifactType: "source-zip"
|
||||
hashAlgorithm: "sha256"
|
||||
provenanceFormat: "slsa-v1"
|
||||
attestationFormat: "in-toto"
|
||||
signingMode: "sigstore-keyless"
|
||||
sbomFormat: "cyclonedx"
|
||||
snapshotOnce: true
|
||||
verifyBeforePromotion: true
|
||||
riskSurfaces:
|
||||
- id: "model-loading"
|
||||
paths: ["obliteratus/models/**", "obliteratus/device.py", "scripts/**"]
|
||||
@@ -57,7 +67,7 @@ riskSurfaces:
|
||||
- id: "ci-supply-chain"
|
||||
paths: [".github/workflows/**", "ci/**", "docs/SUPPLY_CHAIN_POLICY.md", "pyproject.toml", "scripts/check_supply_chain_policy.py", "uv.lock"]
|
||||
concerns: ["workflow-permissions", "dependency-pinning", "untrusted-pull-request-code"]
|
||||
requiredChecks: ["uv lock --check", "python -m pytest tests/test_ci_policy.py tests/test_supply_chain_policy.py", "python -m build --sdist --wheel"]
|
||||
requiredChecks: ["uv lock --check", "python -m pytest tests/test_ci_policy.py tests/test_supply_chain_policy.py"]
|
||||
research:
|
||||
corpusPaths: ["obliteratus/prompts.py", "community_results/**"]
|
||||
evidencePaths: ["paper/**", "docs/**", "community_results/**"]
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
],
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 <candidate>^{commit} >/dev/null"
|
||||
expect: "report binds the gap inventory, repairs, and final evidence to the exact candidate and comparison base"
|
||||
@@ -91,13 +91,37 @@
|
||||
"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": [
|
||||
"artifactType",
|
||||
"hashAlgorithm",
|
||||
"provenanceFormat",
|
||||
"attestationFormat",
|
||||
"signingMode",
|
||||
"sbomFormat",
|
||||
"snapshotOnce",
|
||||
"verifyBeforePromotion"
|
||||
],
|
||||
"properties": {
|
||||
"artifactType": { "const": "source-zip" },
|
||||
"hashAlgorithm": { "const": "sha256" },
|
||||
"provenanceFormat": { "const": "slsa-v1" },
|
||||
"attestationFormat": { "const": "in-toto" },
|
||||
"signingMode": { "enum": ["sigstore-keyless", "project-defined"] },
|
||||
"sbomFormat": { "enum": ["cyclonedx", "spdx"] },
|
||||
"snapshotOnce": { "const": true },
|
||||
"verifyBeforePromotion": { "const": true }
|
||||
}
|
||||
},
|
||||
"riskSurfaces": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
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 deterministic source ZIP
|
||||
of the tested commit, a canonical SHA-256 manifest, a bound source SBOM,
|
||||
SLSA/in-toto provenance, and the configured signature mechanism. Do not
|
||||
compile or publish installable packages unless a repository explicitly
|
||||
overrides the source-snapshot policy. Downstream gates must consume the same
|
||||
ZIP bytes rather than recreating 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.
|
||||
@@ -45,14 +45,19 @@ and does not publish a release without separate explicit authorization.
|
||||
1. Run every repository-profile `validation.full` command at the exact tagged
|
||||
commit.
|
||||
2. Run applicable `documentation`, `researchIntegrity`, and risk-surface checks.
|
||||
3. Run repository-defined packaging, artifact-integrity, compatibility, and
|
||||
supported-platform checks. Verify generated artifacts come from the tagged
|
||||
source rather than an unrelated checkout.
|
||||
3. Run repository-defined source-snapshot integrity, compatibility, and
|
||||
supported-platform checks. Verify the release ZIP comes from the tagged
|
||||
source rather than an unrelated checkout; do not require a compiled package.
|
||||
4. Compare local evidence with CI for the same tag and commit. Record missing or
|
||||
stale evidence as incomplete, not passing.
|
||||
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 source-SBOM binding, and prove promotion uses the tested
|
||||
snapshot-once ZIP bytes. A checksum without authenticated provenance is
|
||||
incomplete evidence.
|
||||
|
||||
## Decision
|
||||
|
||||
|
||||
@@ -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: `<candidate>`
|
||||
|
||||
## Context
|
||||
|
||||
- Repository: `<canonical repository>`
|
||||
- Candidate commit: `<sha>`
|
||||
- Comparison base: `<previous release or exact base>`
|
||||
- Profile: `<path/version>`
|
||||
- Authorization: `<read-only | repairs authorized>`
|
||||
|
||||
## Merged-risk inventory
|
||||
|
||||
| Surface | Changed behavior | Relevant tests/evidence | Risk | Status |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `<path/component>` | `<behavior>` | `<tests/artifacts>` | `<high/medium/low>` | `<covered/gap>` |
|
||||
|
||||
## Release-depth gates
|
||||
|
||||
| Gate | Threshold or expectation | Result | Evidence |
|
||||
| --- | --- | --- | --- |
|
||||
| Full validation | `<profile validation.full>` | `<pass/fail/not run>` | `<artifact/log>` |
|
||||
| Coverage and regression | `<repository/scope/module floors>` | `<pass/fail>` | `<coverage report>` |
|
||||
| Quality depth | `<repeat/mutation/warnings>` | `<pass/fail/not run>` | `<artifact/log>` |
|
||||
| Source snapshot and supply chain | `<policy>` | `<pass/fail/not run>` | `<ZIP/evidence/log>` |
|
||||
| Conditional/platform checks | `<policy>` | `<pass/fail/deferred>` | `<artifact/CI URL>` |
|
||||
|
||||
## Repairs
|
||||
|
||||
| Finding | Correction | Verification | Residual risk |
|
||||
| --- | --- | --- | --- |
|
||||
| `<gap>` | `<code/test/policy change>` | `<command/result>` | `<risk>` |
|
||||
|
||||
## Decision
|
||||
|
||||
`<ready-to-tag | not-ready | hold>`
|
||||
|
||||
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.
|
||||
@@ -33,7 +33,7 @@ Profile: `<path and hash>`
|
||||
| Documentation | `<pass/fail/n-a>` | `<details>` |
|
||||
| Research and provenance | `<pass/fail/n-a>` | `<details>` |
|
||||
| Risk-surface checks | `<pass/fail/n-a>` | `<details>` |
|
||||
| Packaging and artifact integrity | `<pass/fail/n-a>` | `<details>` |
|
||||
| Source ZIP and artifact integrity | `<pass/fail/n-a>` | `<details>` |
|
||||
| Supported platforms | `<pass/fail/incomplete>` | `<details>` |
|
||||
|
||||
## Decision
|
||||
|
||||
@@ -29,11 +29,20 @@ validation:
|
||||
qualityPolicy:
|
||||
pullRequestChangedLineCoverageFloor: 50
|
||||
requireBehaviorTests: true
|
||||
fullSuiteTrigger: "tagged-release"
|
||||
fullSuiteTrigger: "release-readiness-and-tagged-validation"
|
||||
documentation:
|
||||
- "<docs/link/citation check>"
|
||||
researchIntegrity:
|
||||
- "<provenance/corpus/reproducibility check>"
|
||||
releaseEvidence:
|
||||
artifactType: "source-zip"
|
||||
hashAlgorithm: "sha256"
|
||||
provenanceFormat: "slsa-v1"
|
||||
attestationFormat: "in-toto"
|
||||
signingMode: "sigstore-keyless"
|
||||
sbomFormat: "cyclonedx"
|
||||
snapshotOnce: true
|
||||
verifyBeforePromotion: true
|
||||
riskSurfaces:
|
||||
- id: "ingestion"
|
||||
paths: ["<ingestion or parser paths>"]
|
||||
|
||||
+80
-123
@@ -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
|
||||
|
||||
@@ -44,123 +49,76 @@ jobs:
|
||||
pyproject.toml
|
||||
uv.lock
|
||||
|
||||
- name: Install build tooling
|
||||
- name: Install release evidence tooling
|
||||
run: |
|
||||
python -m pip install "uv==${UV_VERSION}"
|
||||
UV_PROJECT_ENVIRONMENT="$BUILD_TOOLS" uv sync --locked --only-group ci
|
||||
|
||||
- name: Build source and wheel distributions
|
||||
- name: Create deterministic tested-source snapshot
|
||||
run: |
|
||||
mkdir -p release package-evidence
|
||||
snapshot="release/OBLITERATUS-${GITHUB_SHA}.zip"
|
||||
git archive \
|
||||
--format=zip \
|
||||
--prefix="OBLITERATUS-${GITHUB_SHA}/" \
|
||||
--output="$snapshot" \
|
||||
"$GITHUB_SHA"
|
||||
test "$(find release -maxdepth 1 -type f -name '*.zip' | wc -l)" -eq 1
|
||||
unzip -t "$snapshot" | tee package-evidence/source-zip-check.txt
|
||||
|
||||
- name: Generate and bind source 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 snapshots < <(find release -maxdepth 1 -type f -name '*.zip' -print)
|
||||
if [ "${#snapshots[@]}" -ne 1 ]; then
|
||||
echo "expected exactly one source snapshot, found ${#snapshots[@]}"
|
||||
exit 1
|
||||
fi
|
||||
python scripts/check_supply_chain_policy.py sbom \
|
||||
--input package-evidence/obliteratus.cdx.unbound.json \
|
||||
--artifact "${snapshots[0]}" \
|
||||
--output package-evidence/obliteratus.cdx.json
|
||||
rm package-evidence/obliteratus.cdx.unbound.json
|
||||
|
||||
- name: Generate canonical release checksums
|
||||
run: >-
|
||||
"$BUILD_TOOLS/bin/python" -m build --sdist --wheel
|
||||
sha256sum release/*.zip package-evidence/obliteratus.cdx.json |
|
||||
tee package-evidence/SHA256SUMS
|
||||
|
||||
- name: Verify wheel contents and entry point
|
||||
- name: Attest release-set SLSA provenance
|
||||
id: provenance
|
||||
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
|
||||
with:
|
||||
subject-checksums: package-evidence/SHA256SUMS
|
||||
|
||||
- name: Attest source snapshot SBOM
|
||||
id: sbom-attestation
|
||||
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
|
||||
with:
|
||||
subject-path: release/*.zip
|
||||
sbom-path: package-evidence/obliteratus.cdx.json
|
||||
|
||||
- name: Retain Sigstore attestation bundles
|
||||
run: |
|
||||
python - <<'PY'
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile
|
||||
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
|
||||
|
||||
wheels = list(Path("dist").glob("*.whl"))
|
||||
if len(wheels) != 1:
|
||||
raise SystemExit(f"expected one wheel, found: {wheels}")
|
||||
|
||||
with ZipFile(wheels[0]) as archive:
|
||||
names = set(archive.namelist())
|
||||
required = {
|
||||
"app.py",
|
||||
"obliteratus/__init__.py",
|
||||
"obliteratus/local_ui.py",
|
||||
}
|
||||
missing = sorted(required - names)
|
||||
if missing:
|
||||
raise SystemExit(f"wheel is missing required modules: {missing}")
|
||||
|
||||
entry_points = [
|
||||
name for name in names if name.endswith(".dist-info/entry_points.txt")
|
||||
]
|
||||
if len(entry_points) != 1:
|
||||
raise SystemExit(f"expected one entry_points.txt, found: {entry_points}")
|
||||
contents = archive.read(entry_points[0]).decode("utf-8")
|
||||
if "obliteratus = obliteratus.cli:main" not in contents:
|
||||
raise SystemExit("wheel is missing the obliteratus console entry point")
|
||||
|
||||
print(f"verified wheel contents: {wheels[0]}")
|
||||
PY
|
||||
|
||||
- name: Validate distribution metadata
|
||||
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: Verify installed wheel contract
|
||||
run: |
|
||||
mapfile -t wheels < <(find "$GITHUB_WORKSPACE/dist" -maxdepth 1 -type f -name '*.whl' -print)
|
||||
if [ "${#wheels[@]}" -ne 1 ]; then
|
||||
echo "expected exactly one wheel, found ${#wheels[@]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
wheel_env="$RUNNER_TEMP/obliteratus-wheel-env"
|
||||
wheel_cwd="$RUNNER_TEMP/obliteratus-wheel-cwd"
|
||||
python -m venv "$wheel_env"
|
||||
mkdir -p "$wheel_cwd"
|
||||
"$wheel_env/bin/python" -m pip install --no-cache-dir "rich==15.0.0"
|
||||
"$wheel_env/bin/python" -m pip install --no-cache-dir --no-deps "${wheels[0]}"
|
||||
|
||||
cd "$wheel_cwd"
|
||||
"$wheel_env/bin/python" -I - <<'PY' | tee "$GITHUB_WORKSPACE/package-evidence/wheel-import.txt"
|
||||
import importlib.metadata
|
||||
from pathlib import Path
|
||||
|
||||
import obliteratus
|
||||
|
||||
origin = Path(obliteratus.__file__).resolve()
|
||||
assert "site-packages" in origin.parts, origin
|
||||
assert obliteratus.__version__ == importlib.metadata.version("obliteratus")
|
||||
print(f"installed wheel import: {origin}")
|
||||
print(f"version: {obliteratus.__version__}")
|
||||
PY
|
||||
"$wheel_env/bin/python" -I -m obliteratus --help > "$GITHUB_WORKSPACE/package-evidence/wheel-module-help.txt"
|
||||
"$wheel_env/bin/obliteratus" --help > "$GITHUB_WORKSPACE/package-evidence/wheel-console-help.txt"
|
||||
|
||||
- name: Verify installed sdist contract
|
||||
run: |
|
||||
mapfile -t sdists < <(find "$GITHUB_WORKSPACE/dist" -maxdepth 1 -type f -name '*.tar.gz' -print)
|
||||
if [ "${#sdists[@]}" -ne 1 ]; then
|
||||
echo "expected exactly one sdist, found ${#sdists[@]}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sdist_env="$RUNNER_TEMP/obliteratus-sdist-env"
|
||||
sdist_cwd="$RUNNER_TEMP/obliteratus-sdist-cwd"
|
||||
python -m venv "$sdist_env"
|
||||
mkdir -p "$sdist_cwd"
|
||||
"$sdist_env/bin/python" -m pip install --no-cache-dir "rich==15.0.0"
|
||||
"$sdist_env/bin/python" -m pip install --no-cache-dir --no-deps "${sdists[0]}"
|
||||
|
||||
cd "$sdist_cwd"
|
||||
"$sdist_env/bin/python" -I - <<'PY' | tee "$GITHUB_WORKSPACE/package-evidence/sdist-import.txt"
|
||||
import importlib.metadata
|
||||
from pathlib import Path
|
||||
|
||||
import obliteratus
|
||||
|
||||
origin = Path(obliteratus.__file__).resolve()
|
||||
assert "site-packages" in origin.parts, origin
|
||||
assert obliteratus.__version__ == importlib.metadata.version("obliteratus")
|
||||
print(f"installed sdist import: {origin}")
|
||||
print(f"version: {obliteratus.__version__}")
|
||||
PY
|
||||
"$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: Upload distributions and package evidence
|
||||
- name: Upload tested source snapshot and release evidence
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: distributions-py3.12
|
||||
name: tested-source-snapshot-py3.12
|
||||
path: |
|
||||
dist/
|
||||
release/
|
||||
package-evidence/
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
@@ -706,6 +664,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 +678,12 @@ jobs:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Download attested tested-source snapshot
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: tested-source-snapshot-py3.12
|
||||
path: /tmp/supply-chain-evidence/release
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||
with:
|
||||
@@ -784,27 +749,19 @@ jobs:
|
||||
echo "$status" > "$EVIDENCE/uv-audit-py${version}.status"
|
||||
done
|
||||
|
||||
- name: Build wheel and bind CycloneDX SBOM
|
||||
- name: Verify attested source snapshot 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)
|
||||
if [ "${#wheels[@]}" -ne 1 ]; then
|
||||
echo "expected exactly one wheel, found ${#wheels[@]}"
|
||||
cd "$EVIDENCE/release"
|
||||
sha256sum -c package-evidence/SHA256SUMS
|
||||
mapfile -t snapshots < <(find release -maxdepth 1 -type f -name '*.zip' -print)
|
||||
if [ "${#snapshots[@]}" -ne 1 ]; then
|
||||
echo "expected exactly one source snapshot, found ${#snapshots[@]}"
|
||||
exit 1
|
||||
fi
|
||||
python scripts/check_supply_chain_policy.py sbom \
|
||||
--input "$EVIDENCE/obliteratus.cdx.unbound.json" \
|
||||
--wheel "${wheels[0]}" \
|
||||
--output "$EVIDENCE/obliteratus.cdx.json"
|
||||
sha256sum "${wheels[0]}" > "$EVIDENCE/distribution.SHA256SUM"
|
||||
python "$GITHUB_WORKSPACE/scripts/check_supply_chain_policy.py" sbom \
|
||||
--input package-evidence/obliteratus.cdx.json \
|
||||
--artifact "${snapshots[0]}" \
|
||||
--output "$EVIDENCE/verified-obliteratus.cdx.json"
|
||||
|
||||
- name: Collect packaged-dependency license inventory
|
||||
run: >-
|
||||
|
||||
+18
-6
@@ -59,15 +59,27 @@ 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
|
||||
actual `main` commit after every merge; never rewrite `main` to repair history.
|
||||
|
||||
Release CI additionally validates wheel and sdist metadata, installs each distribution
|
||||
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).
|
||||
Release CI creates one deterministic ZIP of the exact tested repository commit.
|
||||
The ZIP is a source snapshot and release-quality marker, not an installable or
|
||||
compiled distribution. Immutable CI action/tool pins are recorded in
|
||||
[ci/digests.txt](ci/digests.txt).
|
||||
|
||||
The package job is the sole source-snapshot producer. It binds the ZIP and
|
||||
CycloneDX source 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 that exact
|
||||
ZIP rather than recreating an equivalent-looking archive.
|
||||
|
||||
The source-to-test ownership graph is versioned in
|
||||
[ci/test-risk-map.json](ci/test-risk-map.json). Coverage, JUnit, repeat, and
|
||||
@@ -79,8 +91,8 @@ flaking twice in 30 days requires an active owner/issue-linked quarantine.
|
||||
Python CI resolution is locked by `uv.lock`, including the official CPU-only
|
||||
PyTorch source for Linux and Windows. The required Supply chain job scans all
|
||||
supported Python versions for known vulnerabilities, scans the checkout for
|
||||
secrets with fully redacted evidence, enforces the packaged-dependency license
|
||||
allow list, and binds a CycloneDX SBOM to the built wheel. Exception and update
|
||||
secrets with fully redacted evidence, enforces the dependency license allow
|
||||
list, and binds a CycloneDX source SBOM to the repository ZIP. Exception and update
|
||||
rules are documented in [docs/SUPPLY_CHAIN_POLICY.md](docs/SUPPLY_CHAIN_POLICY.md).
|
||||
|
||||
GPU, MPS, MLX, model-download, external-evaluation, network, operator-UI, and
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -9,15 +9,45 @@ 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
|
||||
|
||||
The release artifact is a deterministic ZIP snapshot of the tested repository
|
||||
commit. No wheel, source distribution, executable, or other compiled package is
|
||||
published. The release job creates the snapshot once with `git archive`, then
|
||||
emits a bound CycloneDX source SBOM and a canonical `SHA256SUMS` manifest.
|
||||
|
||||
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 source ZIP digest.
|
||||
|
||||
The supply-chain job downloads the package job's retained artifact, verifies
|
||||
`SHA256SUMS`, and revalidates the SBOM binding. It must not create a substitute
|
||||
archive. Publication must use this same tested and attested ZIP. A commit,
|
||||
dependency lock, snapshot 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 the source ZIP 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:
|
||||
|
||||
- one redacted Gitleaks JSON report for the checkout;
|
||||
- OSV audit JSON and scanner status for Python 3.10, 3.11, and 3.12 on Linux;
|
||||
- a JSON license inventory for all packaged extras;
|
||||
- a CycloneDX 1.5 SBOM bound to the built wheel by SHA-256;
|
||||
- the policy decisions and built wheel used by those checks.
|
||||
- a JSON license inventory for all supported dependency extras;
|
||||
- a CycloneDX 1.5 source SBOM bound to the repository ZIP by SHA-256;
|
||||
- the policy decisions and exact tested source ZIP used by those checks.
|
||||
|
||||
Every secret finding and every OSV vulnerability is blocking by default. OSV
|
||||
does not provide a normalized severity for every advisory, so the policy treats
|
||||
|
||||
@@ -291,8 +291,8 @@ def evaluate_secrets(
|
||||
}
|
||||
|
||||
|
||||
def bind_sbom(sbom: object, wheel: Path) -> dict[str, Any]:
|
||||
"""Bind a CycloneDX SBOM to the exact built wheel by SHA-256."""
|
||||
def bind_sbom(sbom: object, artifact: Path) -> dict[str, Any]:
|
||||
"""Bind a CycloneDX SBOM to the exact promoted source artifact by SHA-256."""
|
||||
if not isinstance(sbom, dict) or sbom.get("bomFormat") != "CycloneDX":
|
||||
raise ValueError("SBOM must be a CycloneDX JSON object")
|
||||
if sbom.get("specVersion") != "1.5":
|
||||
@@ -303,12 +303,12 @@ def bind_sbom(sbom: object, wheel: Path) -> dict[str, Any]:
|
||||
component = metadata.get("component")
|
||||
if not isinstance(component, dict) or component.get("name") != "obliteratus":
|
||||
raise ValueError("SBOM metadata must describe obliteratus")
|
||||
digest = hashlib.sha256(wheel.read_bytes()).hexdigest()
|
||||
digest = hashlib.sha256(artifact.read_bytes()).hexdigest()
|
||||
component["hashes"] = [{"alg": "SHA-256", "content": digest}]
|
||||
properties = component.setdefault("properties", [])
|
||||
if not isinstance(properties, list):
|
||||
raise ValueError("SBOM component properties must be a list")
|
||||
properties.append({"name": "obliteratus:distribution-file", "value": wheel.name})
|
||||
properties.append({"name": "obliteratus:release-artifact", "value": artifact.name})
|
||||
return sbom
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ def _parser() -> argparse.ArgumentParser:
|
||||
licenses.add_argument("--decision", type=Path, required=True)
|
||||
sbom = commands.add_parser("sbom")
|
||||
sbom.add_argument("--input", type=Path, required=True)
|
||||
sbom.add_argument("--wheel", type=Path, required=True)
|
||||
sbom.add_argument("--artifact", type=Path, required=True)
|
||||
sbom.add_argument("--output", type=Path, required=True)
|
||||
return parser
|
||||
|
||||
@@ -354,9 +354,9 @@ def main() -> int:
|
||||
failures = validate_policy(_read_json(args.policy))
|
||||
return _write_decision(Path("/dev/null"), {"passed": not failures, "failures": failures})
|
||||
if args.command == "sbom":
|
||||
bound = bind_sbom(_read_json(args.input), args.wheel)
|
||||
bound = bind_sbom(_read_json(args.input), args.artifact)
|
||||
args.output.write_text(json.dumps(bound, indent=2) + "\n", encoding="utf-8")
|
||||
print(f"bound SBOM to {args.wheel.name}")
|
||||
print(f"bound SBOM to {args.artifact.name}")
|
||||
return 0
|
||||
|
||||
policy = _read_json(args.policy)
|
||||
|
||||
@@ -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,33 @@ 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",
|
||||
"artifactType": "source-zip",
|
||||
"snapshotOnce": True,
|
||||
"verifyBeforePromotion": True,
|
||||
}
|
||||
|
||||
@@ -41,6 +41,36 @@ def test_every_external_action_is_sha_pinned_and_manifested():
|
||||
assert entries[("action", name)] == (pin, version)
|
||||
|
||||
|
||||
def test_tested_source_snapshot_is_created_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 'git archive \\' in package
|
||||
assert '--format=zip' in package
|
||||
assert 'subject-path: release/*.zip' in package
|
||||
assert "python -m build" not in package
|
||||
assert "*.whl" not in package
|
||||
assert "*.tar.gz" not 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 "tested-source-snapshot-py3.12" in supply_chain
|
||||
assert "find release -maxdepth 1 -type f -name '*.zip'" 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")]
|
||||
|
||||
@@ -5,13 +5,17 @@ from __future__ import annotations
|
||||
import importlib.metadata
|
||||
import json
|
||||
import sys
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
except ModuleNotFoundError: # pragma: no cover - exercised by the Python 3.10 CI lane
|
||||
import tomli as tomllib
|
||||
|
||||
from scripts import jetson_support
|
||||
from scripts import run_conditional_gate
|
||||
from scripts import setup_jetson
|
||||
|
||||
@@ -177,24 +177,24 @@ def test_secret_gate_requires_redaction_even_for_suppressed_finding():
|
||||
assert any("not fully redacted" in failure for failure in decision["failures"])
|
||||
|
||||
|
||||
def test_bind_sbom_adds_exact_wheel_hash(tmp_path):
|
||||
wheel = tmp_path / "obliteratus-0.1.2-py3-none-any.whl"
|
||||
wheel.write_bytes(b"wheel")
|
||||
def test_bind_sbom_adds_exact_release_artifact_hash(tmp_path):
|
||||
artifact = tmp_path / "OBLITERATUS-deadbeef.zip"
|
||||
artifact.write_bytes(b"source snapshot")
|
||||
sbom = {
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.5",
|
||||
"metadata": {"component": {"name": "obliteratus"}},
|
||||
}
|
||||
|
||||
bound = MODULE.bind_sbom(sbom, wheel)
|
||||
bound = MODULE.bind_sbom(sbom, artifact)
|
||||
|
||||
component = bound["metadata"]["component"]
|
||||
assert component["hashes"] == [
|
||||
{
|
||||
"alg": "SHA-256",
|
||||
"content": "ba59926159d2aa256eb8739b8da7e2b574b960e1202c6d624cbe981cef996c91",
|
||||
"content": "41637c7875947b50775c0ab2bb30a28b292be748376a5713eb8f527d9953433c",
|
||||
},
|
||||
]
|
||||
assert component["properties"] == [
|
||||
{"name": "obliteratus:distribution-file", "value": wheel.name},
|
||||
{"name": "obliteratus:release-artifact", "value": artifact.name},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user