web: every dry-run reports a phantom bitborg-web restart (check-mode fabricates command results) #294
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra#294
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "%!s()"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Summary
Every
--check --diffdry-run ofsite.ymlreports a bitborg-web restart that a real run doesnot perform. The web role's restart decision is computed from two
commandprobes, and undercheck mode those probes do not run — Ansible registers a fabricated result in their place, so
the decision is made from fiction.
Found while gating an unrelated docs-only change (#292/#293): the dry-run came back
changed=1,which looked like real pending drift and had to be chased down before the apply gate could be
cleared.
Mechanism
A skipped
commandunder--checkdoes not register "no data" — it registers plausible success:Both halves of that are load-bearing here, in opposite directions:
stdout: ""can never equalgit.gitborg.se/gitborg/gitborg-web:latest, so the drift comparisonalways resolves
state: restarted→ achangedthat never materialises.rc: 0means thewhen: web_image_present.rc == 0guards take the success branch regardless, soa dry-run silently assumes the image is published even when it is not — the failure the
"Note when the bitborg-web image is not yet published" task exists to report.
Note the existing
| default('')guard onstdoutis not what saves or breaks this — the value isregistered as
""outright, so the default never fires.Why it matters
The apply procedure requires accounting for every
changedtask, precisely so that real drift(a merged-but-unapplied PR) is not lost in noise. A permanent phantom
changederodes that: ittrains the reader to expect one unexplained change and wave it through. Verified against the host
that no restart was actually pending — the running container was already on the expected ref.
Fix
check_mode: falseon the two probes. Both are strictly read-only (podman image exists,podman container inspect) and already carrychanged_when: false/failed_when: false, sorunning them under check mode is safe and makes the dry-run honest.
systemctl --user reset-failedin the same block is deliberately left skipped — it mutatesstate and has no business running during a dry-run.
Verification
Scoped dry-run (
--check --diff --tags web) before and after:skippingok(really running)skippingok(really running)changedokchanged=1changed=0Possible follow-up
Other roles were checked and do not share the drift-comparison shape, so this is web-specific
today. The general trap is not: any
when:/state expression derived from acommandregister isreading fabricated values under
--check. Worth a sweep for read-only probes that should carrycheck_mode: false, and worth a line in the apply procedure so the next person recognises thepattern instead of re-deriving it.
web: every dry-run reports a phantom gitborg-web restart (check-mode fabricates command results)till web: every dry-run reports a phantom bitborg-web restart (check-mode fabricates command results)