agentleFS
lukemurraynzlukemurraynz/hve-agent-skills/skills/container-supply-chain/SKILL.md

container-supply-chain

Skill2 starsChanged 3 months agoMITView on GitHub

Production implementation guide for new container image supply-chain security: OCI image signing, digest-first builds, GitHub artifact attestations, Cosign keyless signing, optional Notation/ACR signing, Rekor audit lookup, SBOM generation and attestation, vulnerability scanning, waiver governance, SLSA Build track evidence, deployment admission gates, and artifact-leakage prevention. USE FOR: implementing build-sign-attest-scan-verify pipelines, hardening GHCR or ACR container release workflows, verifying image provenance, configuring Kubernetes/AKS deployment gates, preventing Docker/package artifact leakage, and producing auditable supply-chain records.

  • Reads credentials

The file

Show its rules and text

We split this skill into the rules it gives an agent

50 rules. About 0 are common, 39 are distinctive, and 11 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈39

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 11

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill to design or implement a secure container release path from source through deployment.

    line 26
  2. Distinctive:

    Before writing any Cosign/Notation CLI command, GitHub Actions attestation step, SBOM tool invocation, vulnerability scanner config, or …

    line 47
  3. Distinctive:

    Do not write Cosign commands assuming v1 keyless flow if v2 is installed.

    line 57
  4. Very specific:

    Do not pin GitHub actions by tag (@v1) in supply-chain workflows.

    line 58
  5. Very specific:

    Do not write SBOM attestation predicate types from memory.

    line 59
  6. Very specific:

    Do not assume SLSA Build Level 3 attestation is automatic.

    line 60
  7. Distinctive:

    Do not write image references without digest pins in production manifests.

    line 61
  8. Very specific:

    If you cannot run cosign version, check installed action SHAs, or verify Rekor identity, do not produce production-shaped supply-chain …

    line 73
  9. Distinctive:

    Do not produce speculative supply-chain CI/CD config under blocked verification.

    line 82
  10. Distinctive:

    Use this skill for:

    line 86
  11. Distinctive:

    Do not use this skill as the primary guide for:

    line 99
  12. Distinctive:

    Stop and request human review when any condition is true:

    line 121
  13. Distinctive:

    Verify signature and provenance using an expected identity policy.

    line 150
  14. Distinctive:

    Write an immutable audit record containing digest, signer, builder, SBOM hash, scan result, waivers, and verification evidence.

    line 153
  15. Distinctive:

    Use these recent Microsoft Security blog write-ups as worked examples when explaining why each link in the chain above matters:

    line 157
  16. Distinctive:

    When reviewing a supply-chain design with platform teams, cite these incidents as evidence that the verify and enforce steps are not …

    line 165
  17. Distinctive:

    Use Buildx/build-push-action for attestation-capable builds.

    line 171
  18. Very specific:

    Use --push for registry-backed attestations.

    line 183
  19. Very specific:

    Treat mode=max as sensitive metadata.

    line 184
  20. Distinctive:

    Use BuildKit secret mounts for private feeds and authenticated build steps.

    line 185
  21. Very specific:

    When a policy or audit workflow depends on attestations, use dedicated verification tooling such as gh attestation verify, cosign …

    line 200
  22. Distinctive:

    Use Syft for audit-grade SBOM files because it supports multiple ecosystems and output formats.

    line 206
  23. Distinctive:

    Prefer a signed SBOM attestation when consumers or compliance tooling need to verify that the SBOM belongs to the released image.

    line 221
  24. Distinctive:

    Use Grype when the pipeline already produces an SBOM and audit evidence should be tied to that SBOM.

    line 242
  25. Distinctive:

    Every waiver must include owner, reason, expiry, and compensating control in the PR or adjacent metadata.

    line 270
  26. Distinctive:

    Do not create non-expiring waivers.

    line 271
  27. Distinctive:

    Do not waive critical remote-code-execution findings in runtime packages without security approval.

    line 272
  28. Distinctive:

    Prefer base image refresh or dependency upgrade over waiver creation.

    line 273
  29. Distinctive:

    Use Trivy when scanning the pushed image directly or producing input for Copacetic remediation.

    line 277
  30. Distinctive:

    Use keyless signing for GitHub-hosted release workflows unless the organization requires Notation or an offline/key-managed signing process.

    line 294
  31. Very specific:

    Use id-token: write only in the job that needs OIDC.

    line 305
  32. Distinctive:

    Do not use broad signing jobs that can sign arbitrary artifacts from untrusted inputs.

    line 306
  33. Distinctive:

    Keep signing after the vulnerability gate unless policy requires signing all build outputs with a separate release status.

    line 307
  34. Distinctive:

    Use regex only when the workflow identity varies, and constrain it as tightly as possible:

    line 319
  35. Very specific:

    Do not use repository-wide patterns such as https://github.com/org/repo/.* for production deployment gates.

    line 327
  36. Distinctive:

    Use ACR repositories and image references by digest for production.

    line 390
  37. Distinctive:

    Keep tag immutability and lifecycle rules in registry policy where available.

    line 391
  38. Distinctive:

    Verify base images before build when using curated internal base images.

    line 392
  39. Distinctive:

    If using Notation with Key Vault, define certificate lifecycle, rotation, expiry, signer RBAC, and emergency revocation.

    line 394
  40. Distinctive:

    Use key-based signing only when OIDC/keyless signing is unavailable or policy requires managed signing keys.

    line 400
  41. Distinctive:

    Never store a private signing key as a repository secret without formal risk acceptance.

    line 417
  42. Distinctive:

    Prefer one of these patterns:

    line 458
  43. Distinctive:

    If policy requires environment-specific signing, add environment claims or split release signing into a protected environment job.

    line 659
  44. Very specific:

    Keep id-token: write limited to the attestation and signing jobs.

    line 660
  45. Very specific:

    Do not use Docker build args for secrets.

    line 661
  46. Distinctive:

    Do not claim a SLSA Build level from tool presence alone.

    line 667
  47. Distinctive:

    Do not hard-code a seven-year default unless the organization has approved it.

    line 714
  48. Distinctive:

    Use immutable storage such as Azure Immutable Blob Storage or equivalent WORM/Object Lock storage.

    line 715
  49. Distinctive:

    Do not sign off until the image is traceable by immutable digest, verification happens after generation, and the trust policy names the …

    line 755
  50. Distinctive:

    Before finalizing a PR that uses this skill, confirm:

    line 759

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Container Supply Chain - Production Implementation Guide

