Documents
consumer-guide
consumer-guide
Type
External
Status
Published
Created
Jun 13, 2026
Updated
Jun 13, 2026
Source
View

Consumer Guide — Using These Actions in Your Own bootc Image#

How to wire projectbluefin/actions into a custom Fedora-based bootc image repo.

Contents#

Sub-file (load as needed):


Two paths#

PathWhen to use
Full reusable workflowYour image follows the bluefin/aurora build model (Fedora base, Justfile-driven, GHCR push)
Composite actions à la carteYou have a custom pipeline, non-Fedora base, or multi-arch needs

Path 1 — Full reusable workflow#

Prerequisites#

Your repo must satisfy a Justfile contract: the reusable workflow calls specific recipes from your checked-out repo. All recipe signatures must match exactly.

RecipeSignatureWhat it must do
checkjust checkValidate repo health (lint, format); exit non-zero on failure
image_namejust image_name <base> <stream> <flavor>Print the image name to stdout (e.g. my-image)
generate-default-tagjust generate-default-tag <stream> <ghcr> [kernel_pin]Print the primary OCI tag (e.g. latest)
generate-build-tagsjust generate-build-tags <image> <stream> <flavor> [kernel_pin] <ghcr> [version] <event> <number>Print newline-separated alias tags
setup-cachejust setup-cache <base> <stream> <ghcr> <event>Print the cache key fragment; optionally configure OCI layer cache
build-ghcrjust build-ghcr <image> <stream> <flavor> [kernel_pin]Build the image into local podman storage as <image>:<default-tag>
tag-imagesjust tag-images <image_name> <default_tag> <tags>Apply alias tags to the locally built image

Easiest path: fork the bluefin Justfile as a starting point and adapt it for your image name and base.

Minimal caller workflow#

# .github/workflows/build.yml
name: Build My Image

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    uses: projectbluefin/actions/.github/workflows/reusable-build.yml@v1
    secrets: inherit
    with:
      brand_name: my-image # must match your image_name recipe output
      stream_name: latest # stable | latest | beta | testing
      image_flavors: '["main"]' # JSON array; each entry is passed as <flavor> to Justfile
      architecture: '["x86_64"]' # '["x86_64"]' or '["x86_64", "aarch64"]'

Full inputs reference#

InputRequiredDefaultDescription
brand_namenobluefinPassed as <base> to all Justfile recipes
stream_nameyesstable, latest, beta, or testing
image_flavorsno'["main", "nvidia-open"]'JSON array of flavor strings
architectureno'["x86_64"]'JSON array; aarch64 requires self-hosted ARM runner
kernel_pinno""Full kernel version string; passed through to build and tag recipes
pr_numberno""Set by e2e-dispatch.yml — scopes tags to the PR number

Output#

outputs:
  digests: # Nested JSON: { "my-image-main": { "amd64": "sha256:abc..." } }

Consume downstream in a signing or release job:

jobs:
  build:
    uses: projectbluefin/actions/.github/workflows/reusable-build.yml@v1
    secrets: inherit
    with:
      brand_name: my-image
      stream_name: stable
      image_flavors: '["main"]'
      architecture: '["x86_64"]'

  release:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - run: echo "Digests = ${{ needs.build.outputs.digests }}"

Path 2 — Composite actions à la carte#

Use individual actions when you need more control: different base distro (CentOS, Alpine), multi-arch manifest, non-Justfile build system, or custom signing.

Action catalog#

Actionuses: pathPurpose
setup-runnerbootc-build/setup-runner@v1Update podman, set up BTRFS storage, install tools
dnf-cachebootc-build/dnf-cache@v1Restore/save buildah layer cache
preflightbootc-build/preflight@v1Validate registry auth, normalize image refs
detect-changesbootc-build/detect-changes@v1Detect changed paths, compute image-flavor build matrix
validate-prbootc-build/validate-pr@v1Run just check, shellcheck, hadolint, pre-commit
generate-tagsbootc-build/generate-tags@v1Generate shared Bluefin/Fedora OCI alias tags
push-imagebootc-build/push-image@v1Push with retry, digest capture, skopeo alias tags
create-manifestbootc-build/create-manifest@v1Multi-arch OCI manifest index assembly
sign-and-publishbootc-build/sign-and-publish@v1Cosign (keyless or key) + Syft SBOM + attestation
rechunkbootc-build/rechunk@v1rpm-ostree zstd:chunked rechunking with delta support
chunkabootc-build/chunka@v1OCI-native chunkah rechunking (no rpm-ostree needed)
ghcr-cleanupbootc-build/ghcr-cleanup@v1Prune old/untagged GHCR images

