All skills
lukemurraynz avatar

/container-supply-chain

@2cc2455

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.

Use this Skill: https://skilld.dev/gh/lukemurraynz/hve-agent-skills/container-supply-chain

This session only. Nothing lands on disk.

SKILL.md

≈172 tokens always: the name and description. ≈9.1k when used: this file. ≈3.3k more on demand in 2 files.

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 trigger Should NOT trigger Nearby skill collision
Designing or hardening a build-sign-attest-scan-verify pipeline for OCI images The task is only about runtime debugging, container startup, or incident triage after deployment Use container-operations for runtime/container failure diagnosis
Implementing image signing, provenance, SBOM, attestation verification, or deployment trust gates The task is only about Dockerfile authoring with no supply-chain trust or artifact-leakage scope Use Docker/container authoring guidance unless release trust is in scope
Producing audit-ready release evidence, waiver governance, or admission-policy checks for container artifacts The request is only about registry cleanup or lifecycle retention unrelated to signatures/attestations Use 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

Concern Default Avoid
Image reference Deploy by immutable digest Deploying production from mutable tags
Signing Cosign keyless OIDC for GitHub-based builds Long-lived CI signing keys
Azure signing alternative Notation with Azure Key Vault or Artifact Signing when required by platform policy New Docker Content Trust adoption
Provenance GitHub artifact attestation plus Buildx provenance Unverified provenance files uploaded only as artifacts
SBOM Syft SPDX/CycloneDX file, hash, and signed/attached attestation Relying only on registry UI metadata
Vulnerability gate Scan SBOM and/or image; fail on policy threshold Silent waivers without owner, reason, and expiry
Deployment trust Admission or environment gate verifies digest, signature, and provenance CI-only verification with no runtime control
Secrets in build BuildKit secret mounts Docker build args for credentials or tokens
Audit Immutable per-image release record Retaining 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:

Evidence Supports
GitHub artifact attestation for image digest Signed provenance generated by hosted build platform
Buildx provenance Build process metadata attached to OCI image
Exact digest deployment Artifact immutability and reproducible verification target
Cosign keyless signature Identity-bound artifact signature
Verification gate Downstream provenance/signature verification
Protected reusable workflow Stronger consistency and isolation for higher assurance
Immutable audit record Compliance 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:

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:

Tool Surface Impact
Cosign COSIGN_PASSWORD, COSIGN_REPOSITORY, COSIGN_YES Environment variables that control keyless signing behaviour
Cosign --allow-insecure-registry, --allow-http-registry Insecure registry flags — should never be used in production
Cosign .github/workflows/ with actions/attest-build-provenance GitHub Artifact Attestations — subject-name, push-to-registry
Notation ~/.config/notation/trustpolicy.json Trust policy configuration — trustPolicies[].signatureVerification.verificationCerts
Notation notation cert subcommands Certificate management — add, delete, ls, show
Docker docker build --provenance / --sbom BuildKit provenance and SBOM attestation flags
Docker docker buildx imagetools inspect Image manifest and attestation inspection
Sigstore https://fulcio.sigstore.dev / https://rekor.sigstore.dev Fulcio certificate authority and Rekor transparency log endpoints
SLSA Build L1-L3 verification slsa-verifier CLI — --source-uri, --source-tag flags
OCI referrers oras discover / oras attach OCI 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)

Source: SKILL.md on GitHub

1 alert8d3 checks · Risk CRITICAL
  • Gen Agent Trust Hub8d

    This skill provides production-grade guidance for container supply chain security. It includes an attack surface for indirect prompt injection as it processes external artifacts, and it references a security transparency log that may trigger false positives in generic automated scanners.

  • Socket8d

    No alerts

  • Snyk8d

    Risk: LOW · No issues

Signed by skilld at 2cc2455. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated last month
Other metadata
compatibility
Assumes new projects. Prefer current Docker Buildx/build-push-action, Cosign v2+, GitHub artifact attestations, Syft, Grype, Trivy, and OCI registries that support signatures/referrers. Verify current tool versions, CLI flags, registry support, and cloud-provider guidance before enforcement.
metadata
{
  "owner": "platform-engineering",
  "lastReviewed": "2026-07-29",
  "last_verified": "2026-07-29"
}

README badge

README badge for lukemurraynz/hve-agent-skills/container-supply-chain