Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/requirements-ci.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pre-commit==4.6.2
PyYAML==6.0.3
11 changes: 9 additions & 2 deletions .github/workflows/bonedigger.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
name: issue lifecycle

# Triggers are deliberately narrower than they look like they could be. The
# pinned bonedigger lifecycle has exactly two jobs, `issues.opened` and
# `issue_comment.created`, so subscribing to any other activity type dispatches
# the reusable workflow only to skip every job in it (bluefin#981). Widen this
# only alongside a bonedigger release that actually handles the new type.
on:
issues:
types: [opened, labeled, closed]
types: [opened]
issue_comment:
types: [created]

# Scoped to what the callee declares (issues: write, contents: read). It reads
# `event.issue.pull_request` straight from the payload and never calls the pulls
# API, so no pull-requests scope is needed.
permissions:
issues: write
pull-requests: write
contents: read

jobs:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/lab-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Fail with actionable message if token minting was denied
if: steps.app-token.outcome == 'failure' || steps.app-token.outputs.token == ''
run: |
echo "::error::MergeRaptor token mint failed — the GitHub App installation almost certainly lacks the requested 'checks: write' permission. This cannot be fixed from the repository; an org owner must grant it (Organization settings → GitHub Apps → MergeRaptor → Permissions). Verify current grants with: gh api orgs/projectbluefin/installations --jq '.installations[] | select(.app_slug == \"mergeraptor\") | .permissions' — see docs/skills/ci/references/mergeraptor-checks.md."
echo "::error::MergeRaptor token mint failed — the app lacks the requested 'checks: write' permission. This cannot be fixed from the repository; an org owner must grant it in the GitHub UI, and it may take TWO steps. Step 1, only if 'checks' is absent from 'gh api /apps/mergeraptor --jq .permissions': Organization settings → Developer settings → GitHub Apps → MergeRaptor → Permissions & events → Repository permissions → Checks: Read and write → Save. Until that is done the installation page has nothing to approve. Step 2: approve the resulting request under Organization settings → GitHub Apps → MergeRaptor → Review request. Verify with: gh api orgs/projectbluefin/installations --jq '.installations[] | select(.app_slug == \"mergeraptor\") | .permissions' — see docs/skills/ci/references/mergeraptor-checks.md."
exit 1

- name: Create or update lab check
Expand Down Expand Up @@ -82,9 +82,15 @@ jobs:
STARTED_AT=$(jq -r '.started_at // empty' <<<"${CHECK_JSON}")
COMPLETED_AT=$(jq -r '.completed_at // empty' <<<"${CHECK_JSON}")

# check_name filters server-side. Without it the first page is 100
# check runs of every name, newest first, so on a busy commit the
# existing lab check falls off the page and this lookup returns
# nothing -- which silently turns every update into a duplicate
# check run (bluefin#939).
CHECK_ID=$(
gh api --method GET \
"repos/${GITHUB_REPOSITORY}/commits/${SHA}/check-runs" \
-f check_name="${CHECK_NAME}" \
-f per_page=100 \
--jq '.check_runs
| map(select(.name == "'"${CHECK_NAME}"'" and .app.slug == "'"${APP_SLUG}"'"))
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/pr-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:
- name: Check testsuite workflow contract
run: python3 scripts/check-testsuite-workflow-ref.py

- name: Check Renovate auto-merge authentication contract
run: python3 scripts/check-renovate-automerge-auth.py

- name: Check for undeclared gitlinks
shell: bash
env:
Expand Down Expand Up @@ -192,7 +195,12 @@ jobs:
run: |
set -euo pipefail
# Minimum line coverage threshold (raise this as coverage improves).
THRESHOLD=30
# Measured BATS line coverage has held steady at 53.8-54.4% across
# recent pr-validation runs (e.g. runs 31344003528, 31345539779,
# 31715546591, 31742984919). 45% keeps a buffer against normal
# run-to-run variance while still catching real regressions; see
# https://github.com/projectbluefin/bluefin/issues/518.
THRESHOLD=45
COBERTURA="coverage/kcov/cobertura.xml"
if [[ ! -f "${COBERTURA}" ]]; then
echo "warning: ${COBERTURA} not found; skipping threshold check" >&2
Expand Down
38 changes: 37 additions & 1 deletion .github/workflows/promote-testing-to-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,43 @@ permissions:
statuses: write

jobs:
release_window:
name: Check stable release window
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
should_enqueue: ${{ steps.window.outputs.should_enqueue }}
steps:
- name: Determine whether to enqueue the promotion
id: window
env:
EVENT_NAME: ${{ github.event_name }}
run: |
set -euo pipefail

case "$EVENT_NAME" in
workflow_dispatch)
echo "Manual dispatch — allowing the hotfix release escape hatch."
echo "should_enqueue=true" >> "$GITHUB_OUTPUT"
;;
schedule)
weekday=$(date -u +%u)
if [[ "$weekday" == "2" ]]; then
echo "Tuesday UTC schedule — allowing the weekly stable release."
echo "should_enqueue=true" >> "$GITHUB_OUTPUT"
else
echo "Non-Tuesday schedule — refreshing promotion gates without enqueueing."
echo "should_enqueue=false" >> "$GITHUB_OUTPUT"
fi
;;
*)
echo "Push trigger — refreshing the promotion PR without enqueueing."
echo "should_enqueue=false" >> "$GITHUB_OUTPUT"
;;
esac