Use this skill to design or implement a secure container release path from source through deployment. Optimize for new projects: do not preserve legacy Docker Content Trust, mutable production tags, unsigned images, or CI-only trust checks unless the task explicitly requires migration support.

For policy rules, pair this skill with your repository's Docker supply-chain and GitHub Actions security standards (workflow hardening, OIDC federation, action pinning, artifact hygiene).

Use When

Should triggerShould NOT triggerNearby skill collision
Designing or hardening a build-sign-attest-scan-verify pipeline for OCI imagesThe task is only about runtime debugging, container startup, or incident triage after deploymentUse container-operations for runtime/container failure diagnosis
Implementing image signing, provenance, SBOM, attestation verification, or deployment trust gatesThe task is only about Dockerfile authoring with no supply-chain trust or artifact-leakage scopeUse Docker/container authoring guidance unless release trust is in scope
Producing audit-ready release evidence, waiver governance, or admission-policy checks for container artifactsThe request is only about registry cleanup or lifecycle retention unrelated to signatures/attestationsUse ACR lifecycle/registry skills when trust metadata is not the main concern

Anti-Hallucination Rule (MANDATORY before writing supply-chain CI/CD or signing config)

Container supply-chain tooling spans Cosign (v1 vs v2 with different CLI flag shape - cosign sign --key vs cosign sign --identity-token), Notation v1 (Microsoft-aligned, separate plugin model), Rekor (transparency log lookup), GitHub artifact attestations (actions/attest-build-provenance, actions/attest-sbom), SBOM tools (syft, cdxgen, trivy sbom), vulnerability scanners (trivy, grype), and registry-side signing (ACR az acr task for Notation, GHCR via OIDC). Cosign v1 → v2 was a breaking CLI change (keyless flow rewritten). Tool flag changes between minors silently produce unsigned images that still push successfully.

Before writing any Cosign/Notation CLI command, GitHub Actions attestation step, SBOM tool invocation, vulnerability scanner config, or Rekor lookup, ground each identifier using one of these methods:

  1. Tool version: cosign version, notation version, syft version, trivy version, grype version. Each tool has independent breaking-change cadences.
  2. Cosign keyless vs key-based: cosign sign --yes (keyless, OIDC-based, requires identity provider config) vs cosign sign --key <keyref> - the verification step (cosign verify) also has different flags.
  3. GitHub action versions: pin actions/attest-build-provenance@<SHA> and actions/attest-sbom@<SHA> to immutable SHAs; tag-pinning floats and breaks supply chain.
  4. SBOM format: SPDX vs CycloneDX; syft <image> -o spdx-json vs -o cyclonedx-json. Downstream tools accept one or the other; mixing silently produces unparsed SBOM.
  5. Rekor entry lookup: cosign verify --certificate-identity requires the exact OIDC identity used at signing. Wrong identity silently fails verification.

