Repository navigation
Description
Finding
infra/github-backup/systemd/drain-wrapper.sh — the systemd drainer's only Bitwarden credential path for the github-backup estate mirror — had its credential-loading logic changed twice in one evening, and none of it is tested:
- PR github-backup: portable Bitwarden env in drain wrapper #3222 (github-backup: portable Bitwarden env in drain wrapper #3222, commit a0d2da4) replaced the hard
source ~/tools/bws-env.shwith a three-way branch (sandbox~/tools, laptop~/hatch/tools, raw access-token file). - PR github-backup: drain wrapper bws access fix (laptop token store) #3226 (github-backup: drain wrapper bws access fix (laptop token store) #3226, commit 6361b89) replaced that again: export
~/.config/bws/access-tokenwhen present, then probebws secret listand only on failure source abws-env.shfrom either candidate path, with sourcing failures masked (source "$f" || true).
Both PRs touched only drain-wrapper.sh (verified from both merge commits' file lists). On current main (3adad8fc9e2e) the fallback logic is at drain-wrapper.sh:11-18, and there is no test for the wrapper anywhere in the repo: infra/github-backup/systemd/ contains no test file (directory listing verified), and a code search for drain-wrapper returns only nixos/home/github-backup.nix and the drain service unit.
Why it matters
The fallback branch is precisely the code that runs only on a machine where the primary credential path has already failed — the situation both PRs were written for (the laptop drain). Its failure modes are silent or late:
- If bare
bwsfails andbws-env.shis missing or itself fails, the|| truemask lets the script continue to the Pythoneval, which then dies with a raw traceback/KeyError at timer fire time, not at deploy time. - Path drift (the wrapper already moved conventions once:
~/toolsvs~/hatch/toolsvs~/.config/bws) breaks the fallback without any signal until a drain run fails and the estate mirror silently stops draining.
The sibling scripts in this fleet's backup tooling carry stubbed tests (e.g. pkgs/cold-store-reaper/tests/); the drain wrapper — which handles live credentials — has none.
Acceptance criteria
- A stubbed shell test for
drain-wrapper.sh(fake HOME, stubbws, stub drain target — no real Bitwarden, no network) covering all four branches:BWS_ACCESS_TOKENalready set in the environment → no token-file export, nobws-env.shsourcing, drain proceeds.- Token file present at
~/.config/bws/access-token→ exported, barebwssucceeds, no fallback sourcing, drain proceeds. - Bare
bws secret listfails and abws-env.shexists (each candidate path) → it is sourced, credentials load, drain proceeds. This is the PR github-backup: drain wrapper bws access fix (laptop token store) #3226 branch that currently has zero coverage. - No working credential path → the wrapper exits non-zero before invoking the drain, with a comprehensible error.
- The test runs in the same place/convention as the repo's other shell-script tests and passes.
- Production behavior of
drain-wrapper.shis unchanged unless a branch is shown broken by the new test, in which case the fix is part of this issue.
Found by pr-diff-review lane B reviewing PRs #3222 and #3226 (batch 3217–3251, 2026-11-03). Cross-checks that this is not already covered: open tracker issue #3215 (estate mirror system) does not mention wrapper tests; issue #3240 covers non-atomic state JSON writes in the fetch/drain scripts, a different defect.
Activity
dezren39 commentedon Nov 4, 2026
🤖 Agent note · picked up
dezren39 commentedon Nov 4, 2026
🤖 Agent note · filed
packet-5222-triage.jsonin the goal's hidden_files; evidence in the issue body.dezren39 commentedon Nov 4, 2026
🤖 Agent note · triaged
f486f2aab6a98cf709a4b37659441f318eafa0f8). Fresh reads this run:infra/github-backup/systemd/drain-wrapper.shon main carries exactly the filed credential logic: token-file export first, then a probe of the bare credential CLI, and only on failure a masked, non-fatal source of a fallback env script from either candidate path (lines 11–18, matching the issue's evidence).infra/github-backup/systemd/on main contains only the wrapper, the service/timer units, andinstall-units.sh— no test file.small_fixqueue task by this triage (see the queue task id in the completion of task 8954). Production behavior stays unchanged unless the new test demonstrates a broken branch.dezren39 commentedon Nov 4, 2026
🤖 Agent note · done — triage task 8954 complete: issue #5222 confirmed at main
f486f2aab; the four-branch stubbed test work is enqueued as task 8957 (queue repo-health-code-pilot). Issue #5222 stays open under task 8957.dezren39 commentedon Nov 4, 2026
🤖 Agent note · correction
dezren39 commentedon Nov 4, 2026
🤖 Agent note · handed off
opencode, so this lane hands off per runbook §1b — the opencode claimant launches the bound session.