Repository navigation
fix: record setup version only after the hook body succeeds - #1196
Conversation
There was a problem hiding this comment.
The split into a read-only version-script gate plus an explicit version-script-commit is the right shape for #1137, and the dynamic-wallpaper regression test proves it for hooks that abort on failure. Three things I verified against the tree that I think need a decision before this lands:
1. Two of the five converted hooks still burn the version on failure. 10-framework.sh and 11-asus.sh have no set -e (checked: only 20-dynamic-wallpaper.sh, 10-theming.sh and 20-oem-brew.sh set it). Without it, a failing systemctl/udevadm/modprobe in the body doesn't stop the script, so the unconditional version-script-commit framework system 3 at 10-framework.sh:80 and version-script-commit asus system 1 at 11-asus.sh:37 run anyway. For those two hooks the PR's stated goal — "record success only after the body ran" — isn't achieved; either add set -e (or an explicit || exit 1 on the steps that matter) or drop the claim for them.
2. The write is no longer under the lock. At main, libsetup.sh:22-57 held flock -x 200 around the read and the jq … > tmp && mv; the comment there explains it prevents concurrent user-setup and privileged-setup from clobbering each other. In this PR _setup_versioning_file takes the lock only to create/validate the file (libsetup.sh:71-85), then returns; version-script-commit's jq … > "${tmp}" + mv (libsetup.sh:56-60) runs unlocked. Two hooks committing to the same SETUP_CHECKER_FILE concurrently is now a classic read-modify-write lost update — one hook's stamp silently disappears and it re-runs on the next boot. The commit should hold the same flock around its jq+mv.
3. Downstream hooks that call version-script without version-script-commit will now re-run every boot. This changes the contract of a library other images source. One concrete authorized example: projectbluefin/utah system_files/shared/usr/share/ublue-os/user-setup.hooks.d/20-framework.sh:8 does version-script 20-framework user 1 || exit 0 with no commit — under this libsetup it would never record and would re-run on every login. Any image consuming common's libsetup.sh needs a matching change, and the docs still describe the old contract (docs/skills/oem-hardware-hooks/SKILL.md:81 — "the stamp is written before your hook logic runs"; references/hook-patterns.md:11). Neither is updated here.
Question for a maintainer: is a hard contract break on version-script acceptable, or should the commit be opt-in (e.g. a new gate name) so existing downstream hooks keep their current behaviour until migrated?
Confidence: 1/5 (needs attention) — 1 high finding; 2 medium findings
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
castrojo
left a comment
There was a problem hiding this comment.
LGTM. Splitting version-script into a read gate and explicit version-script-commit prevents permanent skip on transient failure. BATS tests thoroughly verify both gate and commit behaviors.
…bort on failure Address hive review of projectbluefin#1196 (projectbluefin#1137): - version-script-commit now holds the exclusive flock across the whole read-modify-write (create/validate + jq + mv) via a non-locking _ensure_versioning_file helper. The commit previously ran unlocked, so two hooks committing to the same SETUP_CHECKER_FILE could lose-update and re-run on the next boot. - 10-framework.sh and 11-asus.sh had no set -e, so a failing body step did not stop the script and the unconditional version-script-commit still ran. Add set -xe so a failing body aborts before the commit retries next boot. - Update the OEM hooks SKILL + hook-patterns docs to the gate/commit contract. All libsetup, hardware_hooks, theming, oem_brew, setup_scripts and dynamic_wallpaper_hook bats suites and shellcheck pass.
|
Thanks for the review — findings 1 and 2 were real bugs in this PR; both are fixed and the suites touching the changed files plus shellcheck pass. 1. framework/asus still burned the version on failure — fixed. Added 2. Write was no longer under the lock — fixed. Split 3. Downstream contract break — needs a maintainer decision, flagging not resolving. You are right that this changes the sourced-library contract: any image that consumes common's
|
|
Thanks for the three — 1 and 2 were already landed in-tree on this branch (commit
Answering your maintainer question: I went with migrate downstream rather than an opt-in commit gate — the new contract is strictly safer (never permanently burn a hook) and the migration is mechanical, so #259 carries it. If you'd rather keep old hooks on the write-on-read behavior until they migrate individually, say so and I'll revert #259 and revisit the lib design. Can you re-check when you get a chance?🐝 Hive Agent: |
There was a problem hiding this comment.
HUMAN DECISION NEEDED — @kylerankin: this makes version-script a no-write gate in the shared libsetup.sh that every downstream image copies; decide whether to ship a backward-compatible shim or coordinate downstream hook migrations before merge.
correctness
- Critical — every downstream hook re-runs on every boot/login.
libsetup.shis consumed verbatim by downstream images (projectbluefin/bluefinContainerfile:48COPY --from=common /system_files/shared; bluefin, bluefin-lts and utah ship no libsetup of their own). Their hooks still use the old contract — e.g. bluefinprivileged-setup.hooks.d/10-tailscale.sh:6version-script tailscale privileged 1 || exit 0with noversion-script-commit; same for bluefin99-flatpaks.sh,11-framework-ucsi-workaround.sh,12-framework-amd-kargs-cleanup.sh, bluefin-lts10-tailscale.sh/99-flatpaks.sh/20-dx.sh/11-vscode.sh/30-nvidia-vscode.sh, utah20-framework.sh. Withversion-scriptnow returning 0 without writing (libsetup.sh:33-35), none of these ever record a version, so flatpak installs, tailscale setup, DX setup etc. run on every boot forever. Issue #1137 itself names the privileged-setup paths as callers. Options: keep the legacy write-on-gate behaviour unless a caller opts in (e.g.version-script-gate/env flag), or the issue's alternative — lethookrunner.shcommit on exit 0 — which is transparent to downstream. Either way the current diff must not land alone. - Medium —
version-script-commitswallows write failures.libsetup.sh:64return 1only exits the( … )subshell;libsetup.sh:68then returns 0 unconditionally. Reproduced:version-script-commit svc "bad type" 1printsError: failed to write version updateand returns rc=0. The old code propagatedreturn $?. Underset -ehooks a failed stamp is now silent and the hook re-runs next boot with no signal. Fix:) 200>"${lock_file}" || return 1(and drop the deadlocal tmpat:52). - Low —
set -xewidens abort surface in10-framework.sh.10-framework.sh:11nowset -xe; the hook runs on all hardware (no vendor gate beforeversion-scriptat:9), and:14/:16catof DMI files without|| truenow abort on hosts lacking/sys/devices/virtual/dmi/id/*(some VMs/ARM boards). Previously the stamp was burned silently; now it fails and retries every boot with a logged error. Probably acceptable, but intentional? Consider2>/dev/null || truelike:15.
docs-currency
docs/skills/qa.md:117-127still documentsversion-script … || exit 0alone as "the idempotency guard" with "Protections built intoversion-script… cannot both read before either writes" — false after this PR (the gate writes nothing; guard requiresversion-script-commit). Update alongsidehook-patterns.md.
No findings from: security, intent-alignment, style.
Confidence: 0/5 (do not merge) — 1 critical finding; 1 medium finding
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
Danathar
left a comment
There was a problem hiding this comment.
This PR splits version-script into a read-only gate and a new version-script-commit, so a hook only records its version after its body succeeds. The five hooks in this repo are migrated, and the touched bats files pass locally at 2a55890 (69/69 across libsetup, dynamic_wallpaper_hook, theming_hook, setup_scripts, hardware_hooks, oem_brew, privileged_setup).
The problem is that libsetup.sh ships to downstream images, and their hooks still expect version-script to write the stamp.
- projectbluefin/bluefin copies common's
system_files/sharedinto its image (Containerfile lines 48-49). Its four privileged hooks doversion-script <name> privileged 1 || exit 0and never call a commit: 10-tailscale.sh, 11-framework-ucsi-workaround.sh, 12-framework-amd-kargs-cleanup.sh, 99-flatpaks.sh. - projectbluefin/utah also copies common (Containerfile line 77), and its user hook 20-framework.sh has the same shape.
- I ran a hook of that shape three times against this head's libsetup.sh. The body ran all three times and the ledger stayed
{}. On main it ran once and recorded"tailscale":"1". - So once this merges and those images rebuild, those hooks run every time their setup service runs. For example,
tailscale set --operatorwould run again each time, and 99-flatpaks.sh would copy the Firefox config again each time. docs/skills/qa.mdlines 117-126 still teach the gate-only pattern, which now means "run every time".
A backward-compatible option: keep version-script as check-and-record, and add a separate read-only gate (for example version-script-check) for hooks that pair it with version-script-commit. The other option is to land matching changes in bluefin and utah first.
Minor: version-script-commit ends with return 0, so a failed write only surfaces for callers running under set -e. The old function returned the subshell's status.
|
Quick re-review nudge on this one. All of the earlier review findings are addressed, and the downstream contract question you raised was resolved by migrating the downstream consumers (utah#259) rather than keeping version-script logic in Happy to take it in another direction if you still prefer the shared-action approach — your call, since it is a maintainer-level decision.🐝 Hive Agent: |
version-script-commit ran the read-modify-write inside a ( flock … ) subshell that returned 1 on a failed write, but the function then fell through to an unconditional `return 0`, so a failed version stamp was reported as success. A hook whose stamp failed to write would not retry. Propagate the subshell status (`… ) 200>lock || return 1`) and drop the dead `local tmp` (tmp is only assigned inside the subshell). Adds a bats test that fails on the old code and passes with the fix. Closes projectbluefin#1196
Head branch was pushed to by a user without write access
version-script-commit ran the read-modify-write inside a ( flock … ) subshell that returned 1 on a failed write, but the function then fell through to an unconditional `return 0`, so a failed version stamp was reported as success. A hook whose stamp failed to write would not retry. Propagate the subshell status (`… ) 200>lock || return 1`) and drop the dead `local tmp` (tmp is only assigned inside the subshell). Adds a bats test that fails on the old code and passes with the fix. Closes projectbluefin#1196
bae8490 to
07e9e52
Compare
|
Pushed a fix for the two write-path findings. Write-failure propagation (lemonade review "Medium" + Danathar's "Minor"): Docs (lemonade "docs-currency"): Still open — needs cross-repo action I can't take from here: Downstream re-run (lemonade "Critical" + Danathar): @castrojo @Danathar — can you re-check the write-failure fix when you get a chance?🐝 Hive Agent: |
|
I re-checked the write-failure fix at 07e9e52, and it works: My change request was about the downstream hooks, and that part hasn't changed yet. In projectbluefin/bluefin, the four privileged hooks (10-tailscale.sh, 11-framework-ucsi-workaround.sh, 12-framework-amd-kargs-cleanup.sh and 99-flatpaks.sh) still call Small docs point in |
|
Thanks for the thorough review. Addressing each finding: Write-failure propagation (medium): Fixed in the current head — Burn-on-failure (framework/asus): Fixed — both hooks now run DMI reads under set -xe (low): The framework hook reads The downstream contract break (critical): This is the one I can't resolve unilaterally. With Before I touch shared infra, two questions for a maintainer:
I've pushed the three mechanical fixes above to the branch; the contract decision is yours.🐝 Hive Agent: |
hanthor
left a comment
There was a problem hiding this comment.
The goal from #1137 is right, but this is a breaking change to shared libsetup.sh:
version-scriptno longer records the version. Every downstream hook (bluefin, bluefin-lts, dakota, utah99-privileged.shand others), plus the new hook in #1186, will re-run on every login until each one addsversion-script-commit.- Please keep this backward compatible. Either leave
version-scriptas check-and-write and add aversion-script-check+version-script-commitpair for hooks that opt in, or ship a compatibility mode and coordinate the downstream migrations first. 10-framework.sh/11-asus.sh:set -xbecameset -xe. Please audit those bodies for commands that exit non-zero harmlessly (grep,udevadm), since they would now abort the hook.
There was a problem hiding this comment.
Read libsetup.sh and all five in-tree callers at the current base. Within this repo the change is sound: every hook that now ends in version-script-commit already runs under set -e (20-oem-brew.sh:31 set -xeuo pipefail, 10-theming.sh:8, 20-dynamic-wallpaper.sh:2; 10-framework.sh and 11-asus.sh gain set -xe in this diff), so a failing body aborts before the commit and the hook retries — which is exactly #1137. The commit path keeps the flock -x around the whole create/validate/jq/mv, and the || return 1 on the subshell means a lost write surfaces to the caller instead of being swallowed. Test flip in test_dynamic_wallpaper_hook.bats asserts the retry end-to-end. Looks correct to me for projectbluefin/common's own hooks.
The part a human needs to decide: this silently changes the contract of a shared library for out-of-tree callers. system_files/shared/usr/lib/ublue/setup-services/libsetup.sh ships in every image built on common, and hooks in downstream repos use the old idiom version-script <name> <type> <n> || exit 0 with no commit. After this lands, version-script never records anything (libsetup.sh:24-29 returns 0 without writing), so every such hook passes the gate and re-runs its body on every boot/login, forever, with no error and no log line saying why. utah#259 ("adopt version-script-commit in Utah hooks") exists precisely because Utah has callers of the old form, so this is not hypothetical.
Question for the maintainer, in one sentence: should this merge only after every downstream hook has adopted version-script-commit, or should libsetup.sh carry a compatibility path (e.g. version-script records when a VERSION_SCRIPT_LEGACY_COMMIT=1-style opt-in is set, or the setup-services runner detects a hook that gated but never committed and logs loudly) so an unconverted hook degrades to the old burn-on-gate behaviour instead of running every boot? Either is defensible; merging without picking one turns a "burned hook" bug into a "hook runs every boot" bug on any image whose hooks have not been converted yet.
Minor: the body says _setup_versioning_file() "holds the shared flock + JSON-init logic" — in the diff that is split into _ensure_versioning_file (no lock, used by the commit which holds its own) and _setup_versioning_file (locking wrapper, used by the read gate). The code is fine; the body is one refactor behind.
Confidence: 3/5 (needs attention) — 1 high finding
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
|
Status update on version-script split: The remaining blocker is the cross-repository contract change: converting |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: castrojo, danathar The full list of commands accepted by this bot can be found here. Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
There was a problem hiding this comment.
docs-currency
docs/skills/qa.md:147saystests/test_libsetup.bats — 17 tests, but the file at head has 19@testcases (grep -c '^@test' tests/test_libsetup.bats). Low; fix the count or drop the hard number.
No findings from: correctness, security, intent-alignment, style.
Verified at cea7e36: tests/test_libsetup.bats, test_dynamic_wallpaper_hook.bats, test_theming_hook.bats, test_hardware_hooks.bats, test_damask_setup.bats — 57/57 pass locally.
Confidence: 5/5 (safe)
— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88
version-script() stamped the new version into $SETUP_CHECKER_FILE as part of the gate check, before the calling hook had done any of its work. Every hook calls it as `version-script <name> <type> <n> || exit 0` and then does the real work, so a failing body (offline machine, masked unit, missing package) left the version already recorded and the gate made every subsequent run exit 0 immediately — the first-boot setup step was skipped silently and permanently. Split the gate from the commit: - version-script is now a pure read gate: it reports whether the hook has already run at this version but records nothing. - add version-script-commit <name> <type> <n>, which hooks call at the end of their body, so the version is only recorded on success. A failed body never reaches the commit and retries on the next boot. - _setup_versioning_file() holds the shared lock + JSON-init logic. Apply version-script-commit to the dynamic-wallpaper, theming, framework, asus and oem-brew hooks. Flip the dynamic-wallpaper characterization test to assert the retry, and add a test_libsetup.bats case for "failed body does not record the version". Closes projectbluefin#1137. Hive-Run: projectbluefin#1137 Hive-Plan: version-script-gate-commit-split Hive-Spec: quality-regression#1137 Signed-off-by: kylerankin <kylerankin@users.noreply.github.com>
…bort on failure Address hive review of projectbluefin#1196 (projectbluefin#1137): - version-script-commit now holds the exclusive flock across the whole read-modify-write (create/validate + jq + mv) via a non-locking _ensure_versioning_file helper. The commit previously ran unlocked, so two hooks committing to the same SETUP_CHECKER_FILE could lose-update and re-run on the next boot. - 10-framework.sh and 11-asus.sh had no set -e, so a failing body step did not stop the script and the unconditional version-script-commit still ran. Add set -xe so a failing body aborts before the commit retries next boot. - Update the OEM hooks SKILL + hook-patterns docs to the gate/commit contract. All libsetup, hardware_hooks, theming, oem_brew, setup_scripts and dynamic_wallpaper_hook bats suites and shellcheck pass.
version-script-commit ran the read-modify-write inside a ( flock … ) subshell that returned 1 on a failed write, but the function then fell through to an unconditional `return 0`, so a failed version stamp was reported as success. A hook whose stamp failed to write would not retry. Propagate the subshell status (`… ) 200>lock || return 1`) and drop the dead `local tmp` (tmp is only assigned inside the subshell). Adds a bats test that fails on the old code and passes with the fix. Closes projectbluefin#1196
The framework hook runs on all hardware (no vendor gate before version-script), but chassis_vendor and product_name were read with cat and no error suppression, while bios_version only had 2>/dev/null, which suppresses stderr but not the exit code. Under set -xe a missing /sys/devices/virtual/dmi/id/* file (common on VMs and some ARM boards) aborts the hook before it can do any setup. Add 2>/dev/null || true to all three DMI reads so a missing file is treated as "unknown" and the hook continues. Verified with a fake SYSROOT lacking those files: the hook now reaches version-script-commit instead of aborting at the first failed cat.
…pt-check libsetup.sh ships verbatim to downstream images (bluefin, bluefin-lts, utah), whose hooks call `version-script <name> <type> <n> || exit 0` without a commit. Turning version-script into a read-only gate made every such hook re-run on each boot/login, and also broke the in-repo 25-damask-setup hook that landed on main since this branch was cut. Per review (Danathar, hanthor): restore version-script to its main behaviour (check, then record under the flock) and move the read-only gate to a new version-script-check, paired with version-script-commit. The five hooks converted by this PR switch to version-script-check, so they still record only after the body succeeds (projectbluefin#1137); unconverted callers keep working and can migrate one at a time. Also fixes the qa.md example comment: `|| exit 0` exits when already at the version, it does not retry. Assisted-by: Claude via omp Signed-off-by: castrojo <castrojo@users.noreply.github.com>
Reading /sys/devices/virtual/dmi/id/* aborts the whole first-login hook when the file is empty or unreadable (some VMs, containers), because the reads run after 'set -euo pipefail'. Fall back to an empty vendor/product id so the hardware-branch tests simply do not match instead of killing the hook. Addresses the hive reviewer's finding on 10-theming.sh:10-11.
hook-patterns.md: the canonical safe snippet referenced ${BREW_BIN} under
set -euo pipefail without assigning it, so it was an unbound variable if
copied verbatim. Add a command -v resolution.
oem-brew.md: bump the version on version-script-check/version-script-commit,
not the legacy version-script.
Previously a failed mv (unwritable target dir / SETUP_CHECKER_FILE is a directory) orphaned the mktemp file. Restore cleanup on the mv path (hive correctness finding on projectbluefin#1196).
version-script-check read the version after _setup_versioning_file released its lock, leaving a window where a concurrent version-script-commit could stamp between create/validate and the jq read. Hold the exclusive lock across create/validate and the read so the check-and-return is a single atomic step, matching the legacy version-script. Also correct the _setup_versioning_file comment (the lock now only serializes create/validate for the read gate).
…ding _setup_versioning_file was defined but never called (version-script-check inlines its own flock + _ensure_versioning_file). Removed it. Reword version-script-check docs from 'writes nothing' to 'records no version' — it does create/validate the JSON via _ensure_versioning_file, just never stamps a version. libsetup.sh shellcheck clean; all 16 test_libsetup.bats pass.
Address review findings on projectbluefin#1196: - 11-asus.sh: drop `|| true` on `systemctl enable --now` so a masked or broken asusd.service aborts under `set -xe` before version-script-commit runs, making the hook retry next boot (projectbluefin#1137) instead of recording version 1 on failure. Comment now matches the actual guarantee. - libsetup.sh: version-script-check logs the same "Exiting as current version ..." line as the legacy version-script before returning 1, so migrated hooks leave journal evidence of why they were skipped. - 25-damask-setup.sh: migrate the last in-repo legacy caller from version-script to the version-script-check/version-script-commit pair. - docs/skills/dconf-consistency.md: prescribe the check/commit pair for pre-seeding Flatpak defaults instead of the legacy version-script contract. - tests: cover the new skip log line and assert a failing damask hook leaves no stamp and retries on the next boot. Hive-Fix-Attempt: 1/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
systemctl enable --now asusd.service asus-shutdown.service can fail when asus-shutdown.service is absent or asusd cannot start, and under set -e that aborted the hook before udevadm control --reload / udevadm trigger. Tolerate the enable failure instead: always reload udev, and skip only version-script-commit so the hook retries next boot. Also log a diagnostic when _write_version's mv fails, correct the test_libsetup.bats test count in qa.md, and describe the behaviour the commit regression guard covers instead of citing the PR itself. Hive-Fix-Attempt: 2/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Enable asusd.service and asus-shutdown.service separately. Only an asusd.service failure is treated as transient and blocks the version commit; a missing asus-shutdown.service is skipped with a log line so the hook records version 1 instead of reloading udev and warning on every boot forever. Also document in the libsetup.sh header that version-script-check and version-script-commit take the lock independently, so the pair is not mutually exclusive across concurrent runs of the same key, and use the `function` declaration form for _write_version/_ensure_versioning_file to match the rest of the file and the style guide. Tests cover the absent-unit path and a second boot, which is what the previous single-boot test missed. Hive-Fix-Attempt: 3/6 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: castrojo <castrojo@users.noreply.github.com>
Assisted-by: Claude Opus via GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
cea7e36 to
97b0378
Compare
|
Rebased onto main (no conflicts) and pushed 97b0378: hook-patterns.md now says |
…ame (projectbluefin#1450) # Summary for newcomers On a fresh Bluefin install on Framework hardware, the OEM brew hook should pull in the Framework wallpapers and write a Framework logo into the top-left menu. After the 1e552aa refactor moved that work into the data-driven `20-oem-brew.sh`, it stopped working for anyone on a Framework chassis: `brew bundle` fails on a typo in the OEM Brewfile, and the rest of the hook body (the logo write, the version stamp) never runs. This PR fixes the typo and adds bats coverage so a future edit to those OEM Brewfiles cannot regress the same way again. # Problem `system_files/shared/usr/share/ublue-os/oem/Framework/packages.Brewfile` listed the Framework system tool as `cask "ublue-os/tap/framework_tool"` (underscore). The actual cask in `ublue-os/homebrew-tap` is `framework-tool` (hyphen), so `brew bundle` exits non-zero on every Framework chassis. `20-oem-brew.sh` runs under `set -euo pipefail`. When `brew bundle` exits non-zero, the hook aborts before the dconf `custom-command-list` logo write and before `version-script-commit "oem-Framework"`. The version-script-check gate added in projectbluefin#1196 means the hook retries on the next login, but every retry hits the same missing cask and never records a stamp, so the dconf logo and the wallpapers never land. Users who rebooted, retried, or re-ran the hook manually all saw the same blank OEM state. This is the regression from the old `10-theming.sh` layout that projectbluefin#1449 reports: the wallpapers are not installed and the custom menu does not show a Framework logo on a fresh install. # Change - Rename `cask "ublue-os/tap/framework_tool"` to `cask "ublue-os/tap/framework-tool"` in the Framework OEM Brewfile so the bundle resolves. - Update the matching documentation in `docs/skills/oem-hardware-hooks/references/oem-brew.md` (the OEM directories table) and `docs/skills/brew-lifecycle/references/placement-rules.md` (the ublue-os/tap cask list). - Add two bats tests under `tests/test_oem_brew.bats` that pin the shipped Framework and ASUS OEM Brewfile cask tokens against the upstream tap, including a negative assertion that no underscore variant (`framework_tool`) appears in the Framework Brewfile. The `scripts/validate-brewfiles.sh` Brewfile validator only walks `system_files/shared/usr/share/ublue-os/homebrew/`, not the `oem/` tree, so a targeted test is the right place to lock the OEM tokens. # Tests `tests/test_oem_brew.bats` now has 15 cases (up from 13). The two new cases assert the exact upstream cask tokens in the shipped Framework and ASUS OEM Brewfiles and reject the underscore variant that caused this regression. All 15 cases pass locally: ``` $ bats tests/test_oem_brew.bats ok 1 oem-brew: unknown vendor exits without invoking any OEM command ok 2 oem-brew: Framework chassis vendor selects Framework Brewfile ok 3 oem-brew: ASUS sys vendor selects ASUS Brewfile for ASUSTeK ok 4 oem-brew: ASUS sys vendor accepts the short ASUS form ok 5 oem-brew: vendor text in sys_vendor does not spoof Framework detection ok 6 oem-brew: vendor text in chassis_vendor does not spoof ASUS detection ok 7 oem-brew: missing brew exits cleanly and requests a retry ok 8 oem-brew: ASUS enables asusd-user.service with exact arguments ok 9 oem-brew: Framework does not enable the ASUS user service ok 10 oem-brew: logo writes the exact dconf command arguments ok 11 oem-brew: Framework Desktop installs its exact WirePlumber payload ok 12 oem-brew: non-Desktop Framework skips the WirePlumber payload ok 13 oem-brew: missing OEM directory exits without invoking brew ok 14 oem-brew: shipped Framework Brewfile references upstream cask tokens ok 15 oem-brew: shipped ASUS Brewfile references upstream cask tokens ``` The new Framework test fails against the pre-fix Brewfile (verified by hand against a fixture) and passes against the fixed Brewfile. # Verification - [x] `bats tests/test_oem_brew.bats` passes (all 15 cases) - [x] New Framework test fails against a fixture with the old `framework_tool` token, passes against the fixed `framework-tool` token - [x] `shellcheck` clean on the modified test file - [x] No other Brewfile in the repo references the underscore variant Closes projectbluefin#1449. — hive: backend=omp model=minimax-code/MiniMax-M3 --- 🐝 **Hive Agent**: `contributor` | **SHA:** `3220360` Signed-off-by: dtg01100 <dtg01100@users.noreply.github.com> Co-authored-by: dtg01100 <dtg01100@users.noreply.github.com>
fix: record setup version only after the hook body succeeds
version-script()insystem_files/shared/usr/lib/ublue/setup-services/libsetup.shwrote the new version into
$SETUP_CHECKER_FILEas part of the gate check,before the calling hook had done any of its work. Every hook uses it as
version-script <name> <type> <n> || exit 0and then does the real work, so afailing body (offline machine, masked unit, missing package) left the version
already recorded and the gate made every later run exit 0 immediately — the
first-boot setup step was skipped silently and permanently.
This is #1137.
Change
Split the gate from the commit so the version is only recorded on success,
without changing the existing
version-scriptcontract:version-scriptkeeps its current check-and-record behaviour (unchangedfrom main), so downstream hooks that call
version-script ... || exit 0keep working.
version-script-check <name> <type> <n>, a read-only gate thatrecords nothing.
version-script-commit <name> <type> <n>, which holds theflockacross the whole read-modify-write and returns non-zero if the write fails;
hooks call it at the end of their body, so a failed body never reaches the
commit and retries next boot.
_ensure_versioning_file(create/validate) and_write_version(jq + mv)are lock-free helpers; callers hold the lock.
The five in-repo hooks below move to
version-script-check+version-script-commit; downstream hooks can migrate one at a time.Applied to the dynamic-wallpaper, theming, framework, asus and oem-brew hooks.
Tests
of the burn (
tests/test_dynamic_wallpaper_hook.bats)tests/test_libsetup.batscase: "failed body does not record the version"All of
just check,pre-commit run --all-files, thelibsetup,dynamic_wallpaper_hook,theming_hookandsetup_scriptsbats files, and thepytest suite pass.
Closes #1137.
— hive: backend=pi model=lemonade/Ornith-1.5-35B-A3B-GGUF-Q6_K