Forbidden shortcuts:

  • Do not write Cosign commands assuming v1 keyless flow if v2 is installed; the CLI rewrote keyless.
  • Do not pin GitHub actions by tag (@v1) in supply-chain workflows; pin by SHA (@abc123...).
  • Do not write SBOM attestation predicate types from memory; https://spdx.dev/Document vs https://cyclonedx.org/bom are different predicate types.
  • Do not assume SLSA Build Level 3 attestation is automatic; requires actions/attest-build-provenance with hardened runner and pinned action SHAs.
  • Do not write image references without digest pins in production manifests; tag-only references break signature verification.

Known asymmetry traps (illustrative, verify each):

  • Cosign v1 keyless: cosign sign --identity-token <token> <image>; v2 keyless: cosign sign --yes <image> with OIDC issuer auto-detection.
  • cosign verify --certificate-oidc-issuer https://token.actions.githubusercontent.com --certificate-identity-regexp "^https://github.com/<org>/<repo>/" <image> - wrong issuer URL silently fails verification.
  • Notation plugin model: AKV plugin (notation-azure-kv) vs PKI plugin; ACR signing requires AKV plugin and managed identity on ACR.
  • SBOM attestation: cosign attest --predicate sbom.spdx.json --type spdxjson <image> vs --type cyclonedx. Predicate type must match content format.
  • Rekor entry inclusion proof: cosign verify retrieves and verifies inclusion in Sigstore's Rekor by default; private Rekor instances require --rekor-url flag.

Safe degraded output when verification is blocked

If you cannot run cosign version, check installed action SHAs, or verify Rekor identity, do not produce production-shaped supply-chain CI/CD from memory. Cosign v1 → v2 CLI changes and SBOM predicate-type mismatches are dominant silent failures.

Instead, return:

  1. A labelled skeleton with [VERIFY] markers on Cosign CLI flags, action SHA pins, SBOM predicate types, scanner severity flags, Rekor identity regexes, image digest references.
  2. Verification commands: tool version commands, GitHub action SHA pinning procedure, Sigstore Rekor query URL, OIDC issuer verification command.
  3. Identifier guess list grouped by failure mode (image pushed unsigned / signature verification silently fails / SBOM not parsed downstream / scanner severity filter wrong / Rekor identity regex matches nothing).
  4. A design-level artifact offer: sign-attest-scan-verify pipeline diagram, action SHA pin inventory, SBOM format decision, signing identity model (keyless OIDC vs key-based), Rekor lookup strategy, AKS/Container Apps admission gate plan, waiver governance plan.

Do not produce speculative supply-chain CI/CD config under blocked verification. The whole point of supply-chain security is precise identifier matching; fabrication defeats the purpose.

Routing Fit

Use this skill for:

  • Docker/OCI image signing and verification
  • Cosign keyless signing with GitHub Actions OIDC
  • GitHub artifact attestations for container images and SBOMs
  • Buildx SBOM and provenance attestations
  • Syft SBOM generation, Grype or Trivy scanning, and vulnerability waivers
  • Rekor log lookup and release audit evidence
  • SLSA Build track evidence and provenance verification
  • Kubernetes, AKS, or policy-controller deployment gates
  • ACR/GHCR image trust, referrers, immutable digests, and provenance records
  • Artifact leakage prevention for packages, images, release zips, and CI outputs

Do not use this skill as the primary guide for:

  • General Dockerfile authoring unless supply-chain metadata or artifact leakage is involved
  • Runtime container operations, patching, or base image refresh outside release trust
  • Registry cleanup, lifecycle retention, or ACR repository permissions except where trust metadata is affected

Production Defaults for New Projects

ConcernDefaultAvoid
Image referenceDeploy by immutable digestDeploying production from mutable tags
SigningCosign keyless OIDC for GitHub-based buildsLong-lived CI signing keys
Azure signing alternativeNotation with Azure Key Vault or Artifact Signing when required by platform policyNew Docker Content Trust adoption
ProvenanceGitHub artifact attestation plus Buildx provenanceUnverified provenance files uploaded only as artifacts
SBOMSyft SPDX/CycloneDX file, hash, and signed/attached attestationRelying only on registry UI metadata
Vulnerability gateScan SBOM and/or image; fail on policy thresholdSilent waivers without owner, reason, and expiry
Deployment trustAdmission or environment gate verifies digest, signature, and provenanceCI-only verification with no runtime control
Secrets in buildBuildKit secret mountsDocker build args for credentials or tokens
AuditImmutable per-image release recordRetaining logs only in the CI job page

Stop Conditions

