Skip to content

Commit 954fc5d

Browse files
Varashiclaude
andcommitted
chore: supply-chain + CI polish
- release: drop buildx-embedded SBOM; anchore is sole source and the only input to the cosign SBOM attestation - release: cosign-sign image digest once (was signing per-tag, all tags resolve to same digest) - release: cosign-sign Helm chart OCI artifact against digest captured from `helm push` - ci: add `ct lint --all` alongside `helm lint` / `helm template` - Dockerfile: pip `--disable-pip-version-check` (hadolint DL3042) - README: Verifying a release section — image sig, SBOM attestation, `gh attestation verify`, chart sig, `helm pull --verify` - CHANGELOG: populate [Unreleased] Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 5fc95ac commit 954fc5d

5 files changed

Lines changed: 90 additions & 9 deletions

File tree

.github/workflows/ci.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ jobs:
3939
runs-on: ubuntu-latest
4040
steps:
4141
- uses: actions/checkout@v4
42+
with:
43+
fetch-depth: 0
4244
- uses: azure/setup-helm@v4
4345
with:
4446
version: v3.16.3
@@ -53,6 +55,14 @@ jobs:
5355
helm template ci chart/ \
5456
--set vcenter.existingSecret=my-eso-secret \
5557
--set vcenter.caBundle.configMapName=vcenter-ca > /dev/null
58+
- uses: actions/setup-python@v5
59+
with:
60+
python-version: "3.13"
61+
- uses: helm/chart-testing-action@v2
62+
- name: ct lint
63+
# Catches SemVer/maintainer/icon/README drift that plain `helm lint`
64+
# misses. `--all` since this repo has a single chart in chart/.
65+
run: ct lint --all --chart-dirs . --validate-maintainers=false
5666

5767
image:
5868
name: image / buildx smoke

.github/workflows/release.yaml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,10 @@ jobs:
8282
tags: ${{ steps.meta.outputs.tags }}
8383
labels: ${{ steps.meta.outputs.labels }}
8484
provenance: true
85-
sbom: true
85+
# SBOM is produced downstream by anchore/sbom-action and attached
86+
# as a cosign attestation, so skip the buildx-embedded SBOM to
87+
# avoid two different SBOMs against the same digest.
88+
sbom: false
8689
cache-from: type=gha
8790
cache-to: type=gha,mode=max
8891

@@ -92,11 +95,10 @@ jobs:
9295
- name: Cosign keyless sign
9396
env:
9497
DIGEST: ${{ steps.build.outputs.digest }}
95-
TAGS: ${{ steps.meta.outputs.tags }}
96-
run: |
97-
for tag in $TAGS; do
98-
cosign sign --yes "${tag}@${DIGEST}"
99-
done
98+
IMAGE: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
99+
# All tags point at the same digest; sign the digest once rather
100+
# than re-signing it per tag.
101+
run: cosign sign --yes "${IMAGE}@${DIGEST}"
100102

101103
- name: Generate SBOM (SPDX)
102104
uses: anchore/sbom-action@v0
@@ -142,10 +144,24 @@ jobs:
142144
--username ${{ github.actor }} --password-stdin
143145
144146
- name: Push Helm chart (OCI)
147+
id: chart_push
145148
run: |
146149
version="${{ steps.ver.outputs.version }}"
150+
# helm push prints "Digest: sha256:..." to stderr; tee to capture.
147151
helm push "gpu-node-vsphere-maintenance-controller-${version}.tgz" \
148-
"oci://${{ env.CHART_REPO }}"
152+
"oci://${{ env.CHART_REPO }}" 2>&1 | tee push.log
153+
digest=$(awk '/^Digest: /{print $2}' push.log)
154+
if [ -z "$digest" ]; then
155+
echo "Failed to capture chart digest" >&2
156+
exit 1
157+
fi
158+
echo "digest=${digest}" >> "$GITHUB_OUTPUT"
159+
160+
- name: Cosign keyless sign (chart)
161+
env:
162+
DIGEST: ${{ steps.chart_push.outputs.digest }}
163+
CHART_REF: ${{ env.CHART_REPO }}/gpu-node-vsphere-maintenance-controller
164+
run: cosign sign --yes "${CHART_REF}@${DIGEST}"
149165

