mirror of
https://github.com/elder-plinius/OBLITERATUS.git
synced 2026-08-29 22:20:36 +02:00
ci: release tested source snapshots only
This commit is contained in:
+5
-5
@@ -49,7 +49,7 @@
|
||||
"bt6-maintainer": {
|
||||
"version": "0.3.0",
|
||||
"source": "project-local",
|
||||
"installedAt": "2026-08-22T14:56:47.190Z",
|
||||
"installedAt": "2026-08-22T15:28:11.760Z",
|
||||
"deployedTo": {
|
||||
"codex": {
|
||||
"agents": 5,
|
||||
@@ -74,8 +74,8 @@
|
||||
"skills/bt6-pr-audit/SKILL.md": "38be15ba6c6c12f958c7ced0bf6152654dc6df53ddc17156fda84083ae990ea9",
|
||||
"skills/bt6-provider-review/SKILL.md": "a95ac6d2be20847626bb94e5038358148d4a19c25e00ade6049526f8a16d0c15",
|
||||
"skills/bt6-queue-audit/SKILL.md": "aaa77f2e14b46a2f8329025923ed54745152cea6896c947580f7a1babff81312",
|
||||
"skills/bt6-release-readiness/SKILL.md": "b51881662f27604c518c67e009187b3b0bad1d0755116efae1b0d1505dbb3dfe",
|
||||
"skills/bt6-release-validation/SKILL.md": "3ecf342ad12cd1eed2f38ed8eb5b7fb4e396a4e25c79b54e5f649eef0c10c866"
|
||||
"skills/bt6-release-readiness/SKILL.md": "26c65c1f64ce29f947be8a90987489a499814c360f4789ed80ef35f711c3d4e0",
|
||||
"skills/bt6-release-validation/SKILL.md": "9c0dfe72690bdcae273624be730751951b42bab36b538989a8708c0fb48f76d1"
|
||||
},
|
||||
"deployedArtifactHashes": {
|
||||
"codex": {
|
||||
@@ -90,8 +90,8 @@
|
||||
"skills/bt6-pr-audit/SKILL.md": "9a1e55bfd6972f3168f884d54cd6ede3673b541940b54352120ed4c0a4c49f2c",
|
||||
"skills/bt6-provider-review/SKILL.md": "2de8b37f546dda852bee88d023caf82877baab988aebc219fd83a784c2bf58a3",
|
||||
"skills/bt6-queue-audit/SKILL.md": "e0bdb36c8f8f85a2e9dff0180de2f502972bb8af9b7b13c4661be065354ef893",
|
||||
"skills/bt6-release-readiness/SKILL.md": "e609a2f2197fd8c65239f563a0f8cc594ad0d420e4d18da5ba8362f26574ff52",
|
||||
"skills/bt6-release-validation/SKILL.md": "942cd70729c5c13c384532214ebfff1763fd9374a85abda18925932b6dc79167"
|
||||
"skills/bt6-release-readiness/SKILL.md": "db317a00f8f4198e93e0666a00af29ad645d4c3d50de2e42141d84d6e7c16eb1",
|
||||
"skills/bt6-release-validation/SKILL.md": "e94720ea230a8206d7acf5b3c514c6bdf1b7f81865580b7b2c6df11472bdb384"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ validation:
|
||||
- "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:
|
||||
@@ -40,12 +39,13 @@ validation:
|
||||
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"
|
||||
buildOnce: true
|
||||
snapshotOnce: true
|
||||
verifyBeforePromotion: true
|
||||
riskSurfaces:
|
||||
- id: "model-loading"
|
||||
@@ -67,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/**"]
|
||||
|
||||
@@ -102,21 +102,23 @@
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"artifactType",
|
||||
"hashAlgorithm",
|
||||
"provenanceFormat",
|
||||
"attestationFormat",
|
||||
"signingMode",
|
||||
"sbomFormat",
|
||||
"buildOnce",
|
||||
"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"] },
|
||||
"buildOnce": { "const": true },
|
||||
"snapshotOnce": { "const": true },
|
||||
"verifyBeforePromotion": { "const": true }
|
||||
}
|
||||
},
|
||||
|
||||
@@ -52,10 +52,12 @@ promote a tag.
|
||||
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.
|
||||
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
|
||||
|
||||
|
||||
@@ -45,9 +45,9 @@ 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
|
||||
@@ -55,8 +55,9 @@ and does not publish a release without separate explicit authorization.
|
||||
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.
|
||||
validate the source-SBOM binding, and prove promotion uses the tested
|
||||
snapshot-once ZIP bytes. A checksum without authenticated provenance is
|
||||
incomplete evidence.
|
||||
|
||||
## Decision
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ description: Pre-tag audit and hardening report for moving a candidate from the
|
||||
| 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>` |
|
||||
| Packaging and supply chain | `<policy>` | `<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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,12 +35,13 @@ validation:
|
||||
researchIntegrity:
|
||||
- "<provenance/corpus/reproducibility check>"
|
||||
releaseEvidence:
|
||||
artifactType: "source-zip"
|
||||
hashAlgorithm: "sha256"
|
||||
provenanceFormat: "slsa-v1"
|
||||
attestationFormat: "in-toto"
|
||||
signingMode: "sigstore-keyless"
|
||||
sbomFormat: "cyclonedx"
|
||||
buildOnce: true
|
||||
snapshotOnce: true
|
||||
verifyBeforePromotion: true
|
||||
riskSurfaces:
|
||||
- id: "ingestion"
|
||||
|
||||
+29
-121
@@ -49,54 +49,24 @@ 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
|
||||
run: >-
|
||||
"$BUILD_TOOLS/bin/python" -m build --sdist --wheel
|
||||
|
||||
- name: Verify wheel contents and entry point
|
||||
- name: Create deterministic tested-source snapshot
|
||||
run: |
|
||||
python - <<'PY'
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
- name: Generate and bind CycloneDX SBOM
|
||||
- name: Generate and bind source CycloneDX SBOM
|
||||
run: |
|
||||
uv --preview-features sbom-export export \
|
||||
--locked \
|
||||
@@ -105,95 +75,33 @@ jobs:
|
||||
--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[@]}"
|
||||
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 \
|
||||
--wheel "${wheels[0]}" \
|
||||
--artifact "${snapshots[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 |
|
||||
sha256sum release/*.zip package-evidence/obliteratus.cdx.json |
|
||||
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: Attest release-set SLSA provenance
|
||||
id: provenance
|
||||
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
|
||||
with:
|
||||
subject-checksums: package-evidence/SHA256SUMS
|
||||
|
||||
- name: Attest wheel SBOM
|
||||
- name: Attest source snapshot SBOM
|
||||
id: sbom-attestation
|
||||
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
|
||||
with:
|
||||
subject-path: dist/*.whl
|
||||
subject-path: release/*.zip
|
||||
sbom-path: package-evidence/obliteratus.cdx.json
|
||||
|
||||
- name: Retain Sigstore attestation bundles
|
||||
@@ -204,13 +112,13 @@ jobs:
|
||||
package-evidence/sbom-attestation.sigstore.json
|
||||
sha256sum -c package-evidence/SHA256SUMS
|
||||
|
||||
- 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
|
||||
@@ -770,10 +678,10 @@ jobs:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Download attested release set
|
||||
- name: Download attested tested-source snapshot
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: distributions-py3.12
|
||||
name: tested-source-snapshot-py3.12
|
||||
path: /tmp/supply-chain-evidence/release
|
||||
|
||||
- name: Set up Python
|
||||
@@ -841,18 +749,18 @@ jobs:
|
||||
echo "$status" > "$EVIDENCE/uv-audit-py${version}.status"
|
||||
done
|
||||
|
||||
- name: Verify attested release set and bound CycloneDX SBOM
|
||||
- name: Verify attested source snapshot and bound CycloneDX SBOM
|
||||
run: |
|
||||
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[@]}"
|
||||
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 "$GITHUB_WORKSPACE/scripts/check_supply_chain_policy.py" sbom \
|
||||
--input package-evidence/obliteratus.cdx.json \
|
||||
--wheel "${wheels[0]}" \
|
||||
--artifact "${snapshots[0]}" \
|
||||
--output "$EVIDENCE/verified-obliteratus.cdx.json"
|
||||
|
||||
- name: Collect packaged-dependency license inventory
|
||||
|
||||
+11
-11
@@ -70,16 +70,16 @@ 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 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 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
|
||||
@@ -91,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
|
||||
|
||||
+12
-12
@@ -11,21 +11,21 @@ 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.
|
||||
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 wheel digest.
|
||||
- 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 rebuild a substitute
|
||||
wheel. Publication must use these same tested and attested bytes. A commit,
|
||||
dependency lock, build instruction, artifact, checksum manifest, SBOM, or
|
||||
`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:
|
||||
@@ -34,7 +34,7 @@ Consumers can perform the portable integrity check with:
|
||||
sha256sum --check SHA256SUMS
|
||||
```
|
||||
|
||||
For authenticity and provenance, verify each distribution against the canonical
|
||||
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.
|
||||
@@ -45,9 +45,9 @@ 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)
|
||||
|
||||
@@ -139,6 +139,7 @@ def test_release_profile_enforces_cpu_coverage_without_collecting_hardware_gates
|
||||
"attestationFormat": "in-toto",
|
||||
"signingMode": "sigstore-keyless",
|
||||
"sbomFormat": "cyclonedx",
|
||||
"buildOnce": True,
|
||||
"artifactType": "source-zip",
|
||||
"snapshotOnce": True,
|
||||
"verifyBeforePromotion": True,
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ 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():
|
||||
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,
|
||||
@@ -53,6 +53,12 @@ def test_release_artifacts_are_built_once_attested_and_reused():
|
||||
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
|
||||
@@ -60,6 +66,8 @@ def test_release_artifacts_are_built_once_attested_and_reused():
|
||||
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
|
||||
|
||||
|
||||
|
||||
@@ -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