Stop and request human review when any condition is true:

  • The image cannot be built, signed, scanned, attested, or verified by immutable digest.
  • The signing identity cannot be constrained to an expected repository, workflow, and ref/environment.
  • The build uses Docker build args for secrets while provenance is enabled.
  • Critical or high vulnerabilities are waived without owner, reason, expiry, and compensating control.
  • The release artifact contains .git, .env*, private keys, certificates, source maps, debug symbols, prompts, SKILL.md, .agent.md, internal orchestration instructions, or server-only source code.
  • Production deployment uses mutable tags without digest mutation or digest enforcement.
  • A workflow uses unpinned third-party actions where repository policy requires full-SHA pinning.
  • A signing key is stored as a long-lived CI secret without a rotation and recovery plan.
  • The pipeline claims SLSA, provenance, or signed-release compliance without a verification step.

Reference

  • Distribution artifact leakage - package publish checks, Docker image inspection, CI artifact hygiene, prompt protection, and git history secret remediation.

Target Architecture

A production container supply chain should create and verify the following chain:

  1. Build image from reviewed source in a hardened CI workflow.
  2. Push image to registry and capture the immutable digest.
  3. Generate Buildx provenance and SBOM attestations when supported by the output mode.
  4. Generate an explicit GitHub artifact attestation for the container image digest.
  5. Generate a durable SBOM file with Syft for audit and downstream scanners.
  6. Scan SBOM and/or image with Grype or Trivy.
  7. Sign the image by digest with Cosign keyless OIDC, or use Notation where platform policy requires it.
  8. Verify signature and provenance using an expected identity policy.
  9. Deploy only the digest that was scanned, signed, and attested.
  10. Enforce trust at deployment with an admission controller, environment gate, or equivalent platform control.
  11. Write an immutable audit record containing digest, signer, builder, SBOM hash, scan result, waivers, and verification evidence.

Real-world incident scenarios (July 2026)

Use these recent Microsoft Security blog write-ups as worked examples when explaining why each link in the chain above matters:

  • AsyncAPI npm supply chain compromise. GitHub Actions pwn request → import-time payload (Microsoft Security blog, July 15 2026). Attack chain started with a pwn-request against a GitHub Actions workflow that ingested untrusted input, then delivered payload at npm import time. Reinforces:
    • Why GitHub Actions pull_request_target / workflow_run workflows must not checkout or execute untrusted code (link to github-actions-ci-cd skill).
    • Why npm-ecosystem SBOM (Syft) and vulnerability scanning (Grype/Trivy) must run before any image layer is signed.
    • Why build-time attestations (actions/attest-build-provenance, actions/attest-sbom) are the verification primitive that would have caught a tampered dependency.
  • ACR Stealer intrusion chains (Microsoft Security blog, July 16 2026). Two observed chains: (1) WebDAV-based ClickFix with Python loaders and blockchain C2; (2) MSHTA-initiated PowerShell chain with steganographic payload delivery. Relevant for container-image runtime threat modelling, reinforces why signed-image-only admission policies and runtime isolation (Kata MicroVM, Hyperlight) matter even after the build-time chain is solid.

When reviewing a supply-chain design with platform teams, cite these incidents as evidence that the verify and enforce steps are not optional, they are the only links that catch what the build step misses.

Buildx Attestations

Generate Buildx SBOM and Provenance

Use Buildx/build-push-action for attestation-capable builds. Attestations require a push to an OCI registry or another output that preserves attestations.

docker buildx build \
  --sbom=true \
  --provenance=mode=max \
  --tag ghcr.io/myorg/myapp:1.0.0 \
  --push .

Requirements and cautions:

  • Use --push for registry-backed attestations. A classic local Docker image store does not preserve the same OCI attestation model.
  • Treat mode=max as sensitive metadata. It can include build argument values. Never pass credentials, tokens, feed passwords, or deployment secrets through Docker build args.
  • Use BuildKit secret mounts for private feeds and authenticated build steps.
  • Buildx attestations are valuable, but should not replace explicit release attestations and verification gates.

Inspect Registry Attestations

Buildx and registry attestation inspection is version-sensitive. Prefer verification tooling and registry referrers where available, and treat direct template examples as diagnostics rather than policy.

# Inspect image and attached metadata. Output shape can vary by Buildx version.
docker buildx imagetools inspect ghcr.io/myorg/myapp:1.0.0

# Inspect the immutable image reference used by the release.
docker buildx imagetools inspect ghcr.io/myorg/myapp@sha256:<digest>

When a policy or audit workflow depends on attestations, use dedicated verification tooling such as gh attestation verify, cosign verify-attestation, or the platform admission controller rather than parsing human-oriented inspect output.


SBOM Generation and Attestation

Use Syft for audit-grade SBOM files because it supports multiple ecosystems and output formats.

# Registry image; no local pull required.
syft ghcr.io/myorg/myapp@sha256:<digest> -o spdx-json > sbom.spdx.json

