Skip to content

Commit 5dca0c5

Browse files
ob-aiongyrospectrevineethsai7
authored
feat(release): attest build provenance and SBOM for release artifacts (#143)
* feat(release): attest build provenance and SBOM for release artifacts SLSA provenance over dist/* and release assets via actions/attest-build-provenance; CycloneDX SBOM generated from the frozen uv export through a locked sbom dependency group and bound to the distributions via actions/attest-sbom. Proposed in #111. * fix(llm): allow Vertex AI to use ambient Application Default Credentials ProviderConfig.validate() required a truthy credential for every provider except Bedrock and Ollama, and the only credential source it checked for Vertex was GOOGLE_APPLICATION_CREDENTIALS. This blocked ambient auth via a GCE/Cloud Run attached service account or Workload Identity, even though LiteLLM/google-auth already fall back to it automatically when no explicit credential is passed -- the same pattern already supported for Bedrock's IAM role. Excludes is_vertex from the check, mirroring the Bedrock/Ollama precedent, and documents the fallback. * Bumps to resolve security findings * fix(llm): don't leak Vertex ADC credential path into GEMINI_API_KEY - _resolve_api_key() now returns None for Vertex instead of the GOOGLE_APPLICATION_CREDENTIALS path, since vertex_ai/gemini-* models set both is_vertex and is_gemini, which was causing the file path to be written into GEMINI_API_KEY. - Regenerated configuration-reference.md via generate_reference_docs.py instead of hand-editing, and updated the underlying descriptions so the doc doesn't drift on next regeneration. Addresses CodeRabbit review feedbak on #144. * revert unrelated cli-command-reference.md regeneration --------- Co-authored-by: gyrospectre <7224858+gyrospectre@users.noreply.github.com> Co-authored-by: Vineeth Sai Narajala <vnarajal@cisco.com>
1 parent 0b01738 commit 5dca0c5

4 files changed

Lines changed: 350 additions & 21 deletions

File tree

.github/workflows/release.yml

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
permissions:
2525
id-token: write
2626
contents: write # needed to create/update the GitHub release assets
27+
attestations: write # needed to store build provenance and SBOM attestations
2728
steps:
2829
- name: Checkout code
2930
uses: actions/checkout@v4
@@ -53,6 +54,38 @@ jobs:
5354
--no-emit-project \
5455
--output-file release-assets/requirements.txt
5556
57+
# SBOM is generated from the frozen export above so all release artifacts
58+
# describe one locked tree. The project version is dynamic (VCS-derived),
59+
# so it is stamped from the workflow input.
60+
- name: Generate CycloneDX SBOM
61+
env:
62+
VERSION: ${{ inputs.version }}
63+
run: |
64+
uv sync --frozen --only-group sbom
65+
uv run --no-sync cyclonedx-py requirements \
66+
release-assets/requirements.txt \
67+
--pyproject pyproject.toml \
68+
--output-reproducible \
69+
--output-file release-assets/sbom.cdx.json
70+
jq --arg v "$VERSION" \
71+
'.metadata.component.version = $v
72+
| .metadata.component.purl = "pkg:pypi/cisco-ai-skill-scanner@\($v)"' \
73+
release-assets/sbom.cdx.json > sbom.tmp
74+
mv sbom.tmp release-assets/sbom.cdx.json
75+
76+
- name: Attest build provenance
77+
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
78+
with:
79+
subject-path: |
80+
dist/*
81+
release-assets/*
82+
83+
- name: Attest SBOM
84+
uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
85+
with:
86+
subject-path: dist/*
87+
sbom-path: release-assets/sbom.cdx.json
88+
5689
- name: Check GitHub release state
5790
id: release-state
5891
env:
@@ -66,7 +99,7 @@ jobs:
6699
67100
if [[ "$is_draft" == "false" ]]; then
68101
echo "published=true" >> "$GITHUB_OUTPUT"
69-
echo "::warning::GitHub release $VERSION is already published. Immutable releases cannot accept new assets, so requirements.txt upload will be skipped."
102+
echo "::warning::GitHub release $VERSION is already published. Immutable releases cannot accept new assets, so release asset upload will be skipped."
70103
else
71104
echo "published=false" >> "$GITHUB_OUTPUT"
72105
fi
@@ -76,12 +109,14 @@ jobs:
76109
echo "published=false" >> "$GITHUB_OUTPUT"
77110
fi
78111
79-
- name: Attach requirements.txt to draft GitHub release
112+
- name: Attach requirements.txt and SBOM to draft GitHub release
80113
if: steps.release-state.outputs.published != 'true'
81114
uses: softprops/action-gh-release@v2
82115
with:
83116
tag_name: ${{ inputs.version }}
84-
files: release-assets/requirements.txt
117+
files: |
118+
release-assets/requirements.txt
119+
release-assets/sbom.cdx.json
85120
fail_on_unmatched_files: true
86121
draft: true
87122

SECURITY.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,18 @@ following steps:
6565
who install with `pip` can reproduce the exact same dependency tree we ship
6666
and tested against, with hash verification.
6767
- **PyPI Trusted Publishers.** Releases are uploaded to PyPI via OIDC; no
68-
long-lived API tokens are stored in the repository or in CI secrets.
68+
long-lived API tokens are stored in the repository or in CI secrets. Uploads
69+
carry [PEP 740](https://peps.python.org/pep-0740/) attestations generated
70+
during publish.
71+
- **SLSA build provenance.** Every release run attests the wheel, sdist, and
72+
release assets with
73+
[`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance).
74+
Verify any artifact with
75+
`gh attestation verify <artifact> --repo cisco-ai-defense/skill-scanner`.
76+
- **CycloneDX SBOM.** Each GitHub release includes an `sbom.cdx.json` generated
77+
from the same frozen export as `requirements.txt` and bound to the
78+
distributions with
79+
[`actions/attest-sbom`](https://github.com/actions/attest-sbom).
6980
- **Loose abstract constraints in `pyproject.toml`.** Library consumers can
7081
resolve transitive security patches forward without forced cascades. See
7182
[`CONTRIBUTING.md` § Dependency Policy](/CONTRIBUTING.md#dependency-policy)

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ dev = [
130130
"liccheck==0.9.2",
131131
"pip-audit==2.10.0",
132132
]
133+
sbom = [
134+
"cyclonedx-bom==7.3.0",
135+
]
133136

134137
[project.urls]
135138
Homepage = "https://github.com/cisco-ai-defense/skill-scanner"

0 commit comments

Comments
 (0)