From 1eba53c79879ddd461d9a12fb141aaf094268869 Mon Sep 17 00:00:00 2001 From: stacknil Date: Wed, 22 Apr 2026 02:15:04 +0800 Subject: [PATCH] Harden sbom-diff-and-risk release verification docs --- .github/workflows/sbom-diff-and-risk-ci.yml | 68 ++++++++- .../sbom-diff-and-risk-code-scanning.yml | 27 +++- tools/sbom-diff-and-risk/README.md | 36 ++++- .../docs/github-code-scanning.md | 13 ++ .../docs/pypi-trusted-publishing-readiness.md | 144 ++++++++++++++++++ .../docs/release-provenance.md | 87 +++++++++++ .../docs/self-provenance.md | 21 ++- tools/sbom-diff-and-risk/docs/verification.md | 41 +++++ 8 files changed, 418 insertions(+), 19 deletions(-) create mode 100644 tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md create mode 100644 tools/sbom-diff-and-risk/docs/release-provenance.md create mode 100644 tools/sbom-diff-and-risk/docs/verification.md diff --git a/.github/workflows/sbom-diff-and-risk-ci.yml b/.github/workflows/sbom-diff-and-risk-ci.yml index 941fdf1..e6c37f0 100644 --- a/.github/workflows/sbom-diff-and-risk-ci.yml +++ b/.github/workflows/sbom-diff-and-risk-ci.yml @@ -1,8 +1,12 @@ name: sbom-diff-and-risk-ci +run-name: sbom-diff-and-risk ci / ${{ github.event_name }} / ${{ github.ref_name }} on: workflow_dispatch: push: + # Version tags provide a minimal release-build scaffold without changing publishing. + tags: + - "v*" paths: - ".github/workflows/sbom-diff-and-risk-ci.yml" - "tools/sbom-diff-and-risk/**" @@ -11,8 +15,12 @@ on: - ".github/workflows/sbom-diff-and-risk-ci.yml" - "tools/sbom-diff-and-risk/**" +permissions: {} + env: + SBOM_DIFF_RISK_PYTHON_VERSION: "3.11" SBOM_DIFF_RISK_DIST_ARTIFACT_NAME: sbom-diff-and-risk-dist + SBOM_DIFF_RISK_RELEASE_TITLE_PREFIX: sbom-diff-and-risk jobs: test: @@ -24,12 +32,12 @@ jobs: working-directory: tools/sbom-diff-and-risk steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: "3.11" + python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} - name: Upgrade pip run: python -m pip install --upgrade pip @@ -70,12 +78,12 @@ jobs: working-directory: tools/sbom-diff-and-risk steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: - python-version: "3.11" + python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} - name: Upgrade pip run: python -m pip install --upgrade pip @@ -99,3 +107,51 @@ jobs: uses: actions/attest@v4 with: subject-path: ${{ github.workspace }}/tools/sbom-diff-and-risk/dist/* + + publish-release-assets: + # Publish the exact built wheel/sdist bytes from this run as release assets. + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + needs: build-and-attest + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download built distribution artifact + uses: actions/download-artifact@v4 + with: + name: ${{ env.SBOM_DIFF_RISK_DIST_ARTIFACT_NAME }} + path: release-assets + + - name: Publish release assets from CI-built distributions + shell: bash + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ github.ref_name }} + RELEASE_TITLE_PREFIX: ${{ env.SBOM_DIFF_RISK_RELEASE_TITLE_PREFIX }} + run: | + set -euo pipefail + shopt -s nullglob + assets=(release-assets/*.whl release-assets/*.tar.gz) + if [ "${#assets[@]}" -eq 0 ]; then + echo "No release assets found in release-assets/" >&2 + exit 1 + fi + + title="${RELEASE_TITLE_PREFIX} ${RELEASE_TAG}" + + if gh release view "${RELEASE_TAG}" >/dev/null 2>&1; then + is_draft="$(gh release view "${RELEASE_TAG}" --json isDraft -q .isDraft)" + if [ "${is_draft}" != "true" ]; then + echo "Release ${RELEASE_TAG} already exists and is published; leaving assets unchanged." + exit 0 + fi + else + gh release create "${RELEASE_TAG}" \ + --draft \ + --verify-tag \ + --title "${title}" \ + --notes "Release assets for ${RELEASE_TAG}. See docs/release-provenance.md for provenance verification guidance." + fi + + gh release upload "${RELEASE_TAG}" "${assets[@]}" --clobber + gh release edit "${RELEASE_TAG}" --draft=false --title "${title}" diff --git a/.github/workflows/sbom-diff-and-risk-code-scanning.yml b/.github/workflows/sbom-diff-and-risk-code-scanning.yml index 5f8ff65..f05c639 100644 --- a/.github/workflows/sbom-diff-and-risk-code-scanning.yml +++ b/.github/workflows/sbom-diff-and-risk-code-scanning.yml @@ -1,4 +1,5 @@ name: sbom-diff-and-risk-code-scanning +run-name: sbom-diff-and-risk code scanning / ${{ github.event_name }} / ${{ github.ref_name }} on: workflow_dispatch: @@ -7,6 +8,14 @@ on: - ".github/workflows/sbom-diff-and-risk-code-scanning.yml" - "tools/sbom-diff-and-risk/**" +permissions: {} + +env: + SBOM_DIFF_RISK_PYTHON_VERSION: "3.11" + SBOM_DIFF_RISK_SARIF_ARTIFACT_NAME: sbom-diff-and-risk-sarif + SBOM_DIFF_RISK_SARIF_CATEGORY: sbom-diff-risk/example + SBOM_DIFF_RISK_SARIF_FILE: outputs/report.sarif + jobs: upload-sarif: runs-on: ubuntu-latest @@ -23,7 +32,10 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" + python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} + + - name: Upgrade pip + run: python -m pip install --upgrade pip - name: Install sbom-diff-and-risk run: python -m pip install -e .[dev] @@ -34,10 +46,17 @@ jobs: python -m sbom_diff_risk.cli compare \ --before examples/sarif_before.json \ --after examples/sarif_after.json \ - --out-sarif outputs/report.sarif + --out-sarif ${{ env.SBOM_DIFF_RISK_SARIF_FILE }} + + - name: Upload SARIF workflow artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.SBOM_DIFF_RISK_SARIF_ARTIFACT_NAME }} + path: tools/sbom-diff-and-risk/${{ env.SBOM_DIFF_RISK_SARIF_FILE }} + if-no-files-found: error - name: Upload SARIF to code scanning uses: github/codeql-action/upload-sarif@v4 with: - sarif_file: tools/sbom-diff-and-risk/outputs/report.sarif - category: sbom-diff-risk/example + sarif_file: tools/sbom-diff-and-risk/${{ env.SBOM_DIFF_RISK_SARIF_FILE }} + category: ${{ env.SBOM_DIFF_RISK_SARIF_CATEGORY }} diff --git a/tools/sbom-diff-and-risk/README.md b/tools/sbom-diff-and-risk/README.md index c0a3ccc..67452e1 100644 --- a/tools/sbom-diff-and-risk/README.md +++ b/tools/sbom-diff-and-risk/README.md @@ -1,11 +1,18 @@ # sbom-diff-and-risk -v0.3.0 adds opt-in PyPI provenance enrichment, provenance-aware policy and reporting, optional advisory Scorecard signals, and self-provenance verification guidance for workflow-built artifacts. +v0.4 keeps dependency analysis local and deterministic by default while improving how consumers verify `sbom-diff-and-risk` itself through workflow-built artifacts and GitHub Release assets. `sbom-diff-and-risk` is a local, deterministic CLI for comparing two SBOMs or dependency manifests and producing JSON plus Markdown reports. It uses conservative heuristics for change intelligence. By default it does not resolve CVEs, does not act as a reputation oracle, and does not perform hidden network enrichment. +## Start Here + +This project has two different provenance stories: + +1. If you want to verify `sbom-diff-and-risk` itself, start with [docs/verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md). +2. If you want to use `sbom-diff-and-risk` to analyze third-party dependency provenance, start with [Dependency provenance analysis](#dependency-provenance-analysis-opt-in) and [Dependency provenance reporting](#dependency-provenance-reporting). + ## Scope - Normalize two local inputs into a shared component schema. @@ -163,7 +170,9 @@ sbom-diff-risk compare \ Offline mode remains the default. No network access occurs unless `--enrich-pypi` or `--enrich-scorecard` is set explicitly. -## Opt-in Provenance Enrichment +## Dependency Provenance Analysis (Opt-in) + +This section is about analyzing third-party package provenance signals. It is not about verifying the `sbom-diff-and-risk` tool's own release artifacts. PyPI provenance and integrity enrichment is explicit and additive in this PR: @@ -186,7 +195,7 @@ sbom-diff-risk compare \ --out-json outputs/report-enriched.json ``` -## Provenance-Aware Reporting +## Dependency Provenance Reporting When provenance enrichment is enabled, the reports surface trust signals directly instead of burying them in component evidence: @@ -221,17 +230,26 @@ If you want policy gating, make it explicit with a v3 policy such as [policy-sco Setting `minimum_scorecard_score` alone is advisory metadata for review. It only affects policy outcomes when `scorecard_below_threshold` is configured explicitly in `block_on`, `warn_on`, or `ignore_rules`. -## Self-provenance +## Tool Provenance And Verification + +This section is about verifying `sbom-diff-and-risk` itself. If you want the shortest path to the right verification instructions, start with [docs/verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md). This repository also records provenance for `sbom-diff-and-risk` itself by generating GitHub artifact attestations for the wheel and source distribution produced by the `sbom-diff-and-risk-ci` workflow. - the attested files are the wheel and source distribution built by `python -m build` from `tools/sbom-diff-and-risk` - the build files are uploaded together as the `sbom-diff-and-risk-dist` workflow artifact +- version-tag runs also publish those same built files as GitHub Release assets for the matching tag - only trusted non-PR runs publish the attestation -- consumers can verify provenance with GitHub's attestation tooling after downloading one of those artifacts +- consumers can verify workflow-built artifacts with `gh attestation verify` +- consumers can verify immutable releases and downloaded release assets with `gh release verify` and `gh release verify-asset` - this complements the tool's analysis of third-party supply-chain inputs, but it does not replace that analysis -See [docs/self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md) for the exact attested filenames, where the evidence appears in GitHub, and a run-by-run verification flow for consumers. +Verification docs: + +- [docs/verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md) for the quick decision guide +- [docs/self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md) for workflow-artifact attestation +- [docs/release-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/release-provenance.md) for release-asset verification and immutable release guidance +- [docs/pypi-trusted-publishing-readiness.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md) for PyPI publishing prerequisites and sequencing ## Examples @@ -306,8 +324,14 @@ sbom-diff-risk compare \ For GitHub code scanning integration guidance and a minimal upload workflow, see [docs/github-code-scanning.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/github-code-scanning.md). +For the shortest path to the tool-verification docs, start with [docs/verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md). + For details on how this repository attests the tool's own wheel and source distribution artifacts, see [docs/self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md). +For details on how version-tag releases publish those same build outputs as release assets, and how consumers can verify immutable releases with GitHub CLI, see [docs/release-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/release-provenance.md). + +For PyPI Trusted Publishing readiness, prerequisites, and the reasons this repository does not enable PyPI upload yet, see [docs/pypi-trusted-publishing-readiness.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md). + ## Parser Boundaries Deterministic local mode intentionally supports a conservative subset of packaging syntax. The detailed matrix lives in [docs/parser-boundaries.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/parser-boundaries.md). diff --git a/tools/sbom-diff-and-risk/docs/github-code-scanning.md b/tools/sbom-diff-and-risk/docs/github-code-scanning.md index 2f01476..4832f8c 100644 --- a/tools/sbom-diff-and-risk/docs/github-code-scanning.md +++ b/tools/sbom-diff-and-risk/docs/github-code-scanning.md @@ -11,6 +11,7 @@ The example workflow in `.github/workflows/sbom-diff-and-risk-code-scanning.yml` - checks out the repository - installs Python and the local tool - runs `sbom-diff-risk compare ... --out-sarif` +- uploads the generated SARIF file as the workflow artifact `sbom-diff-and-risk-sarif` - uploads the generated SARIF file with `github/codeql-action/upload-sarif` The example intentionally uses local example inputs and does not depend on secrets or network enrichment. @@ -51,6 +52,18 @@ Set a SARIF category when you upload more than one analysis for the same commit If you upload multiple SARIF files for the same tool and commit without distinct categories, later uploads replace earlier ones. In GitHub Actions, set the `category:` input on `github/codeql-action/upload-sarif`. Outside Actions, use `runAutomationDetails.id` in the SARIF file. +## Manual verification for one workflow run + +After merging a change that touches `tools/sbom-diff-and-risk` or the workflow file itself: + +1. Open the repository's **Actions** tab. +2. Open a successful `sbom-diff-and-risk-code-scanning` run for the pull request, or trigger it manually with `workflow_dispatch`. + - the visible run name starts with `sbom-diff-and-risk code scanning / / ` +3. Confirm that the `upload-sarif` job completed successfully. +4. Download the `sbom-diff-and-risk-sarif` artifact and confirm it contains `report.sarif`. +5. Open the repository's **Security** tab, then **Code scanning**. +6. Confirm the uploaded analysis appears under the category `sbom-diff-risk/example`. + ## What this integration does not cover - It does not add CVE lookup or advisory enrichment. diff --git a/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md b/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md new file mode 100644 index 0000000..0c84015 --- /dev/null +++ b/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md @@ -0,0 +1,144 @@ +# PyPI Trusted Publishing readiness + +This page is a readiness checklist, not an enabled publish flow. + +`sbom-diff-and-risk` is not enabling PyPI Trusted Publishing in this PR because the repository is not yet cleanly ready for a narrow, durable publish workflow. The goal here is to make the distribution-authentication story explicit without wiring a half-configured upload path. + +Official references: + +- [PyPI Trusted Publishing overview](https://docs.pypi.org/trusted-publishers/) +- [Creating a PyPI project with a Trusted Publisher](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/) +- [Publishing with a Trusted Publisher](https://docs.pypi.org/trusted-publishers/using-a-publisher/) + +## Current status + +Today, the repository is ready for: + +- local package builds with `python -m build` +- package metadata validation with `python -m twine check` +- GitHub workflow artifact attestation for built distributions +- GitHub Release asset publication and release-verification guidance + +Today, the repository is not yet ready for enabling PyPI Trusted Publishing by default. + +## Why Trusted Publishing is not enabled yet + +The main blockers are packaging and release-readiness concerns, not OIDC support itself: + +1. The current `README.md` is repository-oriented and contains local absolute file links such as `D:/OneDrive/...`. + Those links are acceptable for the local Codex app, but they are not a clean PyPI-facing long description. +2. The package does not yet have a dedicated, publish-only GitHub Actions workflow with the minimal Trusted Publishing permissions and a clear separation between build and upload responsibilities. +3. PyPI-side configuration has not been established yet. + That includes either: + - a pending publisher for a new `sbom-diff-and-risk` project, or + - a trusted publisher entry on an existing PyPI project +4. The first PyPI release version and release sequencing have not been pinned down yet. + The repository currently builds version `0.3.0`, while the repository work is now in the `v0.4` release-hardening theme. + +Because of those gaps, enabling a publish job now would create a fragile or misleading path. + +## Local checks that already pass + +These checks are useful, but they are not sufficient to justify enabling Trusted Publishing: + +```bash +cd tools/sbom-diff-and-risk +python -m build +$files = Get-ChildItem dist | ForEach-Object { $_.FullName } +python -m twine check $files +``` + +What those checks prove: + +- the package can be built locally +- the built distributions pass Twine's metadata/rendering validation + +What they do not prove: + +- that the README and linked documentation are appropriate for PyPI users +- that the repository and PyPI project are wired together for OIDC publishing +- that GitHub-side and PyPI-side Trusted Publishing configuration matches exactly + +## Readiness checklist before enabling Trusted Publishing + +Complete these items first: + +### 1. Make the package description PyPI-facing + +- Replace local absolute-path links in `tools/sbom-diff-and-risk/README.md` with links that render sensibly on PyPI. +- If the repository still needs desktop-specific local links, create a separate PyPI-oriented readme or another long-description strategy for packaging. +- Re-run: + +```bash +cd tools/sbom-diff-and-risk +python -m build +$files = Get-ChildItem dist | ForEach-Object { $_.FullName } +python -m twine check $files +``` + +### 2. Decide the first PyPI-published version and release sequence + +- Decide whether the first PyPI upload should be `0.3.0`, `0.4.0`, or a later release. +- Ensure the tag, package version, release notes, GitHub Release assets, and PyPI upload plan all refer to the same version. + +### 3. Configure PyPI-side Trusted Publishing + +PyPI Trusted Publishing should use OIDC and short-lived credentials instead of a long-lived API token. + +On PyPI, configure either: + +- a pending publisher for a new project, or +- a trusted publisher for an existing project + +Record the exact values that must match GitHub: + +- owner: `stacknil` +- repository: `scientific-computing-toolkit` +- workflow file path that will publish +- optional environment name, if the workflow uses one + +### 4. Add a dedicated publish workflow only after the above is true + +When the repository is actually ready, add a dedicated publish workflow that: + +- uploads only from previously built distribution files +- uses explicit minimal permissions +- uses OIDC via `id-token: write` +- uses the official PyPA publish action +- does not rebuild the package in the upload step + +The intended shape is: + +- one build job that produces the wheel and sdist +- one publish job that downloads those artifacts and uploads them to PyPI + +### 5. Validate on TestPyPI or an equivalent dry-run path first + +Before production PyPI adoption: + +- validate the workflow against TestPyPI or an equivalent pre-production publisher setup +- confirm the GitHub-side workflow identity exactly matches the PyPI-side trusted publisher configuration +- confirm the upload uses OIDC and no long-lived PyPI token secret + +## What the future Trusted Publishing PR should contain + +Once the checklist above is complete, the next publishing PR should be narrow and production-oriented: + +- add a dedicated publish workflow +- document the exact PyPI-side trusted publisher configuration +- document the exact GitHub trigger path for publishing +- preserve the current GitHub workflow artifact attestation and release-asset provenance story +- explain how PyPI distribution provenance relates to, but does not replace, GitHub artifact and release verification + +## Important boundary + +This repository already has: + +- tool provenance guidance for GitHub workflow artifacts +- release provenance guidance for GitHub Releases and release assets + +It does not yet have: + +- enabled PyPI Trusted Publishing +- documented TestPyPI validation +- a production-ready PyPI upload workflow diff --git a/tools/sbom-diff-and-risk/docs/release-provenance.md b/tools/sbom-diff-and-risk/docs/release-provenance.md new file mode 100644 index 0000000..b983d47 --- /dev/null +++ b/tools/sbom-diff-and-risk/docs/release-provenance.md @@ -0,0 +1,87 @@ +# Release provenance and release asset verification + +`sbom-diff-and-risk` now has two GitHub-hosted provenance surfaces for its packaged wheel and source distribution: + +1. workflow-artifact attestations for the files built by `.github/workflows/sbom-diff-and-risk-ci.yml` +2. GitHub Release verification for version-tag releases that publish those same built files as release assets + +This document is about the second surface: verifying a GitHub Release and a downloaded release asset. + +This page is only about the `sbom-diff-and-risk` tool's own GitHub Releases. If you want the quick "which verification page do I need?" guide, start with [verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md). + +## What the release workflow now does + +For version tags matching `v*`, the `sbom-diff-and-risk-ci` workflow: + +1. builds the wheel and source distribution in `build-and-attest` +2. uploads them as the workflow artifact `sbom-diff-and-risk-dist` +3. generates a workflow artifact attestation for those built files +4. downloads that same workflow artifact in `publish-release-assets` +5. publishes those exact `.whl` and `.tar.gz` files as GitHub Release assets for the matching tag + +This intentionally reuses the same workflow-built bytes for both the workflow artifact and the release asset surfaces. It does not add PyPI publishing or a separate rebuild-only release pipeline. + +## What release verification covers + +GitHub Release verification is distinct from workflow artifact attestation: + +- `gh attestation verify` checks a file against the workflow artifact attestation produced by `build-and-attest` +- `gh release verify` checks that a GitHub Release has a valid release attestation +- `gh release verify-asset` checks that a local file exactly matches an attested asset from that release + +Release verification only works for immutable releases. Per GitHub's release integrity and immutable release documentation, immutable releases automatically generate a release attestation and protect release assets from modification after publication. + +If immutable releases are not enabled for the repository, the release may still contain assets, but `gh release verify` and `gh release verify-asset` are not the source of truth. In that case, use the workflow-artifact attestation flow from [self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md). + +## Manual verification for a release + +Use this path after a successful version-tag run such as `v0.4.0`. + +1. Open the repository's **Releases** page. +2. Open the release for the version tag you want to verify. +3. Check whether the release is immutable before relying on release verification: + +```bash +gh release view v0.4.0 --repo stacknil/scientific-computing-toolkit --json isImmutable,assets,url +``` + +4. Confirm the release includes the packaged assets: + - `sbom_diff_and_risk--py3-none-any.whl` + - `sbom_diff_and_risk-.tar.gz` +5. If the repository uses immutable releases, confirm GitHub shows `Immutable` on the release page. +6. Download one of the release assets locally. +7. Verify the release itself with GitHub CLI: + +```bash +gh release verify v0.4.0 --repo stacknil/scientific-computing-toolkit +``` + +8. Verify the downloaded asset against the release attestation: + +```bash +gh release verify-asset v0.4.0 path/to/sbom_diff_and_risk-0.4.0-py3-none-any.whl \ + --repo stacknil/scientific-computing-toolkit +``` + +If `isImmutable` is `false`, the release asset can still be downloaded, but the supported provenance path for this repository remains the workflow-artifact attestation flow from [self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md). + +You can inspect structured output as JSON: + +```bash +gh release verify v0.4.0 \ + --repo stacknil/scientific-computing-toolkit \ + --format json +``` + +```bash +gh release verify-asset v0.4.0 path/to/sbom_diff_and_risk-0.4.0.tar.gz \ + --repo stacknil/scientific-computing-toolkit \ + --format json +``` + +## Important boundary notes + +- `gh release verify-asset` verifies a local file path against a release attestation. It does not verify a workflow artifact download directly unless that file is also a release asset. +- GitHub's generated source-code ZIP and tarball downloads are not covered by `gh release verify-asset`. +- A successful release verification does not replace the workflow-artifact attestation story; it complements it. +- This repository still does not add PyPI Trusted Publishing or PyPI provenance in this PR. For prerequisites and sequencing, see [pypi-trusted-publishing-readiness.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md). diff --git a/tools/sbom-diff-and-risk/docs/self-provenance.md b/tools/sbom-diff-and-risk/docs/self-provenance.md index a955ab2..39e2b3b 100644 --- a/tools/sbom-diff-and-risk/docs/self-provenance.md +++ b/tools/sbom-diff-and-risk/docs/self-provenance.md @@ -2,6 +2,8 @@ `sbom-diff-and-risk` analyzes third-party dependency changes, but consumers should also be able to verify where the tool itself came from. This repository generates GitHub artifact attestations for the packaged build outputs produced by the `sbom-diff-and-risk-ci` workflow. +This page is only about verifying the `sbom-diff-and-risk` tool's own build artifacts. If you want the top-level decision guide, start with [verification.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/verification.md). If you want to analyze third-party dependency provenance with the CLI, go back to the README's dependency provenance sections instead of this page. + ## What is attested in this repository The attested subjects are the exact Python distributables built from `tools/sbom-diff-and-risk` via `python -m build`: @@ -11,7 +13,9 @@ The attested subjects are the exact Python distributables built from `tools/sbom Those two files are uploaded together as the workflow artifact named `sbom-diff-and-risk-dist`. The attestation applies to the built files themselves, not just to the artifact bundle name shown in the Actions UI. -This repository does not currently publish PyPI Trusted Publishing provenance or immutable GitHub release attestations as part of this workflow. The current self-provenance coverage is limited to the workflow-produced wheel and source distribution files. +On version tags matching `v*`, the same workflow also publishes those exact wheel and sdist files as GitHub Release assets for the matching tag. The workflow-artifact attestation story remains the build-provenance source of truth for the files themselves; release verification is an additional GitHub-hosted surface layered on top of those same bytes. + +This repository does not currently publish PyPI Trusted Publishing provenance. Release verification is separate from workflow-artifact attestations and depends on GitHub immutable releases being enabled for the repository. When immutable releases are enabled, GitHub automatically generates a release attestation covering the published release record and its attached assets. ## Workflow and permissions @@ -24,17 +28,22 @@ That job runs only for trusted non-PR events in this repository: Pull request runs still execute the `test` job, but they do not publish artifact attestations. +On version tags matching `v*`, the same workflow also runs `publish-release-assets`, which downloads the already-built `sbom-diff-and-risk-dist` artifact from the workflow run and uploads those same files to the GitHub Release for that tag. + The `build-and-attest` job uses the minimum explicit permissions required for GitHub-hosted build provenance: - `contents: read` for repository checkout - `id-token: write` for GitHub's signing identity - `attestations: write` to publish the attestation +Regular branch pushes remain path-filtered to the `sbom-diff-and-risk` workflow file and tool directory. The workflow also accepts version tags matching `v*`, which gives the repository a minimal release-oriented build path that now covers workflow artifact attestation plus GitHub Release asset publication, without adding PyPI publishing. + ## Where provenance evidence appears in GitHub After a successful non-PR run of `sbom-diff-and-risk-ci`, consumers can find the evidence in two useful places: 1. On the workflow run page: + - the run name starts with `sbom-diff-and-risk ci / / ` - the uploaded artifact appears as `sbom-diff-and-risk-dist` - this is the run consumers should use to confirm the workflow name, job name, and downloaded artifact bundle before verification 2. In the repository-wide attestations view: @@ -46,10 +55,11 @@ On the **Attestations** page, the relevant subjects are the wheel and sdist file ## Manual verification for one workflow run -Use this path after a merge to the default branch or an intentional `workflow_dispatch` run. +Use this path after a merge to the default branch, a version-tag push such as `v0.4.0`, or an intentional `workflow_dispatch` run. 1. Open the repository's **Actions** tab. 2. Open a successful `sbom-diff-and-risk-ci` run triggered by `push` or `workflow_dispatch`. + - for a release-oriented check, prefer a run whose visible name looks like `sbom-diff-and-risk ci / push / v0.4.0` 3. Confirm that the `build-and-attest` job ran successfully. 4. Download the `sbom-diff-and-risk-dist` artifact from that run. 5. Confirm the downloaded archive contains exactly the expected build outputs for that version: @@ -88,7 +98,12 @@ A successful verification confirms that: ## Release-consumer note -If these same wheel or source distribution bytes are later attached to a GitHub release, consumers should verify the downloaded release asset file itself with the same `gh attestation verify` flow. In the current setup, the provenance source of truth is still the workflow-produced build artifact and its attestation, not a separate release-attestation workflow. +If these same wheel or source distribution bytes are attached to a GitHub release, consumers now have two related but distinct verification surfaces: + +- use `gh attestation verify` when you want to verify the workflow-built file against the workflow artifact attestation +- use `gh release verify` and `gh release verify-asset` when you want to verify the GitHub Release record and a downloaded release asset from an immutable release + +These flows complement each other. The workflow-artifact attestation answers "were these bytes built by this workflow?", while immutable release verification answers "does this published release and local release asset exactly match GitHub's release attestation?" See [release-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/release-provenance.md) for the release-specific consumer flow. ## How this complements the tool's own analysis diff --git a/tools/sbom-diff-and-risk/docs/verification.md b/tools/sbom-diff-and-risk/docs/verification.md new file mode 100644 index 0000000..76e2d66 --- /dev/null +++ b/tools/sbom-diff-and-risk/docs/verification.md @@ -0,0 +1,41 @@ +# Verification guide + +Use this page when you are trying to figure out which provenance or verification instructions apply to `sbom-diff-and-risk`. + +## Choose the question you are trying to answer + +### 1. "How do I verify `sbom-diff-and-risk` itself?" + +Use the tool provenance docs: + +- [self-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/self-provenance.md) if you want to verify the workflow-built wheel or source distribution with `gh attestation verify` +- [release-provenance.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/release-provenance.md) if you want to verify a GitHub Release or a downloaded release asset with `gh release verify` or `gh release verify-asset` +- [pypi-trusted-publishing-readiness.md](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md) if you want to know whether this package is ready for PyPI Trusted Publishing + +Current boundaries: + +- the workflow name is `sbom-diff-and-risk-ci` +- the workflow artifact name is `sbom-diff-and-risk-dist` +- version-tag runs matching `v*` can publish the same built files as GitHub Release assets +- release verification depends on immutable releases being enabled for the repository +- this repository still does not publish to PyPI in this flow; see the readiness checklist before enabling that path + +### 2. "How do I use `sbom-diff-and-risk` to analyze third-party dependency provenance?" + +Use the dependency-analysis docs in the README: + +- [Dependency provenance analysis](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/README.md#dependency-provenance-analysis-opt-in) +- [Dependency provenance reporting](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/README.md#dependency-provenance-reporting) +- [Enforcement mode](D:/OneDrive/Code/scientific-computing-toolkit/tools/sbom-diff-and-risk/README.md#enforcement-mode) + +Current boundaries: + +- default CLI behavior remains local and deterministic +- no hidden network access occurs unless enrichment flags are set explicitly +- dependency provenance analysis is about third-party packages, not about verifying the `sbom-diff-and-risk` tool's own artifacts +- release verification and workflow artifact attestation do not change CLI analysis behavior + +## One-line summary + +- Verify the tool itself: use `self-provenance.md` or `release-provenance.md` +- Analyze dependencies with the tool: use the README's dependency provenance sections