# Alternative format for tools that require CycloneDX.
syft ghcr.io/myorg/myapp@sha256:<digest> -o cyclonedx-json > sbom.cyclonedx.json

# Record the SBOM hash in the release record.
sha256sum sbom.spdx.json > sbom.spdx.json.sha256

Attach or Attest the SBOM

Prefer a signed SBOM attestation when consumers or compliance tooling need to verify that the SBOM belongs to the released image.

# Cosign attach is useful for registry discovery, but still verify policy support.
cosign attach sbom --sbom sbom.spdx.json ghcr.io/myorg/myapp@sha256:<digest>

# Generic attestation pattern for custom predicates.
cosign attest --yes \
  --predicate sbom.spdx.json \
  --type spdxjson \
  ghcr.io/myorg/myapp@sha256:<digest>

For GitHub artifact attestations, use the workflow action with sbom-path when the project needs GitHub-native attestation verification.


Vulnerability Scanning and Waivers

Grype - SBOM-First Gate

Use Grype when the pipeline already produces an SBOM and audit evidence should be tied to that SBOM.

# Fail on critical vulnerabilities.
grype sbom:./sbom.spdx.json --fail-on critical

# Produce a machine-readable report for audit records.
grype sbom:./sbom.spdx.json --output json > grype-report.json

# Apply explicit, expiring waivers.
grype sbom:./sbom.spdx.json \
  --fail-on critical \
  --ignore-file ./security/sbom-waivers.yaml

Waiver file pattern:

ignore:
  - vulnerability:
      id: CVE-2026-12345
    reason: "Not reachable in production runtime; compensating WAF rule CR-1234"
    expires: "2026-08-01"
    fix-state: "not-fixed"

Waiver rules:

  • Every waiver must include owner, reason, expiry, and compensating control in the PR or adjacent metadata.
  • Do not create non-expiring waivers.
  • Do not waive critical remote-code-execution findings in runtime packages without security approval.
  • Prefer base image refresh or dependency upgrade over waiver creation.

Trivy - Image and Copacetic Input

Use Trivy when scanning the pushed image directly or producing input for Copacetic remediation.

# Fail on high and critical findings.
trivy image --severity HIGH,CRITICAL --exit-code 1 ghcr.io/myorg/myapp@sha256:<digest>

# Export JSON report for audit, dashboards, or Copacetic.
trivy image --format json --output trivy-report.json ghcr.io/myorg/myapp@sha256:<digest>

# Scan directly from registry.
trivy image --remote ghcr.io/myorg/myapp@sha256:<digest>

Cosign Keyless Signing with GitHub Actions OIDC

Use keyless signing for GitHub-hosted release workflows unless the organization requires Notation or an offline/key-managed signing process.

Sign by Digest

cosign sign --yes ghcr.io/myorg/myapp@sha256:<digest>

Rules:

  • Sign the immutable digest, not a mutable tag.
  • Use id-token: write only in the job that needs OIDC.
  • Do not use broad signing jobs that can sign arbitrary artifacts from untrusted inputs.
  • Keep signing after the vulnerability gate unless policy requires signing all build outputs with a separate release status.

Verify with Exact Identity

For production gates, prefer exact identity constraints over broad repository regexes.

cosign verify ghcr.io/myorg/myapp@sha256:<digest> \
  --certificate-identity="https://github.com/myorg/myrepo/.github/workflows/container-release.yml@refs/heads/main" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

Use regex only when the workflow identity varies, and constrain it as tightly as possible:

cosign verify ghcr.io/myorg/myapp@sha256:<digest> \
  --certificate-identity-regexp="^https://github.com/myorg/myrepo/.github/workflows/container-release.yml@refs/(heads/main|tags/v[0-9]+\\.[0-9]+\\.[0-9]+)$" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

Do not use repository-wide patterns such as https://github.com/org/repo/.* for production deployment gates.


GitHub Artifact Attestations

GitHub artifact attestations provide signed provenance for artifacts, including container images. For container images, attest the fully qualified image name without a tag and provide the sha256:<digest> from the build step.

Minimum permissions for the build job that creates container image attestations:

permissions:
  contents: read
  id-token: write
  attestations: write
  packages: write

Attestation step:

- name: Generate image provenance attestation
  uses: actions/attest@<sha>
  with:
    subject-name: ghcr.io/${{ github.repository }}
    subject-digest: ${{ steps.build.outputs.digest }}
    push-to-registry: true

Verification examples:

# Verify with GitHub CLI when GitHub attestations are part of the trust policy.
gh attestation verify \
  oci://ghcr.io/myorg/myapp@sha256:<digest> \
  --owner myorg

