security: harden supply chain and release provenance - #98
Conversation
Reviewer's GuideAdds a comprehensive supply-chain security and release provenance framework: all GitHub Actions and Docker base images are digest-pinned, new security workflows run Bandit/pip-audit/zizmor/Trivy with a strict, time-bounded exception policy, release tags are provenance-validated and produce SBOMs plus attestations for packages and container images, and documentation/checklists are updated to describe and enforce these processes. Sequence diagram for Docker release image gating and provenancesequenceDiagram
actor Operator
participant GitHubActions as GitHub_Actions
participant DockerGate as Docker_workflow_gate_job
participant ArtifactStore as Actions_artifacts
participant DockerPublish as Docker_workflow_publish_job
participant GHCR as GHCR_registry
participant Trivy as Trivy_scanner
participant Attest as actions_attest
Operator->>GitHubActions: push tag vX.Y.Z
GitHubActions->>DockerGate: start gate job
DockerGate->>DockerGate: Validate release tag provenance
DockerGate->>DockerGate: scripts/security_exceptions.py validate
DockerGate->>DockerGate: docker/build-push-action (build image archive)
DockerGate->>Trivy: aquasecurity/trivy-action (scan archive)
Trivy-->>DockerGate: fail on HIGH,CRITICAL vulns
DockerGate->>ArtifactStore: upload-artifact scanned-release-image-${GITHUB_SHA}
GitHubActions->>DockerPublish: start publish job (needs gate)
DockerPublish->>ArtifactStore: download-artifact scanned-release-image-${GITHUB_SHA}
DockerPublish->>DockerPublish: docker load exact scanned image
DockerPublish->>GHCR: docker/login-action
DockerPublish->>GHCR: docker tag && docker push tags
DockerPublish->>DockerPublish: compute digest via docker buildx imagetools inspect
DockerPublish->>Attest: anchore/sbom-action (generate container-sbom.spdx.json)
DockerPublish->>Attest: actions/attest (image provenance)
DockerPublish->>Attest: actions/attest (image SBOM)
Attest-->>GHCR: push OCI attestations
Sequence diagram for release evidence SBOMs and package attestationssequenceDiagram
actor Operator
participant GitHubActions as GitHub_Actions
participant Gate as Release_evidence_gate_job
participant Packages as Release_evidence_packages_job
participant PipAudit as pip_audit
participant Sbom as anchore_sbom_action
participant Attest as actions_attest
participant ArtifactStore as Actions_artifacts
Operator->>GitHubActions: push tag vX.Y.Z
GitHubActions->>Gate: start gate job
Gate->>Gate: Validate release tag provenance
Gate->>Gate: install pip-audit==2.10.1
Gate->>Gate: scripts/security_exceptions.py validate
Gate->>Gate: scripts/security_exceptions.py ids pip-audit
Gate->>PipAudit: python -m pip_audit . --strict
PipAudit-->>Gate: fail on any vulnerable dependency
GitHubActions->>Packages: start packages job (needs gate)
Packages->>Packages: Revalidate release tag provenance
Packages->>Packages: python -m build (wheel, sdist)
Packages->>Sbom: anchore/sbom-action (wheel.spdx.json)
Packages->>Sbom: anchore/sbom-action (sdist.spdx.json)
Packages->>Attest: actions/attest (package provenance)
Packages->>Attest: actions/attest (wheel SBOM)
Packages->>Attest: actions/attest (sdist SBOM)
Packages->>ArtifactStore: upload-artifact python-release-evidence-${GITHUB_REF_NAME}
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The Dockerfile now pins an Alpine base image but only installs
httpx==0.28.1instead of the project itself (pip install .), which will leave the container without the application code installed and likely break the runtime image; consider restoring an explicit install of the project or a clear rationale for this change. - In the Docker
publishjob, the image "digest" is derived by hashingdocker buildx imagetools inspectoutput rather than using the registry's actual content digest, which means the recorded digest and attestations will not match the pushed image; it would be safer to parse the real OCI digest fromimagetools/docker inspectinstead of hashing the inspect output.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The Dockerfile now pins an Alpine base image but only installs `httpx==0.28.1` instead of the project itself (`pip install .`), which will leave the container without the application code installed and likely break the runtime image; consider restoring an explicit install of the project or a clear rationale for this change.
- In the Docker `publish` job, the image "digest" is derived by hashing `docker buildx imagetools inspect` output rather than using the registry's actual content digest, which means the recorded digest and attestations will not match the pushed image; it would be safer to parse the real OCI digest from `imagetools`/`docker inspect` instead of hashing the inspect output.
## Individual Comments
### Comment 1
<location path=".github/workflows/docker.yml" line_range="19-27" />
<code_context>
- - name: Log in to GHCR
- uses: docker/login-action@v4
+ - name: Validate release tag provenance
+ shell: bash
+ run: |
+ set -euo pipefail
+ package_version=$(python -c \
+ 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
+ test "$GITHUB_REF_NAME" = "v$package_version"
+ git fetch --no-tags origin main
+ git merge-base --is-ancestor "$GITHUB_SHA" origin/main
+
+ - name: Validate security exceptions
</code_context>
<issue_to_address>
**issue (bug_risk):** `python` invocation may fail on runners where only `python3` is available or lacks `tomllib`
This step depends on a pre-existing `python` with `tomllib`, which isn’t guaranteed on GitHub-hosted runners (some only have `python3`, and system Python may be <3.11). That can cause this check to fail due to the runner image rather than the code.
Consider either running this after `actions/setup-python` so a known 3.11+ version is available, or explicitly using `python3` and installing a `tomllib` backport when on <3.11, so the provenance check is stable across runner images.
</issue_to_address>
### Comment 2
<location path=".github/workflows/release-evidence.yml" line_range="22-30" />
<code_context>
- - name: Log in to GHCR
- uses: docker/login-action@v4
+ - name: Validate release tag provenance
+ shell: bash
+ run: |
+ set -euo pipefail
+ package_version=$(python -c \
+ 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
+ test "$GITHUB_REF_NAME" = "v$package_version"
+ git fetch --no-tags origin main
+ git merge-base --is-ancestor "$GITHUB_SHA" origin/main
+
+ - name: Validate security exceptions
</code_context>
<issue_to_address>
**issue (bug_risk):** Same `python` availability issue in release-evidence provenance gate
This job invokes `python` with `tomllib` before `actions/setup-python`, so it may fail on runners where `python` is missing or too old to include `tomllib`, causing flaky provenance checks.
To align with the security/docker provenance logic and improve reliability, either:
- Run `actions/setup-python` first and use that interpreter, or
- Call `python3` with an enforced minimum version / explicit `tomllib` handling.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Closes #72.
Summary
Validation
Summary by Sourcery
Harden supply chain security and release provenance for packages and container images.
New Features:
Enhancements:
Tests: