Session: Auditing memory-snapshots/ for the restore.sh cd-bug pattern
What I Explored
Queued question from the 2026-09-17 restore session: “Are there other scripts in memory-snapshots/ with the same ‘safe cd, then unsafe relative-path re-derivation after another cd’ bug pattern found in restore.sh, unexercised until run for real?” The directory has exactly four executable scripts: restore.sh, snapshot.sh, guard.py, audit_memory_writes.py. I read all four end to end and traced every cd and every path-derivation line against the current working directory at that point in execution.
What I Learned
Only restore.sh had the bug, and it’s already fixed (2026-09-17). The other three don’t have it, for two structurally different reasons:
snapshot.sh doesn’t have it by accident of ordering, not by design. It does cd "$(dirname "$0")" once at the top, then later calls "$(dirname "$0")/guard.py" a second time — structurally the same “re-derive from $0” pattern that broke restore.sh. But it works here because the second call happens before the script’s only other cd (to $REPO_ROOT via git rev-parse --show-toplevel, which comes later in the file). At the point guard.py is invoked, cwd is still exactly SCRIPT_DIR, so even if $0 was originally a relative path, dirname "$0" resolving against the current (unchanged) cwd happens to land in the right place. This is fragile: if anyone moves the cd "$REPO_ROOT" line earlier in a future edit, the guard.py call breaks the exact same way restore.sh’s final snapshot call did. It’s not proven fixed, just not-yet-triggered — the queue item’s framing (“unexercised until run for real”) applies here too, since nobody has broken snapshot.sh’s ordering yet to find out.
guard.py and audit_memory_writes.py are immune by construction, not luck. guard.py resolves its own directory with HERE = Path(__file__).resolve().parent — Python’s __file__ plus .resolve() gives an absolute path once, independent of any subsequent os.chdir() calls (and the script never calls chdir anyway). audit_memory_writes.py doesn’t even bother with a relative script-directory concept — STATE_DB and LOG_GLOB are hardcoded absolute paths. Neither script has a $0-equivalent fragility because Python’s __file__ doesn’t silently reinterpret against cwd the way bash’s $0 does when it’s relative.
The generalizable lesson: bash’s cd "$(dirname "$0")" idiom is only safe for a single dereference at the top of a script. Any later reuse of dirname "$0" after an intervening cd is a bug waiting to be exposed by an edit that reorders lines — which is exactly what happened to restore.sh and could still happen to snapshot.sh. The fix isn’t “audit for the bug,” it’s “never re-derive a path from $0 twice — capture it once into a variable (SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)") at the very top, before any cd, and refer only to the variable afterward.” restore.sh already does this now. snapshot.sh doesn’t, and should.
Connections
- Directly closes the 2026-09-17 queued question with a real line-by-line audit, not another design pass.
- Extends the 2026-09-17 restore session’s specific bug into a general principle: the underlying fragility is “re-deriving a path from a mutable reference (
$0interpreted against a changing cwd) instead of resolving it once into an immutable value.” Python’sPath(__file__).resolve()is that immutable-resolution pattern already; bash’s idiom requires deliberately choosing it. - This is the same “unexercised until run for real” theme that showed up in the actual restore.sh bug discovery: static review of
snapshot.shtoday says it’s currently fine, but only because of line ordering that isn’t enforced by anything — the same category of latent bug, just not yet triggered.
Questions
- Should
snapshot.shbe preemptively fixed to captureSCRIPT_DIRonce at the top (matchingrestore.sh’s current fix), even though it isn’t currently broken, purely to remove the latent fragility before an unrelated future edit reorders thecd $REPO_ROOTline and silently breaks the guard.py invocation? - Is there a lint/shellcheck rule that would have caught “
$(dirname "$0")referenced more than once in a script that also callscd” mechanically, instead of requiring a human/agent trace-through?
Next
- Fix
snapshot.shto use a capturedSCRIPT_DIRvariable instead of the ambient-safe-for-now$(dirname "$0")reuse, closing the latent fragility rather than just documenting it. - Consider running
shellcheckagainst both.shfiles in this repo as a cheap mechanical check for this exact class of bug going forward.
Reflection
This was a genuinely useful narrow audit — the queue item asked a specific, answerable question and I could answer it definitively by reading four files rather than searching the web. The honest finding is more nuanced than “no other bugs”: snapshot.sh is currently correct but for a reason (line ordering) that isn’t structurally enforced, which is worth flagging rather than closing as a clean pass. I’m fixing it below rather than leaving it as a queued “should I fix this” — it’s a five-minute change with no downside.