150166
- name: Create GitHub Release
151167
uses: softprops/action-gh-release@v2

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,29 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
77

88
## [Unreleased]
99

10+
### Added
11+
- README "Verifying a release" section with cosign verify, cosign
12+
verify-attestation, `gh attestation verify`, and `helm pull --verify`
13+
snippets for the published image and chart.
14+
- Release workflow now cosign-keyless-signs the published Helm chart OCI
15+
artifact as well as the image, against the digest returned by
16+
`helm push`.
17+
- CI `chart` job runs `helm/chart-testing` `ct lint` in addition to
18+
`helm lint` and `helm template`, catching SemVer and metadata drift
19+
that plain `helm lint` misses.
20+
21+
### Changed
22+
- Release workflow signs the image digest once rather than once per tag —
23+
all tags resolve to the same digest, so per-tag signing only recorded
24+
duplicate signatures against the same subject.
25+
- Release workflow disables the buildx-embedded SBOM (`sbom: false` on
26+
`docker/build-push-action`). `anchore/sbom-action` remains the single
27+
source of the SPDX SBOM and the only input to the cosign SBOM
28+
attestation, so image consumers no longer see two SBOMs referencing
29+
the same digest.
30+
- Dockerfile `pip install` now passes `--disable-pip-version-check` to
31+
pre-empt hadolint `DL3042` and trim startup noise.
32+
1033
## [0.4.1] — 2026-04-21
1134

1235
### Added

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ LABEL org.opencontainers.image.licenses="MIT"
88

99
WORKDIR /app
1010

11-
RUN pip install --no-cache-dir pyVmomi==8.0.3.0.1 kubernetes==31.0.0
11+
RUN pip install --no-cache-dir --disable-pip-version-check \
12+
pyVmomi==8.0.3.0.1 kubernetes==31.0.0
1213

1314
COPY controller.py .
1415

README.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,44 @@ The `release.yaml` GitHub Actions workflow then:
411411
section of [`CHANGELOG.md`](./CHANGELOG.md) and attaches the SBOM and
412412
the packaged chart `.tgz`.
413413

414-
Verify a release image signature locally:
414+
### Verifying a release
415+
416+
Every release is cosign-keyless-signed (GitHub OIDC), carries a SLSA build
417+
provenance attestation pushed to the registry, and has the SPDX SBOM
418+
attached as a cosign attestation. Verify any of these before deploying:
415419

416420
```bash
421+
# 1. Image signature.
417422
cosign verify \
418423
--certificate-identity-regexp 'https://github\.com/Varashi/gpu-node-vsphere-maintenance-controller/\.github/workflows/release\.yaml@refs/tags/v.*' \
419424
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
420425
ghcr.io/varashi/gpu-node-vsphere-maintenance-controller:<tag>
426+
427+
# 2. SBOM attestation (SPDX).
428+
cosign verify-attestation --type spdxjson \
429+
--certificate-identity-regexp 'https://github\.com/Varashi/gpu-node-vsphere-maintenance-controller/\.github/workflows/release\.yaml@refs/tags/v.*' \
430+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
431+
ghcr.io/varashi/gpu-node-vsphere-maintenance-controller:<tag>
432+
433+
# 3. SLSA build provenance (GitHub Attestations).
434+
gh attestation verify \
435+
oci://ghcr.io/varashi/gpu-node-vsphere-maintenance-controller:<tag> \
436+
--owner Varashi
437+
```
438+
439+
Verify the Helm chart the same way — the release workflow signs chart
440+
digests too:
441+
442+
```bash
443+
cosign verify \
444+
--certificate-identity-regexp 'https://github\.com/Varashi/gpu-node-vsphere-maintenance-controller/\.github/workflows/release\.yaml@refs/tags/v.*' \
445+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
446+
ghcr.io/varashi/charts/gpu-node-vsphere-maintenance-controller:<tag>
447+
448+
# Or pull + verify in one shot (requires helm 3.8+ experimental OCI).
449+
helm pull \
450+
oci://ghcr.io/varashi/charts/gpu-node-vsphere-maintenance-controller \
451+
--version <tag> --verify
421452
```
422453

423454
## Version history

0 commit comments

Comments
 (0)