Home Posts Supply Chain Security: Ephemeral Builds and SBOMs [2026]
Security Deep-Dive

Supply Chain Security: Ephemeral Builds and SBOMs [2026]

Supply Chain Security: Ephemeral Builds and SBOMs [2026]
Dillip Chowdary
Dillip Chowdary
Tech Entrepreneur & Innovator · May 05, 2026 · 8 min read

Bottom Line

A hardened pipeline needs two properties at the same time: a clean build environment per job and a machine-verifiable inventory of what shipped. If you pair ephemeral runners with signed provenance and SBOM attestations, you make tampering, drift, and blind releases much harder.

Key Takeaways

  • GitHub-hosted jobs run in a fresh instance, reducing cross-build residue by default.
  • Use actions/attest@v4 twice: once for provenance and once for the SBOM attestation.
  • Syft emits SPDX JSON directly with syft . -o spdx-json=sbom.spdx.json.
  • Verify the exact shipped artifact with gh attestation verify before release or deploy.

Hardening a software supply chain is less about adding one magic scanner and more about closing two persistent gaps: dirty build environments and unverifiable release metadata. An attacker who lands on a long-lived runner inherits state you forgot about. A release without an attached SBOM leaves downstream teams guessing what actually shipped. This tutorial shows a practical pattern for May 05, 2026: build on ephemeral runners, generate an SBOM, sign both provenance and inventory, and verify the result before release.

  • Use a fresh build environment for every job to reduce state leakage between runs.
  • Generate an SPDX JSON SBOM during the same workflow that creates the artifact.
  • Create a provenance attestation and an SBOM attestation for the exact same subject file.
  • Make verification a release gate, not an afterthought.

Prerequisites and design

Prerequisites

  • A GitHub repository with GitHub Actions enabled.
  • A build output you can package as a single file, such as a tarball or binary.
  • GitHub CLI installed locally for verification.
  • A public repository on any current GitHub plan, or GitHub Enterprise Cloud if you need attestations for private or internal repositories.
  • Optional: a self-hosted runner fleet if you need private network access or custom hardware.

Bottom Line

Start with an ephemeral runner boundary, then attach signed provenance and an SBOM to the exact bytes you ship. That combination turns “trust our CI” into a claim consumers can actually verify.

The design choice here is deliberate. GitHub-hosted jobs are the easiest way to get an ephemeral environment because each job runs in a fresh runner instance. If you need tighter control, GitHub also recommends ephemeral self-hosted runners for autoscaling instead of persistent runners. In both cases, the security property you want is the same: no build should inherit filesystem residue, credentials, or tool drift from a previous one.

Step 1: Pick an ephemeral runner

Recommended baseline: GitHub-hosted

  1. Use a standard hosted runner such as ubuntu-latest.
  2. Keep build and attestation steps in the same job so the subject file and SBOM are created in one clean execution boundary.
  3. Avoid reusing artifacts from older runs as build inputs unless you also verify them.
jobs:
  package:
    runs-on: ubuntu-latest

Optional: ephemeral self-hosted

If your builds need internal package mirrors, private subnet access, or specialized hardware, register self-hosted runners with --ephemeral. For containerized fleets, pair that with --disableupdate and roll runner updates through your image pipeline instead of letting each short-lived runner patch itself on boot.

./config.sh --url https://github.com/ORG --token TOKEN --ephemeral --disableupdate

Keep the workflow YAML readable. If your pipeline grows beyond a small file, a quick pass through TechBytes’ Code Formatter helps reviewers catch permission or path mistakes faster.

Step 2: Build, generate SBOM, and attest

This example packages the repository into a tarball so the flow is language-agnostic. In a real service, replace the packaging command with your compiler or image build step. The important detail is that the subject you attest is the same file you plan to release, publish, or deploy.

  1. Check out the repository.
  2. Install Syft.
  3. Create the release artifact.
  4. Generate an SPDX JSON SBOM.
  5. Create a provenance attestation.
  6. Create a separate SBOM attestation for the same subject.
name: build-and-attest

on:
  push:
    branches: [ main ]
  workflow_dispatch:

jobs:
  package:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
      attestations: write
      artifact-metadata: write

    steps:
      - uses: actions/checkout@v4

      - name: Install Syft
        run: curl -sSfL https://get.anchore.io/syft | sudo sh -s -- -b /usr/local/bin

      - name: Create release artifact
        run: |
          mkdir -p dist
          tar --exclude=.git -czf dist/app-source.tgz .

      - name: Generate SPDX SBOM
        run: syft . -o spdx-json=sbom.spdx.json

      - name: Attest build provenance
        uses: actions/attest@v4
        with:
          subject-path: dist/app-source.tgz

      - name: Attest SBOM
        uses: actions/attest@v4
        with:
          subject-path: dist/app-source.tgz
          sbom-path: sbom.spdx.json

