mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-05 15:09:42 +02:00
docs(test): name the real reason the suite could reach ~/.codeman
#356 stopped a bare suite run from overwriting the production `remote-hosts.json` by pointing `CODEMAN_DATA_DIR` at a throwaway dir, and it gated every case-tree delete on the temp HOME. Both changes are right; the explanation written next to them is not. It says `os.homedir()` reads /etc/passwd rather than `$HOME` on Linux, which would mean the temp HOME in test/setup.ts never worked. It does: libuv checks the env var before the passwd entry (measured: `HOME=/tmp/x node -e 'console.log(os.homedir())'` prints /tmp/x), and CLAUDE.md's testing section relies on exactly that. What bypasses the temp HOME is `CODEMAN_DATA_DIR` itself. `getDataDir()` reads it as an absolute override before it looks at `homedir()`, so one inherited from the shell (a second instance, a beta run) sends the whole suite at the real data dir. That is the case setup.ts now closes, and #371 names the same variable from the other direction. The comments in setup.ts, the `safeRmHomeTree` helper, the voice-routes and case-clone tests now say that, and the containment gate is described as what it is: defense in depth. CLAUDE.md's testing paragraph gets the same note so the next reader does not chase a homedir() bug that does not exist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qg6bcATm1pNNY4kQWGwzgu
This commit is contained in:
@@ -42,13 +42,14 @@ export function createDeferred<T = void>(): {
|
||||
* Delete a directory tree, but ONLY when it lives inside the test HOME.
|
||||
*
|
||||
* SAFETY (2026-08-29): `test/setup.ts` redirects `process.env.HOME` to a
|
||||
* throwaway dir, but code that resolves paths via `os.homedir()` does NOT
|
||||
* follow that redirect on every Linux build/Node version — some read
|
||||
* /etc/passwd instead of $HOME. A test that `rmSync(CASES_DIR, recursive)` can
|
||||
* therefore delete the PRODUCTION `~/codeman-cases` (or any home-anchored
|
||||
* tree) on those platforms. This gate refuses to delete anything not under the
|
||||
* (redirected) `process.env.HOME`. Lexical `resolve()` is used because the leaf
|
||||
* often does not exist and `realpathSync` would throw.
|
||||
* throwaway dir and `os.homedir()` follows it, so a `rmSync(CASES_DIR,
|
||||
* recursive)` normally lands inside the fixture. This gate is defense in depth
|
||||
* for the day that stops being true (a test that runs outside setup.ts, an
|
||||
* env override that anchors a path elsewhere): it refuses to delete anything
|
||||
* not under the redirected `process.env.HOME`, so the failure mode is a
|
||||
* leftover temp dir rather than a deleted PRODUCTION `~/codeman-cases`.
|
||||
* Lexical `resolve()` is used because the leaf often does not exist and
|
||||
* `realpathSync` would throw.
|
||||
*/
|
||||
export function safeRmHomeTree(path: string): void {
|
||||
const home = process.env.HOME;
|
||||
@@ -63,8 +64,7 @@ export function safeRmHomeTree(path: string): void {
|
||||
/**
|
||||
* True when `path` resolves strictly inside `process.env.HOME` (or to it).
|
||||
* Same rationale as `safeRmHomeTree`; use for guarded non-recursive deletes
|
||||
* (single files like `linked-cases.json`) so they never touch prod state on
|
||||
* platforms where `os.homedir()` ignores `$HOME`.
|
||||
* (single files like `linked-cases.json`) so they can never touch prod state.
|
||||
*/
|
||||
export function isUnderTestHome(path: string): boolean {
|
||||
const home = process.env.HOME;
|
||||
|
||||
Reference in New Issue
Block a user