Supply Chain Command
Secure the software supply chain — from the build pipeline to running containers.
Interactive Wizard (fires when no arguments are provided)
When invoked with no arguments, ask before proceeding:
Q1 — Mode?
What do you need?
1. audit — review an existing CI/CD pipeline for supply chain security gaps
2. sign — set up keyless image signing with Cosign (Sigstore/Rekor, no key management)
3. sbom — generate and attest an SBOM with Syft
4. scan — add a CVE vulnerability gate with Trivy or Grype
5. enforce — write a Kyverno policy to block unsigned images at admission
6. slsa — generate a SLSA Level 2 provenance workflow
Enter 1–6 or mode name:
Q2 — Context (after mode selected, one at a time):
- audit:
Paste your GitHub Actions workflow file(s) or describe your current CI/CD pipeline: - sign:
Which container registry? (ECR / GHCR / Docker Hub / other): - sbom:
Which image and registry? (e.g. ghcr.io/org/image): - scan:
Which scanner preference? Trivy (recommended) or Grype — or no preference: - enforce:
Which registry or image prefix should the policy cover? (e.g. ghcr.io/myorg/*): - slsa:
Which registry and repo? (e.g. ghcr.io/org/image from github.com/org/repo):
Then proceed into the relevant mode below.
Mode: audit
Review an existing CI/CD pipeline and cluster admission configuration for supply chain security gaps.
Steps:
- Ask for or read: the GitHub Actions workflow file(s), any existing image scanning steps, and any Kyverno/OPA admission policies
- Classify gaps by severity:
- Critical: images pushed without signing, no CVE gate, unsigned images admitted to cluster
- High: SBOM not generated or not attested, severity gate only on CRITICAL (misses HIGH)
- Medium: action versions pinned to tag not SHA, no SLSA provenance
- Output a prioritised gap list:
[CRITICAL] No image signing — any image can be admitted to the cluster[CRITICAL] No CVE severity gate — vulnerable images pass CI[HIGH] No SBOM attestation — cannot audit what is running[MEDIUM] Action versions pinned to tag, not SHA
- Recommend the fix order: sign → scan-gate → SBOM → enforce → SLSA
Reference: references/supply-chain.md → Gap classification, Fix order
Mode: sign
Set up keyless image signing with Cosign using Sigstore/Rekor (no key management required).
Steps:
- Confirm the image registry (ECR, GHCR, Docker Hub) and CI platform (GitHub Actions assumed)
- Generate the signing workflow step:
- name: Install Cosignuses: sigstore/cosign-installer@11086d9f32b178aa24e93c2b86eba3ef4b16b68a # v3.8.1- name: Sign imagerun: |cosign sign --yes \${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
- Explain the keyless flow: GitHub Actions OIDC token → Fulcio CA → Rekor transparency log
- Show verification command:
cosign verify \--certificate-identity-regexp="https://github.com/<org>/<repo>/.github/workflows/.*" \--certificate-oidc-issuer="https://token.actions.githubusercontent.com" \ghcr.io/<org>/<image>@<digest>
- Flag: always sign the digest (
@sha256:…), never the tag — tags are mutable
Key rules:
- Never store signing keys in CI secrets — use keyless only
- Always sign the digest, not the tag
- Pin
cosign-installerto a full SHA, e.g.:sigstore/cosign-installer@11086d9f32b178aa24e93c2b86eba3ef4b16b68a
Reference: references/supply-chain.md → Keyless signing, Rekor transparency log
Mode: sbom
Generate a Software Bill of Materials with Syft and attest it as an OCI artifact alongside the image.
Steps:
- Add the SBOM generation step after build and push (digest is only available after registry push):
- name: Generate SBOMuses: anchore/sbom-action@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.20.0with:image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}format: spdx-jsonoutput-file: sbom.spdx.json- name: Attest SBOMrun: |cosign attest --yes \--predicate sbom.spdx.json \--type spdxjson \${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}
- Show how to retrieve the SBOM attestation:
cosign download attestation \--predicate-type https://spdx.dev/Document \ghcr.io/<org>/<image>@<digest> | jq '.payload | @base64d | fromjson'
- Note: use
spdx-jsonformat for broadest tooling compatibility;cyclonedx-jsonis an alternative
Reference: references/supply-chain.md → SBOM formats, Syft, Attestation
Mode: scan
Add a CVE vulnerability scan with a configurable severity gate that fails the build.
Steps:
- Add Trivy scan step:
- name: Scan image for vulnerabilitiesuses: aquasecurity/trivy-action@18f2135c0b15d26b3a4c2efded75e06b6f0e4884 # v0.30.0with:image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}format: tableexit-code: '1'ignore-unfixed: truevuln-type: os,libraryseverity: CRITICAL,HIGH
- Explain
ignore-unfixed: true— skip CVEs with no fix available (reduces noise without reducing security) - For Grype (alternative), show:
- name: Scan with Grypeuses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0with:image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}fail-build: trueseverity-cutoff: high
- Recommend Trivy for new setups (CNCF, single binary, SBOM support); Grype for teams already using Syft
Reference: references/supply-chain.md → Trivy vs Grype, Severity gates
Mode: enforce
Generate a Kyverno ImageValidatingPolicy that blocks unsigned or unverified images at admission time.
Steps:
- Ask: keyless (Sigstore) or key-based signing?
- For keyless, generate:
apiVersion: policies.kyverno.io/v1kind: ImageValidatingPolicymetadata:name: require-signed-imagesspec:validationActions: [Audit] # switch to [Deny] after all images are signingmatchConstraints:resourceRules:- apiGroups: [""]apiVersions: ["v1"]operations: ["CREATE", "UPDATE"]resources: ["pods"]matchImageReferences:- glob: "ghcr.io/<org>/*"validations:- expression: >images.containers.map(image, verifyImageSignatures(image, [{"keyless": {"url": "https://fulcio.sigstore.dev","rekor": {"url": "https://rekor.sigstore.dev"},"identities": [{"issuer": "https://token.actions.githubusercontent.com","subjectRegExp": "https://github.com/<org>/.*"}]}}])).all(e, e > 0)message: "Image must be signed via Sigstore keyless signing from GitHub Actions"
- Show audit-first deployment:
spec:validationActions: [Audit] # start here, switch to [Deny] after validation
- Cross-reference:
/platform-skills:kyvernofor full ImageValidatingPolicy guidance
Reference: references/supply-chain.md → Kyverno enforcement, references/kyverno.md → ImageValidatingPolicy
Mode: slsa
Generate a GitHub Actions workflow for SLSA Level 2 provenance using slsa-github-generator.
Steps:
- Explain what SLSA L2 gives: signed provenance linking the artifact to the specific build inputs (source commit, workflow, runner)
- Generate the workflow using the official reusable workflow:
jobs:build:runs-on: ubuntu-latestoutputs:digest: ${{ steps.build.outputs.digest }}permissions:contents: readpackages: writesteps:- name: Build and push imageid: builduses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0with:push: truetags: ghcr.io/<org>/<image>:${{ github.sha }}provenance:needs: buildpermissions:actions: readid-token: writepackages: writeuses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@5a775b367a56d5bd118a224a811bba288150a563 # v2.0.0with:image: ghcr.io/<org>/<image>digest: ${{ needs.build.outputs.digest }}registry-username: ${{ github.actor }}secrets:registry-password: ${{ secrets.GITHUB_TOKEN }}
- Show provenance verification:
slsa-verifier verify-image \ghcr.io/<org>/<image>@<digest> \--source-uri github.com/<org>/<repo> \--source-branch main
- Note:
generator_container_slsa3.ymlproduces L2 provenance by default; L3 requires hermetic builds not available on standard GitHub-hosted runners
Reference: references/supply-chain.md → SLSA levels, slsa-github-generator
After completing this task, log errors and learnings via /platform-skills:self-improve log.