test(v8.1.3): red tests for plan points 1, 2, 3, 5 and addenda a-c

Each test fails on fd7de23:
- own-working-tree: venv site-packages, vendor/, config-dir skills/
  (punkt 1); ~/.claude/plugins next to $CLAUDE_CONFIG_DIR and a leading
  ~ in the variable (punkt 2); NODE_MODULES case variant and a
  case-mismatched parent segment (punkt 3, closes v8.1.2 punkt 4).
- watch-cron-scope: a watched project's own ignore file is honored
  (punkt 5).
- av-surface (b2): no runnable base64-to-shell line with a short
  command blob (addendum a; 3 hits today).
- doc-consistency: scanner-reference Knowledge Files matches knowledge/
  (addendum b); ci-cd-guide makes no offline claim (addendum c).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-23 11:29:22 +02:00
commit b62c3e60f5
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 290 additions and 0 deletions

View file

@ -194,3 +194,132 @@ describe('isOwnWorkingTree(): node_modules and the plugin dir are foreign (v8.1.
}
});
});
// v8.1.3 (order 20260923T092223Z, PM decisions):
// punkt 1 — other install locations are foreign like `node_modules`: a
// `site-packages` segment (Python venv) or a `vendor` segment
// (composer/bundler/Go) on the path from cwd to the target, and anything
// under a Claude Code config dir's `skills/` (third-party skills copied
// into a git-tracked ~/.claude share its git root).
// punkt 2 — BOTH `~/.claude` and `$CLAUDE_CONFIG_DIR` count as config dirs;
// a leading `~` in the variable is expanded to the home dir.
// punkt 3 — case is canonicalized (realpathSync.native), so `NODE_MODULES/x`
// on a case-insensitive volume is the `node_modules` it names, and a
// case-mismatched path to an own subdir is own (§ v8.1.2 punkt 4).
describe('isOwnWorkingTree(): v8.1.3 install locations, config dirs, case', () => {
let root;
let repo;
let savedConfigDir;
let savedHome;
before(() => {
root = mkOwnTreeDir('owt-813-');
repo = join(root, 'repo');
gitInit(repo);
mkdirSync(join(repo, '.venv', 'lib', 'python3.12', 'site-packages', 'evilpkg'), { recursive: true });
mkdirSync(join(repo, 'vendor', 'acme', 'lib'), { recursive: true });
mkdirSync(join(repo, 'my-vendor-notes'), { recursive: true });
mkdirSync(join(repo, 'node_modules', 'evil'), { recursive: true });
mkdirSync(join(repo, 'Sub'), { recursive: true });
// A git-tracked config dir (cwd = it) with third-party skills and its own
// non-skill content, plus a $HOME-like dir with a default ~/.claude.
gitInit(join(root, 'cfg'));
mkdirSync(join(root, 'cfg', 'skills', 'third-party'), { recursive: true });
mkdirSync(join(root, 'cfg', 'agents'), { recursive: true });
mkdirSync(join(root, 'fakehome', '.claude', 'plugins', 'cache', 'mkt', 'p', '1.0.0'), { recursive: true });
mkdirSync(join(root, 'fakehome', '.claude', 'skills', 'x'), { recursive: true });
mkdirSync(join(root, 'fakehome', 'alt', 'plugins', 'cache', 'mkt', 'q'), { recursive: true });
mkdirSync(join(root, 'fakehome', 'work'), { recursive: true });
savedConfigDir = process.env.CLAUDE_CONFIG_DIR;
savedHome = process.env.HOME;
});
after(() => {
if (savedConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
else process.env.CLAUDE_CONFIG_DIR = savedConfigDir;
process.env.HOME = savedHome;
rmSync(root, { recursive: true, force: true });
});
it('punkt 1: a package in a Python venv site-packages is foreign', () => {
assert.equal(ownFrom(repo, join(repo, '.venv', 'lib', 'python3.12', 'site-packages', 'evilpkg')), false);
});
it('punkt 1: a composer/bundler vendor/ package is foreign', () => {
assert.equal(ownFrom(repo, join(repo, 'vendor', 'acme')), false);
assert.equal(ownFrom(repo, join(repo, 'vendor', 'acme', 'lib')), false);
});
it('punkt 1: the venv root and a look-alike name stay own (known-positive)', () => {
assert.equal(ownFrom(repo, join(repo, '.venv')), true);
assert.equal(ownFrom(repo, join(repo, 'my-vendor-notes')), true);
});
it('punkt 1: skills in a git-tracked config dir are foreign, the rest stays own', () => {
process.env.CLAUDE_CONFIG_DIR = join(root, 'cfg');
try {
assert.equal(ownFrom(join(root, 'cfg'), join(root, 'cfg', 'skills', 'third-party')), false);
assert.equal(ownFrom(join(root, 'cfg'), join(root, 'cfg', 'agents')), true);
} finally {
if (savedConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
else process.env.CLAUDE_CONFIG_DIR = savedConfigDir;
}
});
it('punkt 1: skills under the default ~/.claude are foreign', () => {
delete process.env.CLAUDE_CONFIG_DIR;
process.env.HOME = join(root, 'fakehome');
try {
const home = join(root, 'fakehome');
assert.equal(ownFrom(home, join(home, '.claude', 'skills', 'x')), false);
} finally {
process.env.HOME = savedHome;
}
});
it('punkt 2: ~/.claude/plugins stays foreign when CLAUDE_CONFIG_DIR points at another profile', () => {
process.env.HOME = join(root, 'fakehome');
process.env.CLAUDE_CONFIG_DIR = join(root, 'fakehome', 'alt');
try {
const home = join(root, 'fakehome');
assert.equal(ownFrom(home, join(home, '.claude', 'plugins', 'cache', 'mkt', 'p', '1.0.0')), false);
assert.equal(ownFrom(home, join(home, 'alt', 'plugins', 'cache', 'mkt', 'q')), false);
assert.equal(ownFrom(home, join(home, 'work')), true);
} finally {
process.env.HOME = savedHome;
if (savedConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
else process.env.CLAUDE_CONFIG_DIR = savedConfigDir;
}
});
it('punkt 2: a leading ~ in CLAUDE_CONFIG_DIR is expanded to the home dir', () => {
process.env.HOME = join(root, 'fakehome');
process.env.CLAUDE_CONFIG_DIR = '~/alt';
try {
const home = join(root, 'fakehome');
assert.equal(ownFrom(home, join(home, 'alt', 'plugins', 'cache', 'mkt', 'q')), false);
} finally {
process.env.HOME = savedHome;
if (savedConfigDir === undefined) delete process.env.CLAUDE_CONFIG_DIR;
else process.env.CLAUDE_CONFIG_DIR = savedConfigDir;
}
});
it('punkt 3: a case variant of node_modules is foreign (case-insensitive volume)', (t) => {
if (!existsSync(join(repo, 'NODE_MODULES'))) {
t.skip('volume is case-sensitive: NODE_MODULES is a different directory');
return;
}
assert.equal(ownFrom(repo, join(repo, 'NODE_MODULES', 'evil')), false);
});
it('punkt 3: a case-mismatched path to an own subdir is own (§ v8.1.2 punkt 4)', (t) => {
if (!existsSync(join(root, 'REPO'))) {
t.skip('volume is case-sensitive: REPO is not repo');
return;
}
// The mismatch sits in a parent segment: realpathSync keeps `REPO`, so the
// target did not start with cwd and was called foreign.
assert.equal(ownFrom(repo, join(root, 'REPO', 'Sub')), true);
});
});