# Use Cosign for Sigstore-style signature and attestation verification when required.
cosign verify-attestation ghcr.io/myorg/myapp@sha256:<digest> \
  --certificate-identity="https://github.com/myorg/myrepo/.github/workflows/container-release.yml@refs/heads/main" \
  --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
  --type slsaprovenance

Implementation notes:

  • Generating attestations alone is not a security control. Consumers must verify them.
  • Record the verification command and result in release evidence.
  • For private repositories, confirm GitHub plan support for artifact attestations before making them a hard requirement.

Azure Container Registry and Notation Guidance

For Azure-first environments, choose one of two patterns:

  1. Cosign/Sigstore pattern - best fit when GitHub OIDC, GHCR/ACR OCI artifacts, and Sigstore verification are already approved.
  2. Notation/Notary Project pattern - best fit when the organization requires Azure Key Vault, Azure Artifact Signing, Ratify, or Azure Policy integration.

New projects should not adopt Docker Content Trust as the strategic signing pattern. Prefer OCI artifact signing with Cosign or Notation.

Azure-specific requirements:

  • Use ACR repositories and image references by digest for production.
  • Keep tag immutability and lifecycle rules in registry policy where available.
  • Verify base images before build when using curated internal base images.
  • For AKS, enforce trusted image deployment using an admission controller or Azure-supported verification policy.
  • If using Notation with Key Vault, define certificate lifecycle, rotation, expiry, signer RBAC, and emergency revocation.

Key-Based or Offline Signing

Use key-based signing only when OIDC/keyless signing is unavailable or policy requires managed signing keys.

# Generate once during an approved ceremony; do not run casually in CI.
cosign generate-key-pair

# Sign by digest.
cosign sign --key cosign.key ghcr.io/myorg/myapp@sha256:<digest>

# Verify by public key.
cosign verify --key cosign.pub ghcr.io/myorg/myapp@sha256:<digest>

Key-management requirements:

  • Store private keys in a managed secrets service or HSM-backed signing service.
  • Define key owner, backup, rotation, expiry, revocation, and break-glass recovery.
  • Never store a private signing key as a repository secret without formal risk acceptance.
  • Log every signing event with artifact digest and signer identity.

Rekor Transparency Log

Cosign keyless signatures are recorded in Rekor when using the public Sigstore instance. Rekor supports forensic auditing independent of the registry.

# Locate signature object for an image digest.
cosign triangulate ghcr.io/myorg/myapp@sha256:<digest>

# Search or retrieve entries when rekor-cli is available.
rekor-cli search --sha sha256:<digest>
rekor-cli get --uuid <uuid> --format json

# Direct API lookup for a known UUID.
curl -s "https://rekor.sigstore.dev/api/v1/log/entries/<uuid>" | jq .

Audit records should capture the Rekor UUID or bundle reference when available. Private Sigstore deployments or private repository attestations may use different transparency or bundle storage behaviour; document the chosen trust root.


Deployment Admission Gates

CI verification is necessary but insufficient. Production deployments should verify image trust at the environment boundary.

Minimum deployment gate:

  • Image reference resolves to the exact digest that was built and scanned.
  • Image signature verifies against the expected issuer and identity.
  • Provenance attestation exists and matches the expected repository, workflow, branch/tag, and commit policy.
  • SBOM exists or is attested when required by policy.
  • Vulnerability scan passed or waivers are approved and unexpired.
  • Registry and repository are allowlisted.
  • Deployment tooling refuses unsigned or unverifiable images.

Kubernetes and AKS Options

Prefer one of these patterns:

  • Sigstore Policy Controller for Cosign signatures and attestations.
  • Kyverno image verification policies where Kyverno is the existing policy plane.
  • Ratify/Azure Policy for AKS and Notation-oriented Azure signing patterns.
  • A release environment gate that runs cosign verify, gh attestation verify, or notation verify before deployment, when cluster admission is not yet available.

Admission policy should mutate or require digest references and reject tag-only production workloads.


Full GitHub Actions Pipeline

This pipeline is a production baseline for new projects using GHCR, GitHub artifact attestations, Syft, Grype, and Cosign keyless signing. Replace @<sha> placeholders with full 40-character action SHAs where repository policy requires SHA pinning.

name: Container release

on:
  push:
    branches: [main]
    tags: ['v*.*.*']

