fix(#2665): scrub GSD_ALLOW_SYMLINKED_DEST — a write-escape permission
Found by the pre-publication claim audit of this round's response comment, which refuted the sentence "none of the unscrubbed env reads names a write destination" on the grounds that naming a path is not the same property as influencing where writes land. GSD_ALLOW_SYMLINKED_DEST is boolean and names no path, so every rung of the derivation is structurally incapable of reaching it: not a registry configHome, not descriptor-shaped, not one of GSD's own location vars. It is still a #2665 leak vector. install-engine.cts reads it env-first (:214) and threads it as allowOptInFollow into the symlink-escape guard at four call sites, each gating a write (:361/:367, :416/:424, :785/:790, :927/:932). That guard is what stops a write leaving the install root, so an ambient =1 disarms it for the whole suite — the #2665 hazard arriving through a permission rather than a path. Added as its own named family (WRITE_ESCAPE_PERMISSION_ENV_KEYS) rather than folded into a location rung, for the same reason GSD_HOME got its own family in round 3: the list should not misdescribe what its members are. Blanking is fail-safe in the only direction that matters — '' is neither '1' nor 'true', so a blanked value makes the guard stricter, never looser. That asymmetry is what licenses scrubbing it wholesale rather than reasoning about each call site. The guard test names the variable literally rather than iterating the family constant: a test that asserts over the constant shrinks its own expectation when the family is emptied, which is the enumeration-relative failure that let the kimi-code descriptor go unwatched earlier in this same round. #2393's opt-in suite is unaffected (99/100, 0 fail): it sets process.env directly in-process and never routes through scrubConfigLocationEnv, and an explicit env argument still wins over TEST_ENV_BASE in childEnv.
This commit is contained in:
@@ -213,6 +213,29 @@ describe('#2665: TEST_ENV_BASE config-location coverage', () => {
|
||||
}
|
||||
});
|
||||
|
||||
test('write-escape PERMISSIONS are scrubbed (a fifth family — not a location var)', () => {
|
||||
// #2665 round 5. GSD_ALLOW_SYMLINKED_DEST names no path, so every rung of the
|
||||
// derivation above is structurally incapable of reaching it — it is not a
|
||||
// registry configHome, not descriptor-shaped, not one of GSD's own location
|
||||
// vars. It is still a #2665 leak vector: install-engine.cts reads it env-first
|
||||
// and threads it into the symlink-escape guard that stops a write leaving the
|
||||
// install root, so an ambient `=1` disarms that guard for the whole suite.
|
||||
//
|
||||
// Named literally rather than derived from the family constant on purpose: a
|
||||
// test that reads WRITE_ESCAPE_PERMISSION_ENV_KEYS and asserts over it shrinks
|
||||
// its own expectation when the family is emptied — the enumeration-relative
|
||||
// failure this suite already documents, and the one that let the kimi-code
|
||||
// descriptor go unwatched. Naming it is what makes removal fail loudly.
|
||||
assert.strictEqual(
|
||||
TEST_ENV_BASE.GSD_ALLOW_SYMLINKED_DEST,
|
||||
'',
|
||||
'GSD_ALLOW_SYMLINKED_DEST must be blanked: ambient =1 disarms the symlink-escape guard',
|
||||
);
|
||||
// Blanking must be fail-SAFE — '' is neither '1' nor 'true', so the guard gets
|
||||
// stricter, never looser. This is what licenses scrubbing it wholesale.
|
||||
assert.ok(!['1', 'true'].includes(TEST_ENV_BASE.GSD_ALLOW_SYMLINKED_DEST));
|
||||
});
|
||||
|
||||
test('scrubConfigLocationEnv clears and restores the parent process env', () => {
|
||||
// The in-process half of the fix (Blocker 1): TEST_ENV_BASE only reaches
|
||||
// children, so a test calling install() in-process needs the PARENT's env
|
||||
|
||||
Reference in New Issue
Block a user