Dosu LogoDosu Logo
Ask
Join our Discord
Organization avatar
bluefinPublic
Bluefin
Documentsbluefin
ci
ci
Type
External
Status
Published
Created
Jun 13, 2026
Updated
Jul 28, 2026
Updated by
Dosu Bot
Source
docs/ci.md

CI reference#

Jobs#

JobTriggersWhat
validatepull_requestbst show — graph + patch check (~15 min)
e2epull_request when elements/, files/, patches/, Justfile, or project.conf changedSmoke test in QEMU via projectbluefin/testsuite
buildpush: testing/next (paths-ignore: .github/workflows/**, docs/**, **.md, AGENTS.md), merge_group, workflow_dispatch, schedule: daily 13:00 UTC — skips on pull_requestFull OCI build (~60–90 min)
build-aarch64push: testing/main (BST-affecting paths only), workflow_run from publish.yml on testing, workflow_dispatchARM64 — fully decoupled, never blocks release

Publish pipeline (publish.yml)#

build success on testing or next triggers publish.yml via workflow_run:

build.yml (testing|next) → [workflow_run] → publish.yml
                                             setup → publish-image → boot-check → promote (:testing or :next)
                                                                  └──────────→ publish-sbom (parallel)
JobWhat
setupResolves SHA, trigger event, and branch
publish-imageExports from CAS; runs chunka@v1 to rechunk; pushes :$sha; signs + attests
boot-checkHard gate — image must boot before :testing is promoted
promoteskopeo copy :$sha → :testing (only runs after boot-check passes)
publish-sbomGenerates SBOM; attaches via oras; signs SBOM (runs in parallel with promote)

promote depends only on publish-image + boot-check, not on SBOM — saves 10–15 min on the critical path.

Critical ordering: publish.yml pulls the OCI artifact from CAS. The artifact is only in CAS if build.yml ran first for that SHA. Always dispatch build.yml --ref testing (or let push trigger it) before manually dispatching publish.yml.

Stable promotion (execute-release.yml)#

execute-release.yml fires via workflow_run from publish.yml on the testing branch — no commit message gate, no PR, no human approval.

push to testing (BST-affecting) or daily 13:00 UTC schedule
  → build.yml → publish.yml → boot-check → :testing
  → execute-release.yml (workflow_run from publish on testing)
       → SHA freshness check (:testing SHA vs :stable SHA)
           → skip if equal (already up to date)
           → cosign verify :testing
           → skopeo copy :testing → :stable
           → fast-forward main bookmark
           → GitHub Release created

main is a release bookmark only — fast-forwarded by execute-release.yml after each successful promotion. Do not open PRs against main.

Schedule#

Build fires daily at 13:00 UTC (schedule: in build.yml), plus on every BST-affecting push to testing or next, merge_group, and workflow_dispatch.

Remote cache#

cache.projectbluefin.io:11002 — mTLS via CASD_CLIENT_CERT + CASD_CLIENT_KEY.

Published images#

ghcr.io/projectbluefin/dakota:{testing,stable,next,btw} and ghcr.io/projectbluefin/dakota:<sha>

Streams:

  • :testing — published on every BST-affecting push to the testing branch (or daily schedule)
  • :stable — promoted from :testing daily by execute-release.yml (when :testing SHA differs from :stable)
  • :next / :btw — published from the next branch; never promoted to :stable

Never bypass the merge queue with --admin.

Manual stable promotion#

To manually cut a :stable release:

# 1. Verify :testing is fresh and cosign-verified, then dispatch execute-release directly
gh workflow run execute-release.yml --repo projectbluefin/dakota --ref testing

Restarting the factory (publish pipeline has been idle)#

When the publish pipeline has been paused intentionally (e.g., post-refactor),
the restart sequence is:

# 1. Verify publish.yml is healthy — no startup_failure
gh run list --repo projectbluefin/dakota --workflow publish.yml --limit 5

# 2. Dispatch a fresh build on testing to populate the CAS
gh workflow run build.yml --repo projectbluefin/dakota --ref testing
# Wait ~60–90 minutes for build to complete

# 3. publish.yml auto-triggers via workflow_run; if not, dispatch manually
gh workflow run publish.yml --repo projectbluefin/dakota --ref testing

# 4. Monitor until :testing lands, then execute-release auto-triggers
gh run watch --repo projectbluefin/dakota

Common failure: startup_failure with jobs: []

This means GitHub rejected the workflow YAML before creating any jobs — no logs
are available. Root causes found in this repo:

CauseFix
artifact-metadata: write in permissions: blockNot a valid GITHUB_TOKEN scope; remove it
Job-level permissions: on a reusable workflow call jobRemove the job-level block; let it inherit from top-level

Valid GITHUB_TOKEN permission scopes: actions, attestations, checks,
contents, deployments, discussions, environments, id-token, issues,
packages, pages, pull-requests, repository-projects, security-events,
statuses. Any unknown scope causes startup_failure.

e2e change detection#

e2e uses a should-run job that diffs HEAD against the PR base branch. It fires when any of these paths change:

elements/** files/** patches/** Justfile project.conf

There is no paths: filter on the on.pull_request trigger — the workflow always starts, but the e2e job is skipped when should-run finds no relevant changes. This means e2e is marked skipped (not failed) for action pin bumps and workflow-only changes, which satisfies the required status check.

Documents
Changelogs
Bluefin LTS Errata
Pin Log
2024-12-30-ublue-2024-wrapup
2025-01-01-announcements-archive
2025-02-23-february-update
2025-05-14-bluefin-f42
2025-06-23-bazaar-default
2025-07-06-fresh-bluefin-isos-and-bazaar
2025-07-11-four-years-of-ublue
2025-07-15-bold-brew
2025-07-17-ask-projectbluefin
2025-08-01-august-wallpapers
2025-08-08-bluefin-on-lfx
2025-08-29-github-oss-fund
2025-09-17-color-with-bluefin
2025-09-18-bluefin-lts-and-gdx
2025-09-23-LTS-at-indiafoss
2025-10-28-bluefin-autumn
2025-10-31-fastfetch-metrics
2025-11-15-cloud-native-milestone-15-million
2025-11-16-coreos-desktop
2025-11-24-new-just-and-bbrew
2025-11-27-bluefin-and-paleoartists
2025-11-30-report
2025-12-04-flatpak-support-in-brewfiles
2025-12-06-interview-with-michael-tunnell
2025-12-07-documentation-updates
2025-12-14-huntress-holiday-wallpapers
2025-12-15-easier-homebrew-installation-for-custom-images
2025-12-27-upcoming-homebrew-cli-changes
2025-12-30-bluefin-2025-wrapup
2025-12-31-report
2026-01-03-modernizing-custom-images
2026-01-31-report
2026-02-01-automated-reports-changelogs
2026-02-28-report
2026-03-13-bluefin-cli-mac-wsl
2026-03-27-bluefin-lts-gnome-49-50
2026-03-29-composefs-fisherman
2026-03-29-composefs-fisherman-design
2026-03-30-boot-verification
2026-03-30-boot-verification-design
2026-03-30-proportional-progress-tracking
2026-03-30-proportional-progress-tracking-design
2026-03-31-report
2026-04-02-state-of-ecosystem
2026-04-19-dakota-alpha-1
2026-04-30-report
2026-05-05-bluefin-spring
2026-05-12-bluefin-spring-2026
2026-05-13-bluefin-spring-2026-2
2026-05-14-making-our-own-fate
2026-05-15-hummingbird
2026-05-23-gradia-capture-bluefin
2026-05-28-knuckle
2026-05-31-report
2026-06-11-promotion-pr-body
AGENTS
AGENTS
AGENTS
AGENTS
AGENTS
AGENTS
Building a Custom Bluefin Image
CI_CD_GUIDE
CLAUDE
CLAUDE
CONTRIBUTING
CONTRIBUTING
CONTRIBUTING
CONTRIBUTING
CONTRIBUTING
FAQ
How can I install Double Commander on Bluefin (an immutable Linux OS), coming from Arch Linux?
How can you fix random GPU artifacts and hard freezes on an AMD Framework 16 laptop running Linux (Bluefin/Fedora)?
How do I install the Cloudflare WARP (One) client on Bluefin?
How to Reset a User's Home Directory to Defaults on Bluefin
INDEX
MAINTAINERS
MULTI_VARIANT_BUILD
PITFALLS
PULL_REQUEST_TEMPLATE
Plex Media Server
README
README
README
README
README
README
README
README
README
SECURITY
SECURITY
SECURITY
SKILL
SKILL
SKILL
SKILL
TRANSLATING
Update Process
Which Bluefin ISO is recommended for a Lenovo Yoga Pro 9i with an NVIDIA RTX 4050 for Python data science and Machine Learning with CUDA?
about-monthly-reports
action-reference
actionadon
add-package
administration
agentic-contributing
ai
analytics
architect
architecture
artwork
blog-poster.agent
bluefin-dx
bluefin-gdx
bonedigger-agent-donation
bonedigger-lifecycle
bonedigger-overview
bonedigger-templates
bonedigger-ujust
bst-overrides
build
build
buildstream
ci
ci
ci
code-of-conduct
command-line
composite-actions
consumer-guide
consumer-validation
contributing
contributors
conventional-commit.prompt
copilot-instructions
copilot-instructions
copilot-instructions
copilot-instructions
dakota-tpm2-validation
debugging
demo-mode-e2e
determinism
dinosaurs
downloads
downloads-testing
driver-versions
e2e-ci
e2e-feature-verification
encryption-matrix
factory-operations
failure-paths
feedback-loop
gstreamer-codec-validation
human-gates
images
index
index
installation
installer
introduction
knuckle
label-workflow
libpastry-integration
live-iso
local-ota
lore
lts
luks-testing
merge-queue
mission
multi-arch
music
not-bluefin
oci-assembly
oci-layers
onboarding
overview
packaging-binaries
packaging-gnome-extensions
packaging-go
packaging-rust
packaging-zig
patch-junctions
patches
pr-checklist
pr-review
press-kit
projects
pull_request_template
pull_request_template
pull_request_template
qr-phone-companion
quickstart
r2-promotion
release-qualification
remove-package
reports
reusable-workflow
skill-improvement
supply-chain
t2-mac
testing
tips
troubleshooting
ujust-recipes
update-refs
upgrade-and-migration
ux-ubuntu-provision
values
variants
vm-stack
workflow