From e42b0def375a03ecb8a90d6bb7ef63a9a779c940 Mon Sep 17 00:00:00 2001 From: stacknil Date: Mon, 29 Jun 2026 19:52:16 +0800 Subject: [PATCH] chore(repo): normalize lf endings --- .github/workflows/sbom-diff-and-risk-ci.yml | 266 +++++++-------- .../pypi-production-publishing-decision.md | 256 +++++++-------- .../docs/pypi-trusted-publishing-readiness.md | 304 +++++++++--------- .../docs/release-provenance.md | 84 ++--- .../sbom-diff-and-risk/docs/reviewer-brief.md | 72 ++--- .../docs/self-provenance.md | 226 ++++++------- tools/sbom-diff-and-risk/docs/verification.md | 62 ++-- .../src/sbom_diff_risk/__init__.py | 8 +- 8 files changed, 639 insertions(+), 639 deletions(-) diff --git a/.github/workflows/sbom-diff-and-risk-ci.yml b/.github/workflows/sbom-diff-and-risk-ci.yml index 10056d9..1149e19 100644 --- a/.github/workflows/sbom-diff-and-risk-ci.yml +++ b/.github/workflows/sbom-diff-and-risk-ci.yml @@ -1,97 +1,97 @@ -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/**" - pull_request: - paths: - - ".github/workflows/sbom-diff-and-risk-ci.yml" - - "tools/sbom-diff-and-risk/**" - -permissions: {} - -env: +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/**" + pull_request: + paths: + - ".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_CHECKSUM_MANIFEST: sbom-diff-and-risk-SHA256SUMS.txt SBOM_DIFF_RISK_RELEASE_TITLE_PREFIX: sbom-diff-and-risk - -jobs: - test: - runs-on: ubuntu-latest - permissions: - contents: read - defaults: - run: - working-directory: tools/sbom-diff-and-risk - steps: - - name: Check out repository - uses: actions/checkout@v6 - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} - - - name: Upgrade pip - run: python -m pip install --upgrade pip - - - name: Install project - run: python -m pip install -e .[dev] - - - name: Run test suite - run: python -m pytest - - - name: CLI smoke test - shell: bash - run: | - tmpdir="$(mktemp -d)" - python -m sbom_diff_risk.cli compare \ - --before examples/cdx_before.json \ - --after examples/cdx_after.json \ - --format auto \ - --out-json "$tmpdir/report.json" \ - --out-md "$tmpdir/report.md" - test -f "$tmpdir/report.json" - test -f "$tmpdir/report.md" - diff -u examples/sample-report.json "$tmpdir/report.json" - diff -u examples/sample-report.md "$tmpdir/report.md" - - build-and-attest: - # Keep provenance publication on trusted non-PR runs so consumers verify - # workflow-produced wheel/sdist artifacts from this repository workflow. - if: github.event_name != 'pull_request' - needs: test - runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - attestations: write - defaults: - run: - working-directory: tools/sbom-diff-and-risk - steps: - - name: Check out repository - uses: actions/checkout@v6 - - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} - - - name: Upgrade pip - run: python -m pip install --upgrade pip - - - name: Install build tooling - run: python -m pip install build - + +jobs: + test: + runs-on: ubuntu-latest + permissions: + contents: read + defaults: + run: + working-directory: tools/sbom-diff-and-risk + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} + + - name: Upgrade pip + run: python -m pip install --upgrade pip + + - name: Install project + run: python -m pip install -e .[dev] + + - name: Run test suite + run: python -m pytest + + - name: CLI smoke test + shell: bash + run: | + tmpdir="$(mktemp -d)" + python -m sbom_diff_risk.cli compare \ + --before examples/cdx_before.json \ + --after examples/cdx_after.json \ + --format auto \ + --out-json "$tmpdir/report.json" \ + --out-md "$tmpdir/report.md" + test -f "$tmpdir/report.json" + test -f "$tmpdir/report.md" + diff -u examples/sample-report.json "$tmpdir/report.json" + diff -u examples/sample-report.md "$tmpdir/report.md" + + build-and-attest: + # Keep provenance publication on trusted non-PR runs so consumers verify + # workflow-produced wheel/sdist artifacts from this repository workflow. + if: github.event_name != 'pull_request' + needs: test + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + attestations: write + defaults: + run: + working-directory: tools/sbom-diff-and-risk + steps: + - name: Check out repository + uses: actions/checkout@v6 + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: ${{ env.SBOM_DIFF_RISK_PYTHON_VERSION }} + + - name: Upgrade pip + run: python -m pip install --upgrade pip + + - name: Install build tooling + run: python -m pip install build + - name: Build distributable artifacts run: python -m build @@ -135,34 +135,34 @@ jobs: subject-path: | ${{ github.workspace }}/tools/sbom-diff-and-risk/dist/*.whl ${{ github.workspace }}/tools/sbom-diff-and-risk/dist/*.tar.gz - - publish-release-assets: + + publish-release-assets: # Publish the exact built wheel/sdist bytes and checksum manifest from this run. - if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') - needs: build-and-attest - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Check out repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + needs: build-and-attest + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Check out repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Download built distribution artifact and checksum manifest - uses: actions/download-artifact@v8 - 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 }} - GH_REPO: ${{ github.repository }} - RELEASE_TAG: ${{ github.ref_name }} - RELEASE_TITLE_PREFIX: ${{ env.SBOM_DIFF_RISK_RELEASE_TITLE_PREFIX }} - run: | + uses: actions/download-artifact@v8 + 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 }} + GH_REPO: ${{ github.repository }} + 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) @@ -188,21 +188,21 @@ jobs: assets+=( "${checksum_manifest}" ) title="${RELEASE_TITLE_PREFIX} ${RELEASE_TAG}" - - if gh release view "${RELEASE_TAG}" --repo "${GH_REPO}" >/dev/null 2>&1; then - is_draft="$(gh release view "${RELEASE_TAG}" --repo "${GH_REPO}" --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}" \ - --repo "${GH_REPO}" \ - --draft \ - --verify-tag \ - --title "${title}" \ - --notes "Release assets for ${RELEASE_TAG}. See docs/release-provenance.md for provenance verification guidance." - fi - + + if gh release view "${RELEASE_TAG}" --repo "${GH_REPO}" >/dev/null 2>&1; then + is_draft="$(gh release view "${RELEASE_TAG}" --repo "${GH_REPO}" --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}" \ + --repo "${GH_REPO}" \ + --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[@]}" --repo "${GH_REPO}" - gh release edit "${RELEASE_TAG}" --repo "${GH_REPO}" --draft=false --title "${title}" + gh release edit "${RELEASE_TAG}" --repo "${GH_REPO}" --draft=false --title "${title}" diff --git a/tools/sbom-diff-and-risk/docs/pypi-production-publishing-decision.md b/tools/sbom-diff-and-risk/docs/pypi-production-publishing-decision.md index 38a4cd5..96baae5 100644 --- a/tools/sbom-diff-and-risk/docs/pypi-production-publishing-decision.md +++ b/tools/sbom-diff-and-risk/docs/pypi-production-publishing-decision.md @@ -1,9 +1,9 @@ -# Production PyPI publishing decision - -This page records the PR 5 production PyPI gate for `sbom-diff-and-risk`. - -## PR 5 decision - +# Production PyPI publishing decision + +This page records the PR 5 production PyPI gate for `sbom-diff-and-risk`. + +## PR 5 decision + Production PyPI publishing is **deferred, but conditionally allowed after the prerequisites below are complete**. In short: production PyPI is currently deferred. @@ -13,26 +13,26 @@ to production PyPI. The successful TestPyPI Trusted Publishing dry-run proves that the package metadata can render on TestPyPI and that the TestPyPI OIDC path can work, but it is not automatic proof that production PyPI publishing is ready. - -The production gate is intentionally conservative because: - -- the production PyPI project does not currently exist under the intended name + +The production gate is intentionally conservative because: + +- the production PyPI project does not currently exist under the intended name - the package metadata has moved beyond the TestPyPI dry-run version, but production PyPI publishing has not been enabled -- the first production upload should be a deliberate release version, not an old dry-run version -- the production PyPI pending publisher or trusted publisher has not been configured -- the production GitHub environment has not yet been confirmed - -## Package name and external state - -The production package name should be `sbom-diff-and-risk`. - -As checked on April 26, 2026: - -- `https://pypi.org/pypi/sbom-diff-and-risk/json` returned `404` -- `https://test.pypi.org/pypi/sbom-diff-and-risk/json` returned `200` -- TestPyPI reports `sbom-diff-and-risk` version `0.4.1` - +- the first production upload should be a deliberate release version, not an old dry-run version +- the production PyPI pending publisher or trusted publisher has not been configured +- the production GitHub environment has not yet been confirmed + +## Package name and external state + +The production package name should be `sbom-diff-and-risk`. + +As checked on April 26, 2026: + +- `https://pypi.org/pypi/sbom-diff-and-risk/json` returned `404` +- `https://test.pypi.org/pypi/sbom-diff-and-risk/json` returned `200` +- TestPyPI reports `sbom-diff-and-risk` version `0.4.1` + This means the intended production project name is not currently visible on production PyPI, while the TestPyPI dry-run project exists. Treat the production name as available for this decision, but re-check immediately before @@ -40,36 +40,36 @@ configuration because PyPI can reserve, prohibit, or receive new projects at any time. The first production upload should use a production PyPI pending publisher unless the project is created by a maintainer before the publishing workflow is enabled. - -## First production version - -Do not publish `0.4.1` to production PyPI casually. - + +## First production version + +Do not publish `0.4.1` to production PyPI casually. + The first production PyPI version should be an explicitly approved current or future GitHub release tag. Do not backfill an older release casually. - -For the first production upload: - -- the GitHub tag should be `v` + +For the first production upload: + +- the GitHub tag should be `v` - `tools/sbom-diff-and-risk/pyproject.toml` should declare the matching `` -- the GitHub release and release assets should be available for the same tag -- the production PyPI workflow should run from the matching tag ref -- the production PyPI upload should use the checked distributions from that workflow run - -## Production publisher identity - -Configure the production PyPI publisher to match this identity exactly: - -| Field | Value | -| --- | --- | -| PyPI project name | `sbom-diff-and-risk` | -| GitHub owner | `stacknil` | -| GitHub repository | `scientific-computing-toolkit` | -| Future workflow file path | `.github/workflows/sbom-diff-and-risk-pypi.yml` | -| Trusted Publisher workflow name field | `sbom-diff-and-risk-pypi.yml` | -| GitHub environment | `pypi` | - +- the GitHub release and release assets should be available for the same tag +- the production PyPI workflow should run from the matching tag ref +- the production PyPI upload should use the checked distributions from that workflow run + +## Production publisher identity + +Configure the production PyPI publisher to match this identity exactly: + +| Field | Value | +| --- | --- | +| PyPI project name | `sbom-diff-and-risk` | +| GitHub owner | `stacknil` | +| GitHub repository | `scientific-computing-toolkit` | +| Future workflow file path | `.github/workflows/sbom-diff-and-risk-pypi.yml` | +| Trusted Publisher workflow name field | `sbom-diff-and-risk-pypi.yml` | +| GitHub environment | `pypi` | + If production PyPI still has no project for this name, configure a pending publisher for a new project. If the project exists by the time production publishing is implemented, add the trusted publisher to the existing project @@ -77,9 +77,9 @@ instead. Do not create or document a PyPI API token for this workflow. Production upload should use Trusted Publishing / OIDC only. - -PyPI-side setup should use these paths: - + +PyPI-side setup should use these paths: + - for a new production project, create a pending publisher on production PyPI for project `sbom-diff-and-risk` with the owner, repository, workflow, and environment values above @@ -88,86 +88,86 @@ PyPI-side setup should use these paths: environment values - leave the environment field as `pypi`; if the PyPI publisher omits the environment, it will not match the future publish job identity -- do not add a PyPI API token, PyPI password, or GitHub publishing secret as a fallback - -## Prerequisites before enabling production publishing - -Before adding `.github/workflows/sbom-diff-and-risk-pypi.yml`, maintainers should complete all of these checks: - -- confirm the intended production package name still resolves as expected on production PyPI +- do not add a PyPI API token, PyPI password, or GitHub publishing secret as a fallback + +## Prerequisites before enabling production publishing + +Before adding `.github/workflows/sbom-diff-and-risk-pypi.yml`, maintainers should complete all of these checks: + +- confirm the intended production package name still resolves as expected on production PyPI - choose the first production version as an explicitly approved current or future release tag -- update `pyproject.toml` to that version -- create or verify the matching GitHub tag and release assets -- create the GitHub environment named `pypi` -- configure required reviewers or equivalent repository controls on the `pypi` environment -- create the PyPI pending publisher or existing-project trusted publisher with the exact identity above -- run the future workflow in no-publish mode first and confirm the publish job is skipped -- verify the checked distributions with `python -m twine check dist/*` - -## Future workflow shape - -PR 5 intentionally documents the future workflow shape without enabling it. - -The future production workflow should: - -- use `workflow_dispatch` only for the initial production publishing process -- require an explicit boolean input such as `publish_to_pypi` -- require a confirmation string such as `publish sbom-diff-and-risk to production PyPI` -- require an expected version input and assert that it matches `pyproject.toml` +- update `pyproject.toml` to that version +- create or verify the matching GitHub tag and release assets +- create the GitHub environment named `pypi` +- configure required reviewers or equivalent repository controls on the `pypi` environment +- create the PyPI pending publisher or existing-project trusted publisher with the exact identity above +- run the future workflow in no-publish mode first and confirm the publish job is skipped +- verify the checked distributions with `python -m twine check dist/*` + +## Future workflow shape + +PR 5 intentionally documents the future workflow shape without enabling it. + +The future production workflow should: + +- use `workflow_dispatch` only for the initial production publishing process +- require an explicit boolean input such as `publish_to_pypi` +- require a confirmation string such as `publish sbom-diff-and-risk to production PyPI` +- require an expected version input and assert that it matches `pyproject.toml` - require the run ref to be a version tag such as `refs/tags/v` -- build the wheel and source distribution once -- run `python -m twine check dist/*` -- upload the checked distributions as a workflow artifact -- publish only from a separate gated job that downloads that artifact -- use the GitHub environment `pypi` on the publish job -- grant `id-token: write` only to the publish job -- avoid production upload on ordinary push or pull request events - +- build the wheel and source distribution once +- run `python -m twine check dist/*` +- upload the checked distributions as a workflow artifact +- publish only from a separate gated job that downloads that artifact +- use the GitHub environment `pypi` on the publish job +- grant `id-token: write` only to the publish job +- avoid production upload on ordinary push or pull request events + The publish step should use `pypa/gh-action-pypi-publish@release/v1` without a `repository-url` override so it targets production PyPI. - -## Provenance boundaries - + +## Provenance boundaries + Production PyPI Trusted Publishing provenance, GitHub workflow artifact attestations, and GitHub Release asset verification answer related but different questions. - -PyPI Trusted Publishing provenance answers: - -- was this distribution uploaded to this PyPI project through the configured GitHub publisher identity? -- did the upload use the expected owner, repository, workflow file, and environment? - -GitHub workflow artifact attestations answer: - -- were these local wheel or source distribution bytes built by `.github/workflows/sbom-diff-and-risk-ci.yml`? -- do the downloaded files match the attested workflow subjects? - -GitHub Release verification answers: - -- does the GitHub Release record have a valid release attestation? -- does a downloaded release asset match an attested asset from an immutable release? - -Do not treat one provenance surface as a replacement for the others. A PyPI package can have valid Trusted Publishing provenance without proving that it is byte-for-byte identical to a GitHub Release asset. Consumers who need cross-surface verification should compare hashes between a PyPI download and the corresponding GitHub Release asset, then use the GitHub verification flows documented in `self-provenance.md` and `release-provenance.md`. - -## Consumer guidance after a future production release - -After production publishing is enabled in a later PR, consumers should: - -- install only the intended project name, `sbom-diff-and-risk` -- check that the PyPI version matches the expected GitHub release tag -- inspect PyPI's Trusted Publishing provenance for the expected publisher identity -- use GitHub artifact attestation verification for workflow-built files when downloading from GitHub -- use GitHub Release verification for immutable release assets when relying on GitHub Releases -- continue to treat TestPyPI as a dry-run environment only - -## PR 5 local verification - -PR 5 should remain a documentation and gate-design change. Local verification is still required to prove the existing package surface did not regress: - -```powershell -python -m build -python -m twine check dist/* -python -m pytest -git diff --check -``` + +PyPI Trusted Publishing provenance answers: + +- was this distribution uploaded to this PyPI project through the configured GitHub publisher identity? +- did the upload use the expected owner, repository, workflow file, and environment? + +GitHub workflow artifact attestations answer: + +- were these local wheel or source distribution bytes built by `.github/workflows/sbom-diff-and-risk-ci.yml`? +- do the downloaded files match the attested workflow subjects? + +GitHub Release verification answers: + +- does the GitHub Release record have a valid release attestation? +- does a downloaded release asset match an attested asset from an immutable release? + +Do not treat one provenance surface as a replacement for the others. A PyPI package can have valid Trusted Publishing provenance without proving that it is byte-for-byte identical to a GitHub Release asset. Consumers who need cross-surface verification should compare hashes between a PyPI download and the corresponding GitHub Release asset, then use the GitHub verification flows documented in `self-provenance.md` and `release-provenance.md`. + +## Consumer guidance after a future production release + +After production publishing is enabled in a later PR, consumers should: + +- install only the intended project name, `sbom-diff-and-risk` +- check that the PyPI version matches the expected GitHub release tag +- inspect PyPI's Trusted Publishing provenance for the expected publisher identity +- use GitHub artifact attestation verification for workflow-built files when downloading from GitHub +- use GitHub Release verification for immutable release assets when relying on GitHub Releases +- continue to treat TestPyPI as a dry-run environment only + +## PR 5 local verification + +PR 5 should remain a documentation and gate-design change. Local verification is still required to prove the existing package surface did not regress: + +```powershell +python -m build +python -m twine check dist/* +python -m pytest +git diff --check +``` 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 index 1f4c195..ed87aaf 100644 --- a/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md +++ b/tools/sbom-diff-and-risk/docs/pypi-trusted-publishing-readiness.md @@ -1,155 +1,155 @@ -# PyPI Trusted Publishing readiness - -This page documents the PR 4 TestPyPI / Trusted Publishing dry-run path for `sbom-diff-and-risk`. - +# PyPI Trusted Publishing readiness + +This page documents the PR 4 TestPyPI / Trusted Publishing dry-run path for `sbom-diff-and-risk`. + The PR 5 production PyPI decision gate is documented separately in [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md). - -The repository now has a safe GitHub Actions path that always builds and checks the Python distributions, and can publish those already-checked distributions to TestPyPI only when a maintainer explicitly enables the manual upload input. It does not publish to production PyPI. - -Official references: - -- [PyPI Trusted Publishers](https://docs.pypi.org/trusted-publishers/) -- [Adding a Trusted Publisher to an existing PyPI project](https://docs.pypi.org/trusted-publishers/adding-a-publisher/) -- [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/) -- [Configuring OpenID Connect in PyPI](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi) -- [PyPA gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) - -## PR 4 decision - -Use a TestPyPI-first readiness workflow, but do not treat TestPyPI success as automatic production PyPI readiness. - -Current outcome for this PR: - -- **Trusted Publishing readiness and TestPyPI dry-run completed** after the external TestPyPI publisher was configured and a maintainer manually enabled upload -- **No production PyPI publishing** + +The repository now has a safe GitHub Actions path that always builds and checks the Python distributions, and can publish those already-checked distributions to TestPyPI only when a maintainer explicitly enables the manual upload input. It does not publish to production PyPI. + +Official references: + +- [PyPI Trusted Publishers](https://docs.pypi.org/trusted-publishers/) +- [Adding a Trusted Publisher to an existing PyPI project](https://docs.pypi.org/trusted-publishers/adding-a-publisher/) +- [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/) +- [Configuring OpenID Connect in PyPI](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-pypi) +- [PyPA gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) + +## PR 4 decision + +Use a TestPyPI-first readiness workflow, but do not treat TestPyPI success as automatic production PyPI readiness. + +Current outcome for this PR: + +- **Trusted Publishing readiness and TestPyPI dry-run completed** after the external TestPyPI publisher was configured and a maintainer manually enabled upload +- **No production PyPI publishing** - **Production PyPI deferred** to the decision gate in [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md) - -The workflow file is `.github/workflows/sbom-diff-and-risk-testpypi.yml`. - -It has two separate jobs: - -- `build-and-check` builds the wheel and source distribution, runs `twine check`, and uploads the checked files as a workflow artifact -- `publish-testpypi` downloads that artifact and publishes to TestPyPI with OIDC only when `workflow_dispatch` input `publish_to_testpypi` is set to `true` - -The upload job does not rebuild the package. - -## Current package and project status - -As checked on April 26, 2026: - -- `https://pypi.org/pypi/sbom-diff-and-risk/json` returned `404` -- `https://test.pypi.org/pypi/sbom-diff-and-risk/json` returned `200` -- TestPyPI reports `sbom-diff-and-risk` version `0.4.1` - -That means the production PyPI project is not currently visible under `sbom-diff-and-risk`, while the TestPyPI dry-run project exists. For production PyPI, use the PR 5 decision gate before adding any production workflow or publisher configuration. - -## Workflow identity - -Configure the TestPyPI publisher to match this GitHub workflow identity exactly: - -| Field | Value | -| --- | --- | -| Package/project name | `sbom-diff-and-risk` | -| GitHub owner | `stacknil` | -| GitHub repository | `scientific-computing-toolkit` | -| Workflow file in repository | `.github/workflows/sbom-diff-and-risk-testpypi.yml` | -| Trusted Publisher workflow name field | `sbom-diff-and-risk-testpypi.yml` | -| GitHub environment | `testpypi` | - -The workflow uses `environment: testpypi` for the upload job, so the TestPyPI publisher must also include `testpypi` as the environment name. If the publisher is configured without an environment, the OIDC identity will not match this workflow. - -## What this PR validates - -Locally and in GitHub Actions, this PR validates: - -- package metadata still points at `PYPI_DESCRIPTION.md` as the PyPI-facing long description -- the package can build a wheel and source distribution -- the built distributions pass `twine check` -- the GitHub workflow separates build/check from upload -- the TestPyPI upload job uses OIDC-compatible permissions with `id-token: write` -- no PyPI token secret is required or documented -- production PyPI upload is absent - -This PR does not validate: - -- that production PyPI has a project, pending publisher, or trusted publisher -- that production PyPI publishing should happen for version `0.4.1` -- that a TestPyPI upload is sufficient proof of production PyPI readiness - -## TestPyPI setup used for upload - -The completed TestPyPI dry-run required these external steps. Use them again only if the TestPyPI publisher must be recreated. - -1. In GitHub, create or verify the repository environment named `testpypi`. -2. In TestPyPI, create a pending publisher for the new `sbom-diff-and-risk` project. -3. Use the identity values from [Workflow identity](#workflow-identity). -4. Do not add a PyPI API token or GitHub secret for publishing. -5. Run the workflow manually and set `publish_to_testpypi` to `true`. - -If the pending publisher or trusted publisher is missing, or any identity field differs, the upload job should fail instead of silently falling back to a token or pretending the dry-run succeeded. - -## Local validation - -From `tools/sbom-diff-and-risk`: - -```powershell -python -m pip install --upgrade build twine -python -m build -$files = (Get-ChildItem dist -File).FullName -python -m twine check $files -``` - -What this proves: - -- the local package can be built -- the built distributions have valid metadata and long-description rendering according to Twine - -What this does not prove: - -- the GitHub OIDC identity matches TestPyPI -- the TestPyPI pending publisher exists -- the upload job can mint a TestPyPI publishing token - -## GitHub Actions validation - -Without uploading anything: - -1. Open **Actions**. -2. Run **sbom-diff-and-risk-testpypi** with `publish_to_testpypi` left as `false`. -3. Confirm `build-and-check` succeeds. -4. Confirm the run uploads `sbom-diff-and-risk-testpypi-dist`. -5. Confirm `publish-testpypi` is skipped. - -With TestPyPI pending publisher configured: - -1. Open **Actions**. -2. Run **sbom-diff-and-risk-testpypi** with `publish_to_testpypi` set to `true`. -3. Confirm `build-and-check` succeeds before upload. -4. Confirm `publish-testpypi` downloads `sbom-diff-and-risk-testpypi-dist`. -5. Confirm `publish-testpypi` uses OIDC and publishes to `https://test.pypi.org/legacy/`. -6. Open `https://test.pypi.org/project/sbom-diff-and-risk/` and confirm the uploaded version appears. - -After those steps pass, maintainers can describe the result as **TestPyPI dry-run completed**. - -## Production PyPI boundary - -Production PyPI remains intentionally separate from the TestPyPI dry-run. - -Do not add a production PyPI publish job to the TestPyPI workflow. Do not configure production PyPI Trusted Publishing from the TestPyPI readiness process. - -PR 5 decides: - -- the first production PyPI version -- whether to use a pending publisher or an existing-project trusted publisher -- the production workflow file identity -- the GitHub environment name for production, if any -- how PyPI distribution provenance should be documented alongside GitHub artifact and release verification - + +The workflow file is `.github/workflows/sbom-diff-and-risk-testpypi.yml`. + +It has two separate jobs: + +- `build-and-check` builds the wheel and source distribution, runs `twine check`, and uploads the checked files as a workflow artifact +- `publish-testpypi` downloads that artifact and publishes to TestPyPI with OIDC only when `workflow_dispatch` input `publish_to_testpypi` is set to `true` + +The upload job does not rebuild the package. + +## Current package and project status + +As checked on April 26, 2026: + +- `https://pypi.org/pypi/sbom-diff-and-risk/json` returned `404` +- `https://test.pypi.org/pypi/sbom-diff-and-risk/json` returned `200` +- TestPyPI reports `sbom-diff-and-risk` version `0.4.1` + +That means the production PyPI project is not currently visible under `sbom-diff-and-risk`, while the TestPyPI dry-run project exists. For production PyPI, use the PR 5 decision gate before adding any production workflow or publisher configuration. + +## Workflow identity + +Configure the TestPyPI publisher to match this GitHub workflow identity exactly: + +| Field | Value | +| --- | --- | +| Package/project name | `sbom-diff-and-risk` | +| GitHub owner | `stacknil` | +| GitHub repository | `scientific-computing-toolkit` | +| Workflow file in repository | `.github/workflows/sbom-diff-and-risk-testpypi.yml` | +| Trusted Publisher workflow name field | `sbom-diff-and-risk-testpypi.yml` | +| GitHub environment | `testpypi` | + +The workflow uses `environment: testpypi` for the upload job, so the TestPyPI publisher must also include `testpypi` as the environment name. If the publisher is configured without an environment, the OIDC identity will not match this workflow. + +## What this PR validates + +Locally and in GitHub Actions, this PR validates: + +- package metadata still points at `PYPI_DESCRIPTION.md` as the PyPI-facing long description +- the package can build a wheel and source distribution +- the built distributions pass `twine check` +- the GitHub workflow separates build/check from upload +- the TestPyPI upload job uses OIDC-compatible permissions with `id-token: write` +- no PyPI token secret is required or documented +- production PyPI upload is absent + +This PR does not validate: + +- that production PyPI has a project, pending publisher, or trusted publisher +- that production PyPI publishing should happen for version `0.4.1` +- that a TestPyPI upload is sufficient proof of production PyPI readiness + +## TestPyPI setup used for upload + +The completed TestPyPI dry-run required these external steps. Use them again only if the TestPyPI publisher must be recreated. + +1. In GitHub, create or verify the repository environment named `testpypi`. +2. In TestPyPI, create a pending publisher for the new `sbom-diff-and-risk` project. +3. Use the identity values from [Workflow identity](#workflow-identity). +4. Do not add a PyPI API token or GitHub secret for publishing. +5. Run the workflow manually and set `publish_to_testpypi` to `true`. + +If the pending publisher or trusted publisher is missing, or any identity field differs, the upload job should fail instead of silently falling back to a token or pretending the dry-run succeeded. + +## Local validation + +From `tools/sbom-diff-and-risk`: + +```powershell +python -m pip install --upgrade build twine +python -m build +$files = (Get-ChildItem dist -File).FullName +python -m twine check $files +``` + +What this proves: + +- the local package can be built +- the built distributions have valid metadata and long-description rendering according to Twine + +What this does not prove: + +- the GitHub OIDC identity matches TestPyPI +- the TestPyPI pending publisher exists +- the upload job can mint a TestPyPI publishing token + +## GitHub Actions validation + +Without uploading anything: + +1. Open **Actions**. +2. Run **sbom-diff-and-risk-testpypi** with `publish_to_testpypi` left as `false`. +3. Confirm `build-and-check` succeeds. +4. Confirm the run uploads `sbom-diff-and-risk-testpypi-dist`. +5. Confirm `publish-testpypi` is skipped. + +With TestPyPI pending publisher configured: + +1. Open **Actions**. +2. Run **sbom-diff-and-risk-testpypi** with `publish_to_testpypi` set to `true`. +3. Confirm `build-and-check` succeeds before upload. +4. Confirm `publish-testpypi` downloads `sbom-diff-and-risk-testpypi-dist`. +5. Confirm `publish-testpypi` uses OIDC and publishes to `https://test.pypi.org/legacy/`. +6. Open `https://test.pypi.org/project/sbom-diff-and-risk/` and confirm the uploaded version appears. + +After those steps pass, maintainers can describe the result as **TestPyPI dry-run completed**. + +## Production PyPI boundary + +Production PyPI remains intentionally separate from the TestPyPI dry-run. + +Do not add a production PyPI publish job to the TestPyPI workflow. Do not configure production PyPI Trusted Publishing from the TestPyPI readiness process. + +PR 5 decides: + +- the first production PyPI version +- whether to use a pending publisher or an existing-project trusted publisher +- the production workflow file identity +- the GitHub environment name for production, if any +- how PyPI distribution provenance should be documented alongside GitHub artifact and release verification + See [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md) for the current production gate. - -## Current decision - -PR 4 established the TestPyPI readiness workflow and the manual dry-run path. After the external TestPyPI publisher was configured and a maintainer ran the manual upload, the dry-run completed for version `0.4.1`. - -Production PyPI remains deferred behind the PR 5 gate. + +## Current decision + +PR 4 established the TestPyPI readiness workflow and the manual dry-run path. After the external TestPyPI publisher was configured and a maintainer ran the manual upload, the dry-run completed for version `0.4.1`. + +Production PyPI remains deferred behind the PR 5 gate. diff --git a/tools/sbom-diff-and-risk/docs/release-provenance.md b/tools/sbom-diff-and-risk/docs/release-provenance.md index 2824d8d..5097678 100644 --- a/tools/sbom-diff-and-risk/docs/release-provenance.md +++ b/tools/sbom-diff-and-risk/docs/release-provenance.md @@ -1,20 +1,20 @@ -# Release provenance and release asset verification - +# 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 - + +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](verification.md). Release assets produced by the updated workflow also include a deterministic SHA256 checksum manifest named `sbom-diff-and-risk-SHA256SUMS.txt`. The manifest is written with filenames sorted in a stable order. It is not a separate provenance system; it is a local byte-integrity check that helps reviewers confirm downloaded wheel and source distribution files match the hashes published with the same GitHub Release. - -## What the release workflow now does - -For version tags matching `v*`, the `sbom-diff-and-risk-ci` workflow: - + +## 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. generates `dist/sbom-diff-and-risk-SHA256SUMS.txt` with SHA256 hashes for the built `.whl` and `.tar.gz` 3. uploads the distributions and checksum manifest as the workflow artifact `sbom-diff-and-risk-dist` @@ -25,27 +25,27 @@ For version tags matching `v*`, the `sbom-diff-and-risk-ci` workflow: 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. The workflow artifact attestation subject remains the built wheel and source distribution. The checksum manifest verifies hashes for those files, but the manifest itself is not presented as a replacement for artifact attestation. - -## 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. - + +## 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](self-provenance.md). - -## Manual verification for a release - + +## Manual verification for a release + Use this path after a successful version-tag run produced by the updated workflow. - -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: - + +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 --repo stacknil/scientific-computing-toolkit --json isImmutable,assets,url ``` @@ -68,18 +68,18 @@ gh release verify --repo stacknil/scientific-computing-toolkit gh release verify-asset path/to/sbom_diff_and_risk--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](self-provenance.md). - -You can inspect structured output as JSON: - -```bash + +You can inspect structured output as JSON: + +```bash gh release verify \ --repo stacknil/scientific-computing-toolkit \ --format json -``` - -```bash +``` + +```bash gh release verify-asset path/to/sbom_diff_and_risk-.tar.gz \ --repo stacknil/scientific-computing-toolkit \ --format json @@ -120,11 +120,11 @@ Get-Content .\sbom-diff-and-risk-SHA256SUMS.txt | ForEach-Object { ``` A passing checksum check means the local downloaded wheel and source distribution match the hashes in the release manifest. It does not by itself prove who built or uploaded the artifacts, and the manifest itself is not the attested subject. Pair checksum verification with workflow artifact attestation or immutable release verification when you need provenance. - -## Important boundary notes - + +## 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. - `sbom-diff-and-risk-SHA256SUMS.txt` checks local file integrity against the release manifest. It does not replace provenance verification. - 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. +- A successful release verification does not replace the workflow-artifact attestation story; it complements it. - This repository now has a separate TestPyPI Trusted Publishing readiness workflow, but production PyPI publishing remains deferred. For the production decision gate, publisher identity, future workflow shape, and provenance boundary, see [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md). diff --git a/tools/sbom-diff-and-risk/docs/reviewer-brief.md b/tools/sbom-diff-and-risk/docs/reviewer-brief.md index 2a61207..2a72fc5 100644 --- a/tools/sbom-diff-and-risk/docs/reviewer-brief.md +++ b/tools/sbom-diff-and-risk/docs/reviewer-brief.md @@ -1,5 +1,5 @@ -# Reviewer brief - +# Reviewer brief + ## Summary `sbom-diff-and-risk` is a local CLI for comparing two SBOMs or dependency manifests and producing deterministic review artifacts: JSON, Markdown, and SARIF. It is built for conservative supply-chain review, not for vulnerability scanning or package reputation scoring. @@ -8,22 +8,22 @@ Current released version: `v0.9.0`. For the shortest ordered review route, use [reviewer-path.md](reviewer-path.md). - -## Why this project matters - -Dependency review often needs evidence that is stable enough for code review, CI, and audit trails. This project turns dependency changes into repeatable findings, optional policy outcomes, and machine-readable security output while keeping default analysis offline and file-based. - -## Capability map - -| Area | What exists | -| --- | --- | -| Deterministic local analysis | Compares CycloneDX, SPDX, `requirements.txt`, and conservative `pyproject.toml` inputs without hidden network access by default. | + +## Why this project matters + +Dependency review often needs evidence that is stable enough for code review, CI, and audit trails. This project turns dependency changes into repeatable findings, optional policy outcomes, and machine-readable security output while keeping default analysis offline and file-based. + +## Capability map + +| Area | What exists | +| --- | --- | +| Deterministic local analysis | Compares CycloneDX, SPDX, `requirements.txt`, and conservative `pyproject.toml` inputs without hidden network access by default. | | Reviewer output | Produces JSON and Markdown reports for dependency diffs, heuristic risk buckets, and policy outcomes. It can also write compact `summary.json` and policy-only `policy.json` sidecars for CI consumers. | -| Security tooling output | Emits a conservative SARIF subset for selected high-signal findings and explicit policy violations. | -| Provenance-aware reporting | Optionally records PyPI provenance and integrity evidence when `--enrich-pypi` is enabled. | -| Scorecard signals | Optionally records OpenSSF Scorecard evidence when `--enrich-scorecard` is enabled and a repository mapping is explicit enough. | -| Policy support | Supports local YAML policies for thresholds, source allowlists, provenance requirements, and Scorecard thresholds. | - +| Security tooling output | Emits a conservative SARIF subset for selected high-signal findings and explicit policy violations. | +| Provenance-aware reporting | Optionally records PyPI provenance and integrity evidence when `--enrich-pypi` is enabled. | +| Scorecard signals | Optionally records OpenSSF Scorecard evidence when `--enrich-scorecard` is enabled and a repository mapping is explicit enough. | +| Policy support | Supports local YAML policies for thresholds, source allowlists, provenance requirements, and Scorecard thresholds. | + ## Evidence map | Question | Evidence path | @@ -36,10 +36,10 @@ Dependency review often needs evidence that is stable enough for code review, CI | Are default runs offline? | CLI docs, tests for no-enrichment behavior, and explicit enrichment flags. | | Can code scanning consume the output? | `docs/github-code-scanning.md` and `examples/sample-sarif.sarif`. | | Can the tool's own artifacts be verified? | `docs/self-provenance.md` for workflow artifact attestations. | -| Can GitHub release assets be verified? | `docs/release-provenance.md` for release asset verification. | -| Did Trusted Publishing get exercised safely? | `docs/pypi-trusted-publishing-readiness.md` documents the completed TestPyPI dry-run. | -| Is production PyPI enabled? | `docs/pypi-production-publishing-decision.md` documents that production PyPI is intentionally deferred. | - +| Can GitHub release assets be verified? | `docs/release-provenance.md` for release asset verification. | +| Did Trusted Publishing get exercised safely? | `docs/pypi-trusted-publishing-readiness.md` documents the completed TestPyPI dry-run. | +| Is production PyPI enabled? | `docs/pypi-production-publishing-decision.md` documents that production PyPI is intentionally deferred. | + ## Quick verification path 1. Use [reviewer-path.md](reviewer-path.md) as the ordered route. @@ -50,18 +50,18 @@ Dependency review often needs evidence that is stable enough for code review, CI 6. Use `docs/self-provenance.md` when verifying workflow-built wheel or source distribution artifacts. 7. Use `docs/release-provenance.md` when verifying GitHub Release assets. 8. Use `docs/pypi-production-publishing-decision.md` before making any production PyPI publishing decision. - -## What this project intentionally does not claim - -- It does not claim to be a vulnerability scanner. -- It does not resolve CVEs, advisories, or exploitability. -- It does not score package reputation or declare packages safe. -- It does not perform hidden network enrichment. -- It does not treat TestPyPI success as production PyPI readiness. -- It does not currently publish to production PyPI. -- It does not treat PyPI Trusted Publishing provenance, GitHub workflow artifact attestations, and GitHub Release asset verification as interchangeable evidence. - -## Resume / application wording - -Built `sbom-diff-and-risk`, a deterministic SBOM and dependency diff CLI that produces JSON, Markdown, and SARIF review artifacts; supports local policy checks and optional provenance/Scorecard evidence; and documents a release verification story covering GitHub artifact attestations, GitHub Release assets, TestPyPI Trusted Publishing validation, and intentionally deferred production PyPI publishing. - + +## What this project intentionally does not claim + +- It does not claim to be a vulnerability scanner. +- It does not resolve CVEs, advisories, or exploitability. +- It does not score package reputation or declare packages safe. +- It does not perform hidden network enrichment. +- It does not treat TestPyPI success as production PyPI readiness. +- It does not currently publish to production PyPI. +- It does not treat PyPI Trusted Publishing provenance, GitHub workflow artifact attestations, and GitHub Release asset verification as interchangeable evidence. + +## Resume / application wording + +Built `sbom-diff-and-risk`, a deterministic SBOM and dependency diff CLI that produces JSON, Markdown, and SARIF review artifacts; supports local policy checks and optional provenance/Scorecard evidence; and documents a release verification story covering GitHub artifact attestations, GitHub Release assets, TestPyPI Trusted Publishing validation, and intentionally deferred production PyPI publishing. + diff --git a/tools/sbom-diff-and-risk/docs/self-provenance.md b/tools/sbom-diff-and-risk/docs/self-provenance.md index ee8223b..f6753ff 100644 --- a/tools/sbom-diff-and-risk/docs/self-provenance.md +++ b/tools/sbom-diff-and-risk/docs/self-provenance.md @@ -1,117 +1,117 @@ -# Self-provenance and artifact attestations - -`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. - +# Self-provenance and artifact attestations + +`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](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`: - -- the wheel: `dist/sbom_diff_and_risk--py3-none-any.whl` -- the source distribution: `dist/sbom_diff_and_risk-.tar.gz` - -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. - -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. - + +## 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`: + +- the wheel: `dist/sbom_diff_and_risk--py3-none-any.whl` +- the source distribution: `dist/sbom_diff_and_risk-.tar.gz` + +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. + +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 production PyPI Trusted Publishing provenance. The separate TestPyPI readiness workflow is a pre-production validation path and is documented in [pypi-trusted-publishing-readiness.md](pypi-trusted-publishing-readiness.md). The production PyPI decision gate is documented in [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md). 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 - -The attestation is generated in `.github/workflows/sbom-diff-and-risk-ci.yml` by the `build-and-attest` job in the `sbom-diff-and-risk-ci` workflow. - -That job runs only for trusted non-PR events in this repository: - -- `push` -- `workflow_dispatch` - -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 production 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: - - open **Actions** - - in the left sidebar, under **Management**, open **Attestations** - - search for `sbom_diff_and_risk-` or filter by recent creation date - -On the **Attestations** page, the relevant subjects are the wheel and sdist filenames, not the workflow artifact bundle name. On the workflow run page, the main visible bundle name is still `sbom-diff-and-risk-dist`. - -## Manual verification for one workflow 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: - - `sbom_diff_and_risk--py3-none-any.whl` - - `sbom_diff_and_risk-.tar.gz` -6. Verify one of the files with the GitHub CLI: - -```bash -gh attestation verify path/to/sbom_diff_and_risk--py3-none-any.whl \ - --repo OWNER/scientific-computing-toolkit \ - --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml -``` - -You can verify the source distribution the same way: - -```bash -gh attestation verify path/to/sbom_diff_and_risk-.tar.gz \ - --repo OWNER/scientific-computing-toolkit \ - --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml -``` - -If you want more inspection detail during review, ask the CLI for structured output: - -```bash -gh attestation verify path/to/sbom_diff_and_risk--py3-none-any.whl \ - --repo OWNER/scientific-computing-toolkit \ - --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml \ - --format json -``` - -A successful verification confirms that: - -- the downloaded file matches an attested subject -- the attestation was linked to `OWNER/scientific-computing-toolkit` -- the attestation was signed by `.github/workflows/sbom-diff-and-risk-ci.yml` - -## Release-consumer note - -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 - + +## Workflow and permissions + +The attestation is generated in `.github/workflows/sbom-diff-and-risk-ci.yml` by the `build-and-attest` job in the `sbom-diff-and-risk-ci` workflow. + +That job runs only for trusted non-PR events in this repository: + +- `push` +- `workflow_dispatch` + +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 production 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: + - open **Actions** + - in the left sidebar, under **Management**, open **Attestations** + - search for `sbom_diff_and_risk-` or filter by recent creation date + +On the **Attestations** page, the relevant subjects are the wheel and sdist filenames, not the workflow artifact bundle name. On the workflow run page, the main visible bundle name is still `sbom-diff-and-risk-dist`. + +## Manual verification for one workflow 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: + - `sbom_diff_and_risk--py3-none-any.whl` + - `sbom_diff_and_risk-.tar.gz` +6. Verify one of the files with the GitHub CLI: + +```bash +gh attestation verify path/to/sbom_diff_and_risk--py3-none-any.whl \ + --repo OWNER/scientific-computing-toolkit \ + --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml +``` + +You can verify the source distribution the same way: + +```bash +gh attestation verify path/to/sbom_diff_and_risk-.tar.gz \ + --repo OWNER/scientific-computing-toolkit \ + --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml +``` + +If you want more inspection detail during review, ask the CLI for structured output: + +```bash +gh attestation verify path/to/sbom_diff_and_risk--py3-none-any.whl \ + --repo OWNER/scientific-computing-toolkit \ + --signer-workflow OWNER/scientific-computing-toolkit/.github/workflows/sbom-diff-and-risk-ci.yml \ + --format json +``` + +A successful verification confirms that: + +- the downloaded file matches an attested subject +- the attestation was linked to `OWNER/scientific-computing-toolkit` +- the attestation was signed by `.github/workflows/sbom-diff-and-risk-ci.yml` + +## Release-consumer note + +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](release-provenance.md) for the release-specific consumer flow. - + Future production PyPI Trusted Publishing provenance will be a third, separate surface. It will answer whether a PyPI distribution was uploaded through the configured GitHub publisher identity, not whether the file is byte-identical to a GitHub workflow artifact or release asset. See [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md) for that boundary. - -## How this complements the tool's own analysis - -Self-provenance and dependency analysis solve different problems: - -- artifact attestations help consumers verify where `sbom-diff-and-risk` itself was built -- `sbom-diff-and-risk` helps users review and gate third-party dependency changes in their own projects - -These attestations strengthen trust in the tool's own distributable artifacts, but they do not replace the tool's analysis of external SBOM inputs, policy decisions, or trust-signal reporting for third-party packages. + +## How this complements the tool's own analysis + +Self-provenance and dependency analysis solve different problems: + +- artifact attestations help consumers verify where `sbom-diff-and-risk` itself was built +- `sbom-diff-and-risk` helps users review and gate third-party dependency changes in their own projects + +These attestations strengthen trust in the tool's own distributable artifacts, but they do not replace the tool's analysis of external SBOM inputs, policy decisions, or trust-signal reporting for third-party packages. diff --git a/tools/sbom-diff-and-risk/docs/verification.md b/tools/sbom-diff-and-risk/docs/verification.md index a903597..8dc2d31 100644 --- a/tools/sbom-diff-and-risk/docs/verification.md +++ b/tools/sbom-diff-and-risk/docs/verification.md @@ -1,46 +1,46 @@ -# 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: - +# 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](self-provenance.md) if you want to verify the workflow-built wheel or source distribution with `gh attestation verify` - [release-provenance.md](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](pypi-trusted-publishing-readiness.md) if you want to know whether this package is ready for PyPI Trusted Publishing - -Current boundaries: - + +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 assets produced by the updated workflow include `sbom-diff-and-risk-SHA256SUMS.txt` for local SHA256 verification of the wheel and source distribution - release verification depends on immutable releases being enabled for the repository -- the TestPyPI readiness workflow is `sbom-diff-and-risk-testpypi` -- the TestPyPI Trusted Publishing dry-run has completed for version `0.4.1` +- the TestPyPI readiness workflow is `sbom-diff-and-risk-testpypi` +- the TestPyPI Trusted Publishing dry-run has completed for version `0.4.1` - production PyPI publishing remains deferred behind the gate in [pypi-production-publishing-decision.md](pypi-production-publishing-decision.md) - -### 2. "How do I use `sbom-diff-and-risk` to analyze third-party dependency provenance?" - -Use the dependency-analysis docs in the README: - + +### 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](../README.md#dependency-provenance-analysis-opt-in) - [Dependency provenance reporting](../README.md#dependency-provenance-reporting) - [Enforcement mode](../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 - + +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` - Check downloaded release bytes: use the checksum manifest instructions in `release-provenance.md` - Decide whether production PyPI publishing is ready: use `pypi-production-publishing-decision.md` -- Analyze dependencies with the tool: use the README's dependency provenance sections +- Analyze dependencies with the tool: use the README's dependency provenance sections diff --git a/tools/sbom-diff-and-risk/src/sbom_diff_risk/__init__.py b/tools/sbom-diff-and-risk/src/sbom_diff_risk/__init__.py index f8bfe67..347cd8d 100644 --- a/tools/sbom-diff-and-risk/src/sbom_diff_risk/__init__.py +++ b/tools/sbom-diff-and-risk/src/sbom_diff_risk/__init__.py @@ -1,5 +1,5 @@ -"""sbom-diff-and-risk package.""" - -__all__ = ["__version__"] - +"""sbom-diff-and-risk package.""" + +__all__ = ["__version__"] + __version__ = "0.9.0"