Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions test/hermetic-wiring.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,21 @@ describe('hermetic wiring tripwire', () => {
expect(configDir.startsWith(runRoot + path.sep)).toBe(true);
expect(configDir.startsWith(operatorClaude)).toBe(false);
const skillsDir = path.join(configDir, 'skills');
const repoRootReal = fs.realpathSync(ROOT) + path.sep;
for (const entry of fs.readdirSync(skillsDir)) {
const target = fs.readlinkSync(path.join(skillsDir, entry, 'SKILL.md'));
expect(target.startsWith(operatorClaude), `${entry}: symlink escapes to ${target}`).toBe(false);
expect(fs.realpathSync(target).startsWith(fs.realpathSync(ROOT) + path.sep), `${entry}: symlink outside repo: ${target}`).toBe(true);
const resolved = fs.realpathSync(target);
// Targets inside the live repo checkout are the blessed edge — exempt
// them BEFORE the operator-~/.claude ban. On the default global-git
// install the repo itself lives at ~/.claude/skills/gstack, so every
// CORRECT symlink carries the operatorClaude prefix and an unexempted
// ban can never pass (regression 2026-08-15: pristine v1.64.1.0 fails
// this test in any worktree under ~/.claude/skills/ and passes
// elsewhere — realpath both sides so a symlinked HOME can't dodge it).
if (!resolved.startsWith(repoRootReal)) {
expect(resolved.startsWith(operatorClaude), `${entry}: symlink escapes to ${target}`).toBe(false);
}
expect(resolved.startsWith(repoRootReal), `${entry}: symlink outside repo: ${target}`).toBe(true);
}
});
});