Files
msd-core/tests/no-unconfined-path-join.rule.test.cjs
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

500 lines
16 KiB
JavaScript

'use strict';
/**
* no-unconfined-path-join.rule.test.cjs
*
* RuleTester unit tests for the local/no-unconfined-path-join ESLint rule.
*
* Arm 1: hand-rolled containment comparison `x.startsWith(y + sep)`.
* Arm 2: a discarded containment-predicate result (bare statement call).
* Plus the `allow-handrolled-containment: <reason>` marker escape and the
* allowlist ratchet mechanics.
*/
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const { RuleTester } = require('eslint');
const rule = require('../eslint-rules/no-unconfined-path-join.cjs');
const ruleTester = new RuleTester({
languageOptions: {
ecmaVersion: 2022,
sourceType: 'commonjs',
},
});
// ─── module shape ─────────────────────────────────────────────────────────────
describe('no-unconfined-path-join rule module', () => {
test('exports meta and create', () => {
assert.strictEqual(typeof rule.meta, 'object');
assert.strictEqual(typeof rule.create, 'function');
assert.strictEqual(rule.meta.type, 'problem');
assert.ok(rule.meta.messages.handRolledContainment, 'handRolledContainment message must exist');
assert.ok(
rule.meta.messages.discardedContainmentResult,
'discardedContainmentResult message must exist',
);
assert.ok(rule.meta.messages.staleAllowlistEntry, 'staleAllowlistEntry message must exist');
});
});
// ─── Arm 1: hand-rolled containment — fires ──────────────────────────────────
describe('no-unconfined-path-join: arm 1 fires', () => {
test('invalid: resolved.startsWith(root + path.sep)', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: resolved !== root && !resolved.startsWith(root + path.sep) reports exactly one error', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `if (resolved !== root && !resolved.startsWith(root + path.sep)) { throw new Error('x'); }`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: x.startsWith(y + "/")', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `x.startsWith(y + '/');`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: x.startsWith(y + "\\\\")', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `x.startsWith(y + '\\\\');`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: x.startsWith(y + p.sep)', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `x.startsWith(y + p.sep);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: x.startsWith(`${root}${path.sep}`) — template literal ending in a `.sep` expression', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: 'x.startsWith(`${root}${path.sep}`);',
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: x.startsWith(`${root}/`) — template literal ending in a literal separator character', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: 'x.startsWith(`${root}/`);',
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: const sep = path.sep; x.startsWith(root + sep) — separator reached through a single const alias', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: 'const sep = path.sep; x.startsWith(root + sep);',
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
});
// ─── Arm 1: hand-rolled containment — silent ─────────────────────────────────
describe('no-unconfined-path-join: arm 1 silent', () => {
test('valid: x.startsWith(prefix) — bare identifier argument', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith(prefix);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: x.startsWith("msd-") — plain literal argument', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith('msd-');`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: x.startsWith(y + "-") — right side is not a separator', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith(y + '-');`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: x.startsWith(y + z) — right side is an unresolvable identifier', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith(y + z);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: let sep = path.sep; x.startsWith(root + sep) — reassignable `let` binding is not resolved', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `let sep = path.sep; x.startsWith(root + sep);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: function f(sep) { x.startsWith(root + sep); } — parameter binding is not resolved', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{ code: `function f(sep) { x.startsWith(root + sep); }`, filename: 'src/foo.cts' },
],
invalid: [],
});
});
test('valid: x.startsWith(a, b) — wrong arity', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith(a, b);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: x.startsWith(`${root}-suffix`) — template literal NOT ending in a separator', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: 'x.startsWith(`${root}-suffix`);', filename: 'src/foo.cts' }],
invalid: [],
});
});
});
// ─── Arm 2: discarded containment result — fires ─────────────────────────────
describe('no-unconfined-path-join: arm 2 fires', () => {
test('invalid: assertWithinRoot(p, root); as a bare statement', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `assertWithinRoot(p, root);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'discardedContainmentResult' }],
},
],
});
});
test('invalid: tryWithinRoot(p, root); as a bare statement', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `tryWithinRoot(p, root);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'discardedContainmentResult' }],
},
],
});
});
test('invalid: isContainedIn(p, root); as a bare statement — boolean predicate discarded', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `isContainedIn(p, root);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'discardedContainmentResult' }],
},
],
});
});
});
// ─── Arm 2: discarded containment result — silent ────────────────────────────
describe('no-unconfined-path-join: arm 2 silent', () => {
test('valid: const x = assertWithinRoot(p, root); — VariableDeclarator init', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `const x = assertWithinRoot(p, root);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
test('valid: if (tryWithinRoot(p, root) === null) {} — inside a comparison', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{ code: `if (tryWithinRoot(p, root) === null) {}`, filename: 'src/foo.cts' },
],
invalid: [],
});
});
test('valid: return assertWithinRoot(p, root); — return value', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `function f() { return assertWithinRoot(p, root); }`,
filename: 'src/foo.cts',
},
],
invalid: [],
});
});
test('valid: fs.readFileSync(assertWithinRoot(p, root)); — call argument', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{ code: `fs.readFileSync(assertWithinRoot(p, root));`, filename: 'src/foo.cts' },
],
invalid: [],
});
});
test('valid: someOtherFn(p, root); — unrelated callee name', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `someOtherFn(p, root);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
});
// ─── marker escape ────────────────────────────────────────────────────────────
describe('no-unconfined-path-join: marker escape', () => {
test('valid: suppressed with a real reason', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `resolved.startsWith(root + path.sep); // allow-handrolled-containment: legacy call site pending migration`,
filename: 'src/foo.cts',
},
],
invalid: [],
});
});
test('invalid: does NOT suppress with an empty reason', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep); // allow-handrolled-containment:`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: does NOT suppress without a colon', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep); // allow-handrolled-containment`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: does NOT suppress when the marker is on a different line', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `// allow-handrolled-containment: legacy call site pending migration\nresolved.startsWith(root + path.sep);`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('invalid: does NOT suppress with a BLOCK comment on the same line', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep); /* allow-handrolled-containment: legacy call site pending migration */`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('two violations on one line: trailing marker suppresses only the one it trails', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `a.startsWith(root + path.sep); b.startsWith(root + path.sep); // allow-handrolled-containment: legacy call site pending migration`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('valid: suppressed with a justification (b) reason — pre-build bootstrap file', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `resolved.startsWith(root + path.sep); // allow-handrolled-containment: this is a committed .cjs that must run before npm run build:lib, so src/security.cts is unreachable here`,
filename: 'msd-core/bin/lib/capability-validator.cjs',
},
],
invalid: [],
});
});
test('valid: marker suppresses a discarded arm-2 call — tryWithinRoot(p, root); // allow-handrolled-containment: <reason>', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `tryWithinRoot(p, root); // allow-handrolled-containment: legacy call site pending migration`,
filename: 'src/foo.cts',
},
],
invalid: [],
});
});
test('invalid: the old spelling allow-lexical-prefix-match no longer suppresses', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep); // allow-lexical-prefix-match: legacy call site pending migration`,
filename: 'src/foo.cts',
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
});
// ─── allowlist ratchet ────────────────────────────────────────────────────────
describe('no-unconfined-path-join: allowlist', () => {
test('valid: allowlisted file with violations reports nothing', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `resolved.startsWith(root + path.sep);`,
filename: 'src/legacy.cts',
options: [{ allowlist: ['src/legacy.cts'] }],
},
],
invalid: [],
});
});
test('invalid: allowlisted file with ZERO violations reports staleAllowlistEntry', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `const x = 1;`,
filename: 'src/legacy.cts',
options: [{ allowlist: ['src/legacy.cts'] }],
errors: [{ messageId: 'staleAllowlistEntry' }],
},
],
});
});
test('invalid: allowlisted file whose only occurrence is marker-suppressed reports staleAllowlistEntry', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep); // allow-handrolled-containment: legacy call site pending migration`,
filename: 'src/legacy.cts',
options: [{ allowlist: ['src/legacy.cts'] }],
errors: [{ messageId: 'staleAllowlistEntry' }],
},
],
});
});
test('invalid: non-allowlisted file with violations reports', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [],
invalid: [
{
code: `resolved.startsWith(root + path.sep);`,
filename: 'src/other.cts',
options: [{ allowlist: ['src/legacy.cts'] }],
errors: [{ messageId: 'handRolledContainment' }],
},
],
});
});
test('valid: allowlisted file with one marked and one unmarked occurrence keeps the entry alive', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [
{
code: `a.startsWith(root + path.sep); // allow-handrolled-containment: legacy call site pending migration\nb.startsWith(root + path.sep);`,
filename: 'src/legacy.cts',
options: [{ allowlist: ['src/legacy.cts'] }],
},
],
invalid: [],
});
});
test('valid: rule configured with no options at all does not crash', () => {
ruleTester.run('no-unconfined-path-join', rule, {
valid: [{ code: `x.startsWith(prefix);`, filename: 'src/foo.cts' }],
invalid: [],
});
});
});