ci
Skill131 starsChanged 18 days agoApache-2.0View on GitHub
GitHub Actions, Renovate, the two-branch release model, signing, and promotion. Use when changing workflows, dependency policy, or releasing.
- Installs packages
In this repository6 other files it gives its agents.
- AGENTS.mdAGENTS.md
- buildSkill
- customizeSkill
- onboardingSkill
- overviewSkill
- troubleshootingSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 107
Wait for validate and the image build.
≈ “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.
Files
CI
Workflows
| Workflow | Trigger | Does |
build-image.yml | push to main or stable, dispatch | Builds, signs, and pushes the image. |
execute-release.yml | push to stable | Promotes the candidate digest. Does not rebuild. |
promote-main-to-stable.yml | daily schedule, dispatch | Opens the squash promotion PR and runs the release gate on it. |
sync-stable-to-main.yml | push to stable | Merges stable hotfixes back into main. |
pr-validation.yml | pull request | The validate check: shellcheck and hadolint. |
validate-brewfiles.yml | pull request | Brewfiles, without evaluating them. |
validate-flatpaks.yml | pull request | Flatpak preinstall files against Flathub. |
validate-justfiles.yml | pull request | just check. |
validate-renovate.yml | pull request | Renovate config. |
unit-tests.yml | push, pull request | The bats suite. |
renovate.yml | schedule, config change | Runs Renovate. |
clean.yml | schedule | Deletes images older than 90 days. |
Most are thin callers of reusable workflows in projectbluefin/actions.
The release model
main publishes :stable-testing. stable never rebuilds: promotion is a
squash PR from main to stable, and execute-release.yml copies the digest
:testing resolves to. The README owns the release table and the promotion
gate's current limits.
The factory reusable puts its release gate and its auto-merge enrollment behind
one input, enqueue_promotion. A personal repository cannot enroll — there is no
merge queue, and gh pr merge --auto refuses without a merge method — so
enrollment is off, and promote-main-to-stable.yml runs the gate itself in its
own gate job to keep the pre-merge check. That gate resolves :testing when it
runs, so it attests the current candidate. The binding comes from
execute-release.yml passing source_branch: main, which makes the reusable
refuse to promote at all once main has moved past the promotion commit; a
manual dispatch is exempt, because that path is deliberate recovery.
The same reusable builds the squash branch, and it stages deletions with
git diff --diff-filter=D. Git reports a moved file as a rename, so a path main
moved survives on its old path and the branch's tree stops matching main's —
the state the guard above refuses, but only after the PR is merged.
repair-promotion-branch in promote-main-to-stable.yml rebuilds the branch from
main's tree when it has drifted, and the validate check fails a promotion PR
whose tree does not match main. The sweep belongs to projectbluefin/actions;
the one-line fix there is --no-renames.
Signing
Keyless OIDC via Cosign. There are no keys to generate or store; the workflow
needs id-token: write and packages: write. Unsigned images fail the promotion
gate. The README has the command to verify an image.
The promotion gate is the only enforcement point. Nothing checks the signature
on an installed system, so 00-image-info.sh writes an unverified update
transport (ostree-unverified-image:docker://…) and the README says so.
ostree-image-signed: would send the client to /etc/containers/policy.json,
which Common supplies with no scope for this namespace — it would verify against
the "" catch-all, insecureAcceptAnything, and report success having checked
nothing. Adding a scope does not rescue it while signing stays keyless:
containers/image matches a Fulcio certificate on subjectEmail alone
(mandatory, exact, with a standing FIXME for URI SANs in
signature/fulcio_cert.go), and a GitHub Actions certificate names its workflow
in a URI SAN with no email to match. Device-side verification is a key-based
signing change first, a policy change second.
tests/contract/image-signing_test.bats fails if either side moves alone.
The identity regexp the release workflows pass to the reusables is scoped with
github.repository, not github.repository_owner. Matching the owner and then
any repository accepts a signature minted by any repository in the org, and
github.repository keeps the scope correct in a fork without hardcoding it.
Renovate
Self-hosted through projectbluefin/actions, running every six hours. It pins
GitHub Actions to SHAs and updates image digests. The policy lives in
.github/renovate.json: updates below a major automerge once checks pass;
majors wait for a pull request — except quay.io/fedora-ostree-desktops/*,
where cross-major bumps do not open a PR at all (the rule is enabled: false).
A Fedora major rebase for that namespace is a deliberate manual step: bump the
tag in Containerfile by hand when the next major is released and validated.
Renovate needs the RENOVATE_TOKEN secret and auto-merge enabled. Both are
onboarding steps. The secret is optional: with it unset the workflow logs a skip
and the run stays green, which is how upstream runs, where an org-wide app does
the work instead. The check sits in its own token job because a job that calls
a reusable workflow cannot hold steps, and jobs.<job_id>.if cannot read the
secrets context — secrets in a job-level if is a parse error, not a skip.
Automerge deliberately covers GitHub Actions SHA bumps, which reverses a guard
upstream kept. Those SHAs run in jobs holding packages: write,
id-token: write, and secrets: inherit, and PR builds are disabled, so a bump
merges with only shellcheck, hadolint, and the test suite having run. Putting the
guard back is one rule — matchManagers: ["github-actions"] with
automerge: false.
Making a change
- Open a pull request against
main. - Wait for
validateand the image build. - Merge.
mainpublishes:stable-testing. - Review and merge the promotion PR to publish
:stable.
Apt mirror resilience
The unit-tests.yml Install bats step runs apt-get against the runner
image's stock Ubuntu mirrors. A slow mirror can leave apt waiting past the
10-minute job timeout, cancelling a run whose diff cannot have caused the
stall (issue #497, observed on PR #492 head 5769c24, job 112944421448). The
step fronts both apt-get update and apt-get install with timeout 180,
passes -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30 -o
Acquire::Retries=2 to each so a stalled socket fails fast from either
half, and --no-install-recommends to skip the bats-doc package the
workflow never reads. The wall-clock cap is what catches a slow-but-alive
mirror; the per-call timeouts only fire on inactivity.
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
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.