permissions: {}

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    name: Build, attest, and create SBOM
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      id-token: write
      attestations: write
    outputs:
      image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      digest: ${{ steps.build.outputs.digest }}
    steps:
      - name: Checkout
        uses: actions/checkout@<sha>
        with:
          persist-credentials: false

      - name: Set up Buildx
        uses: docker/setup-buildx-action@<sha>

      - name: Log in to registry
        uses: docker/login-action@<sha>
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract image metadata
        id: meta
        uses: docker/metadata-action@<sha>
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=tag
            type=sha,prefix=sha-

      - name: Build and push image with Buildx attestations
        id: build
        uses: docker/build-push-action@<sha>
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          sbom: true
          provenance: mode=max
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Generate image provenance attestation
        uses: actions/attest@<sha>
        with:
          subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          subject-digest: ${{ steps.build.outputs.digest }}
          push-to-registry: true

      - name: Install Syft
        uses: anchore/sbom-action/download-syft@<sha>

      - name: Generate audit SBOM
        run: |
          syft ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }} \
            -o spdx-json > sbom.spdx.json
          sha256sum sbom.spdx.json > sbom.spdx.json.sha256

      - name: Upload SBOM evidence
        uses: actions/upload-artifact@<sha>
        with:
          name: sbom-${{ github.sha }}
          path: |
            sbom.spdx.json
            sbom.spdx.json.sha256
          retention-days: 90

  scan:
    name: Scan SBOM
    needs: build
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Download SBOM evidence
        uses: actions/download-artifact@<sha>
        with:
          name: sbom-${{ github.sha }}

      - name: Install Grype
        uses: anchore/scan-action/download-grype@<sha>

      - name: Scan SBOM
        run: |
          grype sbom:./sbom.spdx.json \
            --fail-on critical \
            --output json > grype-report.json
          grype sbom:./sbom.spdx.json --fail-on critical --output table

      - name: Upload vulnerability evidence
        if: always()
        uses: actions/upload-artifact@<sha>
        with:
          name: vulnerability-report-${{ github.sha }}
          path: grype-report.json
          retention-days: 90

  sign:
    name: Sign image
    needs: [build, scan]
    runs-on: ubuntu-latest
    permissions:
      packages: write
      id-token: write
    steps:
      - name: Install Cosign
        uses: sigstore/cosign-installer@<sha>

      - name: Log in to registry
        uses: docker/login-action@<sha>
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Sign image by digest
        run: |
          cosign sign --yes ${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }}

  verify:
    name: Verify release evidence
    needs: [build, scan, sign]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      attestations: read
      packages: read
    steps:
      - name: Install Cosign
        uses: sigstore/cosign-installer@<sha>

      - name: Verify Cosign signature
        run: |
          cosign verify ${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }} \
            --certificate-identity="https://github.com/${{ github.repository }}/.github/workflows/container-release.yml@${{ github.ref }}" \
            --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

      - name: Verify GitHub image attestation
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh attestation verify \
            oci://${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }} \
            --owner ${{ github.repository_owner }}

  deploy:
    name: Deploy verified image
    needs: [build, verify]
    runs-on: ubuntu-latest
    permissions:
      contents: read
    environment: production
    steps:
      - name: Deploy digest-pinned image
        run: |
          echo "Deploy ${{ needs.build.outputs.image }}@${{ needs.build.outputs.digest }}"
          # Replace with az containerapp update, kubectl set image, Helm values update, or GitOps PR.

Pipeline notes:

  • The exact --certificate-identity must match the workflow file name and ref used by the repository. Update container-release.yml if the workflow file has a different name.
  • For tag releases, ${{ github.ref }} becomes refs/tags/<tag>. Ensure the expected identity policy allows only approved tag patterns.
  • If policy requires environment-specific signing, add environment claims or split release signing into a protected environment job.
  • Keep id-token: write limited to the attestation and signing jobs.
  • Do not use Docker build args for secrets. Use BuildKit secrets and make sure the Dockerfile consumes them with RUN --mount=type=secret.

SLSA Build Track Guidance

Do not claim a SLSA Build level from tool presence alone. Record which requirements are satisfied, which are inherited from the hosted build platform, and which remain unverified.

Practical evidence mapping:

EvidenceSupports
GitHub artifact attestation for image digestSigned provenance generated by hosted build platform
Buildx provenanceBuild process metadata attached to OCI image
Exact digest deploymentArtifact immutability and reproducible verification target
Cosign keyless signatureIdentity-bound artifact signature
Verification gateDownstream provenance/signature verification
Protected reusable workflowStronger consistency and isolation for higher assurance
Immutable audit recordCompliance and incident response traceability

Minimum review questions before saying “SLSA aligned”:

  • Which SLSA version and track is being referenced?
  • Is provenance generated by the trusted hosted build platform?
  • Is the provenance signed or otherwise authenticated?
  • Is verification performed by consumers or deployment gates?
  • Can the build workflow be changed without review?
  • Are secrets isolated from untrusted build steps?
  • Is a reusable hardened workflow required for this project type?

Compliance Audit Trail

For regulated or customer-audited workloads, write one immutable record per released image digest.