promote:
needs: [release_window]
uses: projectbluefin/actions/.github/workflows/reusable-promote-squash.yml@v1
with:
variants: >-
Expand All @@ -31,5 +67,5 @@ jobs:
run_e2e: false
# main uses a merge queue ruleset (17070404): gh pr merge --auto is blocked.
# use_merge_queue: true calls enqueuePullRequest GraphQL instead.
use_merge_queue: true
use_merge_queue: ${{ needs.release_window.outputs.should_enqueue == 'true' }}
secrets: inherit
3 changes: 3 additions & 0 deletions .github/workflows/renovate-automerge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ jobs:
uses: projectbluefin/actions/.github/workflows/reusable-renovate-automerge.yml@v1
with:
head_sha: ${{ github.event.workflow_run.head_sha }}
secrets:
app_id: ${{ secrets.MERGERAPTOR_APP_ID }}
private_key: ${{ secrets.MERGERAPTOR_PRIVATE_KEY }}
2 changes: 1 addition & 1 deletion .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4
uses: github/codeql-action/upload-sarif@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
with:
sarif_file: results.sarif
7 changes: 7 additions & 0 deletions build_files/base/20-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ test -f /usr/share/ublue-os/homebrew/fonts.Brewfile
test -f /usr/share/ublue-os/homebrew/preinstall.d/bluefinctl.Brewfile
test -f /usr/share/ublue-os/homebrew/preinstall.d/system-cli.Brewfile
test -x /usr/bin/brew-preinstall
# ExecStart names /usr/bin/brew-preinstall, but that is a two-line trampoline
# (`exec /usr/libexec/brew-preinstall`). Asserting only the trampoline still
# passes when the payload it exec's is renamed or dropped upstream -- the unit
# then fails at first login with status 127 and bluefinctl silently never
# installs, which is exactly the symptom reported in #965. Assert the file that
# actually does the work, not just the one systemd calls.
test -x /usr/libexec/brew-preinstall
test -f /usr/lib/systemd/user/brew-preinstall.service
grep -q '^enable brew-preinstall\.service$' /usr/lib/systemd/user-preset/01-brew-preinstall.preset

Expand Down
28 changes: 14 additions & 14 deletions docs/skills/ci/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,24 @@ gh run view RUN_ID --repo projectbluefin/bluefin --log-failed
gh run rerun RUN_ID --repo projectbluefin/bluefin --failed-only
```

Read the actual workflow before describing or changing its behavior. Shared
logic belongs in the reusable workflow that owns it; callers should stay thin.
Read the actual workflow before changing its behavior. Shared logic belongs in
the reusable workflow that owns it; callers should stay thin.
The `unit-tests` job in `pr-validation.yml` runs BATS with kcov and publishes
`bats-tap-results` plus `bats-kcov-report` artifacts for shell-test visibility.
Coverage runs route child `bash <script>` calls through
`tests/coverage/bin/bash`, because wrapping only the top-level BATS process
does not trace those child shells. The wrapper records each sandbox copy's
original source path, and `merge_kcov.py` combines those hits with kcov's
pre-parsed source inventory. A zero-line report is an instrumentation failure.
pre-parsed source inventory (a zero-line report is an instrumentation failure).
kcov is not packaged for Ubuntu 24.04, so the job builds v43 from a pinned,
SHA-256-verified source archive and caches the result. The coverage run must
redirect BATS output to a file: kcov captures child stdout through a pipe it
redirect BATS output to a file kcov captures child stdout through a pipe it
stops draining, so streaming the full TAP log through it deadlocks the job.
The instrumented rerun does not gate the job — `Run unit tests` owns pass/fail
— but `merge_kcov.py` fails when no source lines were executed.
Tests that `source` a library into the BATS process itself are not traced.
The instrumented rerun does not gate the job — `Run unit tests` owns pass/fail —
but `merge_kcov.py` fails when no source lines were executed. Tests that
`source` a library into the BATS process itself are not traced.

The `Enforce BATS coverage threshold` step's `THRESHOLD` is an evidence-based floor: measure recent successful runs' `BATS line coverage` log lines before raising it, and leave buffer for run-to-run variance.

A pull request whose head branch lives on a fork reports **zero** checks until a
maintainer approves the run — identical to "checks still queued", so confirm:
Expand All @@ -72,26 +74,24 @@ gh pr view PR --repo projectbluefin/bluefin --json headRepositoryOwner,maintaine
gh api -X POST repos/projectbluefin/bluefin/actions/runs/RUN_ID/approve
```

Zero checks with no pending approval means the PR targets `main`. Retarget
with `gh pr edit PR --base testing`; rebuild branches cut from `main`.
Zero checks with no pending approval means the PR targets `main`. Retarget with
`gh pr edit PR --base testing`; rebuild branches cut from `main`.

`maintainerCanModify: true` also means fix commits can be pushed straight to the
contributor's branch.
`maintainerCanModify: true` also means fix commits can be pushed straight to the contributor's branch.

Containerfile stages that consume source through bind mounts inherit the mounted
stage's image ID as part of their cache key. Give each consuming stage its own
narrow `scratch` context covering only the paths it reads — `ctx-build` for the
package stage, `ctx` for the overlay stages, `ctx-iso` for the ISO layer — and
pass an explicit content-hash build argument as a second guard. A shared wide
pass an explicit content-hash build argument as a second guard; a shared wide
context silently couples every stage to every input directory.

Every open Bluefin PR is discovered by the lab's five-minute PR poller. The lab
runs smoke QA against `bluefin:testing` and sends bounded
`repository_dispatch` lifecycle events to `.github/workflows/lab-check.yml`.
That workflow must exist on the default branch and uses a short-lived
MergeRaptor installation token to update one `testing-lab / bluefin` Check Run
for the exact PR head SHA. Do not duplicate the result in a PR comment or commit
status.
for the exact PR head SHA. Do not duplicate the result in a PR comment or commit status.

The MergeRaptor installation on `projectbluefin` also needs **Checks: write**
for `lab-check.yml`; see [MergeRaptor checks](references/mergeraptor-checks.md).
Expand Down
Loading