Why the workflow is structured this way

  • id-token: write lets the workflow mint the OIDC token used for signing.
  • attestations: write allows the attestation to be stored and associated with the repository.
  • artifact-metadata: write lets GitHub create the artifact storage record used by the attestation flow.
  • Running actions/attest@v4 twice gives you two distinct claims: provenance and SBOM.
  • Generating the SBOM inside the same ephemeral job reduces drift between “what was built” and “what was described.”
Pro tip: Attest the final artifact, not just the repository tree. Consumers verify shipped bytes, not your intentions.

Step 3: Verify the artifact

Verification belongs on the consumer side of the boundary: before promotion, before deployment, or before mirroring to another registry. Download the exact file you built, then verify its attestation against the repository that produced it.

  1. Fetch the built artifact to a local path such as dist/app-source.tgz.
  2. Verify its provenance.
  3. Optionally emit machine-readable JSON for policy checks.
gh attestation verify dist/app-source.tgz --repo ORG/REPO

gh attestation verify dist/app-source.tgz --repo ORG/REPO --format json

Expected output

  • A success message indicating verification completed.
  • The repository identity that signed the attestation.
  • The workflow path or signer workflow reference used to produce the artifact.
  • In JSON mode, structured fields you can feed into release gates or admission policy.

If you later move from tarballs to container images, the same pattern applies. The verification target becomes an oci:// image reference instead of a local file path, but the trust model stays the same.

Troubleshooting

1. The attestation step fails with a permissions error

  • Check that the job has id-token, attestations, and artifact-metadata set to write.
  • Do not assume repository defaults are enough; set job-level permissions explicitly.

2. Private repository attestations are unavailable

  • GitHub supports artifact attestations for public repositories across current plans.
  • For private or internal repositories, you need GitHub Enterprise Cloud.

3. Verification fails even though the workflow passed

  • Verify the exact file that was attested. Repacking or recompressing it changes the digest.
  • If you export logs or artifacts for debugging, sanitize secrets before sharing them. TechBytes’ Data Masking Tool is useful for scrubbing tokens and environment values from CI output.
Watch out: A signed SBOM does not prove the build environment was clean. You need both the ephemeral runner boundary and the attested metadata to get meaningful supply-chain hardening.

What's next

  • Make gh attestation verify a mandatory check before promoting artifacts from CI to release storage.
  • Emit both SPDX and CycloneDX if different downstream tools expect different formats.
  • For internal workloads, move from GitHub-hosted runners to autoscaled ephemeral self-hosted runners while preserving the same attestation pattern.
  • Forward self-hosted runner logs to external storage so ephemeral teardown does not destroy your forensic trail.
  • Review the official references for exact behavior and current syntax: workflow syntax, GitHub-hosted runners, ephemeral self-hosted runners, artifact attestations, GitHub CLI verification, and Syft.

The core pattern is intentionally small: fresh runner, deterministic artifact, SBOM generated in-band, and verifiable attestations tied to the same subject. That is enough to raise the cost of tampering without turning your pipeline into a compliance science project.

Frequently Asked Questions

Do SBOMs alone harden a software supply chain? +
No. An SBOM tells you what components were present, but it does not prove the build ran in a clean environment or that the artifact came from the workflow you expect. Pair the SBOM with provenance attestation and an ephemeral build boundary.
Should I use GitHub-hosted runners or ephemeral self-hosted runners? +
Use GitHub-hosted runners when you want the simplest fresh-per-job model. Use ephemeral self-hosted runners when you need private networking, custom hardware, or tighter control over the image, but keep the one-job-per-runner pattern.
Why does gh attestation verify fail after a successful workflow run? +
The most common cause is digest mismatch. If you re-zip, rename, or otherwise rebuild the file after attestation, the bytes no longer match the signed subject, so gh attestation verify correctly rejects it.
Do I need two attestation steps in GitHub Actions? +
Yes if you want both claims. actions/attest@v4 creates a provenance attestation by default, while providing sbom-path creates an SBOM attestation, so run the action once for each claim against the same subject file.

Get Engineering Deep-Dives in Your Inbox

Weekly breakdowns of architecture, security, and developer tooling — no fluff.

Found this useful? Share it.