Minimum fields:

  • Image name and immutable digest
  • Source repository, commit SHA, workflow name, run ID, run URL, and triggering ref
  • Builder identity and signing identity
  • GitHub attestation verification result
  • Cosign or Notation verification result
  • SBOM hash and SBOM storage location
  • Vulnerability report hash and severity counts
  • Waiver file hash, owners, reasons, and expiry dates
  • Rekor UUID, Sigstore bundle, or equivalent trust evidence when available
  • Deployment environment and deployment approval reference
  • Timestamp in UTC

Retention:

  • Set retention from customer, regulatory, legal, and audit requirements.
  • Do not hard-code a seven-year default unless the organization has approved it.
  • Use immutable storage such as Azure Immutable Blob Storage or equivalent WORM/Object Lock storage.

Example record:

cat > audit-record.json <<'JSON'
{
  "image": "ghcr.io/myorg/myapp",
  "digest": "${IMAGE_DIGEST}",
  "source_repository": "${GITHUB_REPOSITORY}",
  "commit_sha": "${GITHUB_SHA}",
  "workflow_run": "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}",
  "ref": "${GITHUB_REF}",
  "built_utc": "$(date -u --iso-8601=seconds)",
  "builder": "github-actions",
  "signing_method": "cosign-keyless-oidc",
  "sbom_sha256": "$(sha256sum sbom.spdx.json | cut -d' ' -f1)",
  "vulnerability_report_sha256": "$(sha256sum grype-report.json | cut -d' ' -f1)",
  "waivers_applied": false
}
JSON

Resource Directories

Load these directories only when the selected workflow needs deeper examples, prompts, or reference material:

  • references/

Final Output Contract

  • A concrete trust pipeline covering build, digest capture, scan, signature, attestation, verification, and deployment gate expectations.
  • The selected signing/attestation model, required identities, and evidence artefacts that downstream consumers must verify.
  • Waiver, audit, and artifact-leakage controls needed for production release governance.
  • Any unverified tool flags, action pins, registry capabilities, or policy assumptions marked with [VERIFY].

Quality Gate

Do not sign off until the image is traceable by immutable digest, verification happens after generation, and the trust policy names the expected identity and deployment gate. If any part of signing, attestation, or verification is only assumed, keep it explicitly conditional with [VERIFY].

Review Checklist

Before finalizing a PR that uses this skill, confirm:

  • Workflow actions are pinned according to repository policy.
  • Image is built, scanned, signed, attested, verified, and deployed by digest.
  • GitHub artifact attestation step exists when the pipeline claims GitHub provenance.
  • Cosign verification uses exact identity or a narrowly constrained regex.
  • Buildx provenance does not expose secrets through build args.
  • SBOM is generated, hashed, stored, and scanned.
  • Vulnerability waivers are explicit, expiring, owned, and reviewed.
  • Deployment has an admission gate or equivalent environment verification gate.
  • Audit record is immutable and contains verification evidence.
  • Artifact leakage reference was applied to image, package, and CI artifact outputs.

Hidden Tooling Surface Properties

Container supply-chain tooling (Cosign, Notation, Docker, GitHub Attestations) has configuration surfaces absent from overview docs:

ToolSurfaceImpact
CosignCOSIGN_PASSWORD, COSIGN_REPOSITORY, COSIGN_YESEnvironment variables that control keyless signing behaviour
Cosign--allow-insecure-registry, --allow-http-registryInsecure registry flags — should never be used in production
Cosign.github/workflows/ with actions/attest-build-provenanceGitHub Artifact Attestations — subject-name, push-to-registry
Notation~/.config/notation/trustpolicy.jsonTrust policy configuration — trustPolicies[].signatureVerification.verificationCerts
Notationnotation cert subcommandsCertificate management — add, delete, ls, show
Dockerdocker build --provenance / --sbomBuildKit provenance and SBOM attestation flags
Dockerdocker buildx imagetools inspectImage manifest and attestation inspection
Sigstorehttps://fulcio.sigstore.dev / https://rekor.sigstore.devFulcio certificate authority and Rekor transparency log endpoints
SLSABuild L1-L3 verificationslsa-verifier CLI — --source-uri, --source-tag flags
OCI referrersoras discover / oras attachOCI reference types — attestation, SBOM, signature as referrers

Related Guidance

Companion topics that may live in separate skills or standards in your own setup:

  • Container image operations - Copacetic patching, base image refresh, runtime image operations
  • Registry lifecycle - ACR immutable tags, retention, ABAC permissions
  • GitHub Actions workflow hardening - OIDC federation, action pinning, artifact hygiene
  • Kubernetes deployment guardrails - admission policy (not covered by a dedicated skill here)

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.