generate-tags is for Path 2 and other custom pipelines. Path 1 does not use it; tag generation stays in the caller's Justfile.

Minimal custom pipeline#

jobs:
  build:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
      packages: write
      id-token: write # required for keyless cosign signing

    steps:
      - uses: actions/checkout@v4

      - uses: projectbluefin/actions/bootc-build/setup-runner@v1
        with:
          storage-backend: btrfs
          install-tools: '["cosign", "oras", "syft"]'

      - uses: projectbluefin/actions/bootc-build/dnf-cache@v1
        id: dnf-cache-restore
        with:
          action: restore
          cache-name: my-image-42
          image-flavor: ${{ matrix.image_flavor }}

      - name: Build image
        run: |
          sudo podman build \
            --tag my-image:latest \
            --label "org.opencontainers.image.version=42.$(date +%Y%m%d)" \
            .

      - uses: projectbluefin/actions/bootc-build/dnf-cache@v1
        with:
          action: save
          cache-name: my-image-42
          image-flavor: ${{ matrix.image_flavor }}

      - if: github.event_name != 'pull_request'
        uses: projectbluefin/actions/bootc-build/push-image@v1
        id: push
        with:
          image-name: my-image
          tags: "latest"
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - if: github.event_name != 'pull_request'
        uses: projectbluefin/actions/bootc-build/sign-and-publish@v1
        with:
          image-ref: ghcr.io/${{ github.repository_owner }}/my-image
          digest: ${{ steps.push.outputs.digest }}
          github-token: ${{ secrets.GITHUB_TOKEN }}
          signing-mode: keyless
          generate-sbom: "true"

Multi-arch pipeline (with manifest)#

strategy:
  matrix:
    arch: [x86_64, aarch64]
    include:
      - arch: x86_64
        runner: ubuntu-24.04
      - arch: aarch64
        runner: ubuntu-24.04-arm

jobs:
  build:
    runs-on: ${{ matrix.runner }}
    outputs:
      digest: ${{ steps.push.outputs.digest }}
    # ... build and push per-arch image ...

  manifest:
    needs: build
    runs-on: ubuntu-24.04
    steps:
      - uses: projectbluefin/actions/bootc-build/create-manifest@v1
        with:
          image-name: my-image
          tags: "latest"
          digests-json: >-
            {
              "amd64": "${{ needs.build.outputs.digest-amd64 }}",
              "arm64": "${{ needs.build.outputs.digest-arm64 }}"
            }
          github-token: ${{ secrets.GITHUB_TOKEN }}

Note: create-manifest does not install its dependencies. Ensure podman and jq are available on the runner.


Versioning and SHA pinning#

Pin to @v1 for stability. To test against a feature branch before it merges:

uses: projectbluefin/actions/.github/workflows/reusable-build.yml@abc1234

Move back to @v1 after the branch merges. Renovate manages SHA bumps automatically.


Known constraints#

ConstraintDetail
Fedora only (reusable workflow)The rechunk step uses rpm-ostree and assumes Fedora OSTree base. CentOS/Alpine users should use composite actions à la carte with chunka
Justfile contract is strictAll 7 required recipes must exist with the exact expected signatures
aarch64 requires ARM runnerSelf-hosted or GitHub-hosted ubuntu-24.04-arm; not included in the default free-tier
Registry hardcoded to GHCRThe IMAGE_REGISTRY env var is ghcr.io/${{ github.repository_owner }}; override only via composite actions
CentOS Stream requires explicit compressionSet force-compression: true on both chunka and push-image. Fedora consumers must leave both at the default false
SBOM on all non-PR streamstesting stream builds include SBOM — weekly promotions retag testing digests to stable, so SBOM coverage is required end-to-end
Multi-arch matrix stays in the consumer workflowDo not move matrix orchestration into shared actions. Shared actions are per-arch steps; the matrix stays in the consumer workflow

Checklist before going live#

  • Justfile has all 7 required recipes with correct signatures
  • permissions: id-token: write in the calling job (required for keyless cosign)
  • secrets: inherit (or explicit GITHUB_TOKEN) passed to the reusable workflow
  • GHCR package visibility set to public, or GITHUB_TOKEN has write access
  • stream_name is one of stable, latest, beta, testing
  • image_flavors and architecture use double-quoted strings inside the JSON array: '["main"]' not "['main']"
  • Tested with stream_name: testing first (faster feedback loop)
  • Opened a draft PR in your repo to validate the integration before merging
  • Added a skill-drift.yml wrapper calling skill-drift-check.yml@v1 — see docs/skills/factory-operations.md → "Skill-Drift PR Check"
  • Production promotion workflow gated behind environment: production with 2 required reviewers

Getting help#