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:
yaml
- name: Install Cosign uses: sigstore/cosign-installer@11086d9f32b178aa24e93c2b86eba3ef4b16b68a # v3.8.1 - name: Sign image run: | 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:
bash
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):
yaml
- name: Generate SBOM uses: anchore/sbom-action@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.20.0 with: image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} format: spdx-json output-file: sbom.spdx.json - name: Attest SBOM run: | 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:
bash
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:
yaml
- name: Scan image for vulnerabilities uses: aquasecurity/trivy-action@18f2135c0b15d26b3a4c2efded75e06b6f0e4884 # v0.30.0 with: image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} format: table exit-code: '1' ignore-unfixed: true vuln-type: os,library severity: CRITICAL,HIGH - Explain
ignore-unfixed: true— skip CVEs with no fix available (reduces noise without reducing security) - For Grype (alternative), show:
yaml
- name: Scan with Grype uses: anchore/scan-action@e1165082ffb1fe366ebaf02d8526e7c4989ea9d2 # v7.4.0 with: image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} fail-build: true severity-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.
Finding where unsigned images already run: Kubescape reports them as control C-0237 "Check if signature exists" (/platform-skills:kubescape-operator, or kubescape scan control C-0237 on a cluster). Use that list to size the rollout before switching the policy to Deny.
Steps:
- Ask: keyless (Sigstore) or key-based signing?
- For keyless, generate:
yaml
apiVersion: policies.kyverno.io/v1 kind: ImageValidatingPolicy metadata: name: require-signed-images spec: validationActions: [Audit] # switch to [Deny] after all images are signing matchConstraints: 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:
yaml
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:
yaml
jobs: build: runs-on: ubuntu-latest outputs: digest: ${{ steps.build.outputs.digest }} permissions: contents: read packages: write steps: - name: Build and push image id: build uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0 with: push: true tags: ghcr.io/<org>/<image>:${{ github.sha }} provenance: needs: build permissions: actions: read id-token: write packages: write uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@5a775b367a56d5bd118a224a811bba288150a563 # v2.0.0 with: image: ghcr.io/<org>/<image> digest: ${{ needs.build.outputs.digest }} registry-username: ${{ github.actor }} secrets: registry-password: ${{ secrets.GITHUB_TOKEN }} - Show provenance verification:
bash
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
Signing and SBOMs cover what the pipeline produces. They say nothing about the pipeline itself — an unpinned uses: or a pull_request_target checkout of untrusted code compromises the build before any artifact exists. To audit the workflows that run this supply chain, including unpinned-uses hash-pin policy enforcement, use /platform-skills:zizmor. They also say nothing about whether a credential leaked into the repo that produces this artifact in the first place — for that, live-validate and revoke with /platform-skills:kingfisher.
After completing this task, log errors and learnings via /platform-skills:self-improve log.


