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.
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
/**
|
||||
* tests/shadow-report.security.test.cjs — hostile-manifest rendering suite
|
||||
* for `install-shadow-report.cts` (#2873, epic #2866 Phase 4a — governed by
|
||||
* `.gsd/phase/feat-2873-cross-scope-shadowing/40-design.md`).
|
||||
* `.msd/phase/feat-2873-cross-scope-shadowing/40-design.md`).
|
||||
*
|
||||
* Implements matrix section B ("Rendering / sanitization (hostile manifest)",
|
||||
* rows B1-B16) from
|
||||
* `.gsd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`. The
|
||||
* `.msd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`. The
|
||||
* matrix's own "Suites" section names this file `install-shadow-report
|
||||
* .security.test.cjs`; it is shipped as `shadow-report.security.test.cjs`
|
||||
* instead so its `lint-test-file-count.cjs` prefix is `shadow` rather than
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
* Fixture provenance (#2371, per the matrix's own note): B1-B4/B7/B8's
|
||||
* `declaredRuntime` payloads and B9-B13's manifest bodies are authored
|
||||
* against the PUBLISHED `gsd-file-manifest.json` schema/format directly (raw
|
||||
* against the PUBLISHED `msd-file-manifest.json` schema/format directly (raw
|
||||
* JSON text or a hand-built `readManifest` result), never derived from
|
||||
* `writeManifest`'s own output — a fixture the writer produced could only
|
||||
* confirm what the writer already believes.
|
||||
@@ -36,9 +36,9 @@ const path = require('node:path');
|
||||
|
||||
const { createTempDir, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const { buildShadowReport, renderShadowReport } = require('../gsd-core/bin/lib/install-shadow-report.cjs');
|
||||
const { resolveScope } = require('../gsd-core/bin/lib/install-scope.cjs');
|
||||
const { MANIFEST_NAME } = require('../gsd-core/bin/lib/installer-migrations.cjs');
|
||||
const { buildShadowReport, renderShadowReport } = require('../msd-core/bin/lib/install-shadow-report.cjs');
|
||||
const { resolveScope } = require('../msd-core/bin/lib/install-scope.cjs');
|
||||
const { MANIFEST_NAME } = require('../msd-core/bin/lib/installer-migrations.cjs');
|
||||
|
||||
// ─── Fixture helpers (mirrors tests/installed-surface-resolver.test.cjs) ───
|
||||
|
||||
@@ -124,8 +124,8 @@ describe('buildShadowReport — hostile declaredRuntime is sanitized in the IR (
|
||||
|
||||
describe('buildShadowReport — declaredRuntime length cap, real reader (B5-B6)', () => {
|
||||
function realCappedReport(t, n) {
|
||||
const home = createTempDir('gsd-shadow-sec-b56-home-');
|
||||
const cwd = createTempDir('gsd-shadow-sec-b56-cwd-');
|
||||
const home = createTempDir('msd-shadow-sec-b56-home-');
|
||||
const cwd = createTempDir('msd-shadow-sec-b56-cwd-');
|
||||
t.after(() => { cleanup(home); cleanup(cwd); });
|
||||
const globalDir = path.join(home, '.claude');
|
||||
fs.mkdirSync(globalDir, { recursive: true });
|
||||
@@ -185,8 +185,8 @@ describe('buildShadowReport — empty vs absent declaredRuntime (B7-B8)', () =>
|
||||
|
||||
describe('buildShadowReport — malformed manifest documents degrade, never throw (B9-B11)', () => {
|
||||
function realSingleScopeReport(t, rawBody) {
|
||||
const home = createTempDir('gsd-shadow-sec-b9-home-');
|
||||
const cwd = createTempDir('gsd-shadow-sec-b9-cwd-');
|
||||
const home = createTempDir('msd-shadow-sec-b9-home-');
|
||||
const cwd = createTempDir('msd-shadow-sec-b9-cwd-');
|
||||
t.after(() => { cleanup(home); cleanup(cwd); });
|
||||
const globalDir = path.join(home, '.claude');
|
||||
fs.mkdirSync(globalDir, { recursive: true });
|
||||
@@ -218,7 +218,7 @@ describe('buildShadowReport — malformed manifest documents degrade, never thro
|
||||
' "manifestVersion": 2,',
|
||||
' "runtime": "claude",',
|
||||
' "scope": "global",',
|
||||
' "files": { "skills/gsd-plan-phase/SKILL.md": "a" }',
|
||||
' "files": { "skills/msd-plan-phase/SKILL.md": "a" }',
|
||||
'}',
|
||||
'',
|
||||
].join('\n');
|
||||
@@ -239,15 +239,15 @@ describe('buildShadowReport — manifest KEY hostility and normalization (B12-B1
|
||||
[homes.global, manifest({
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'global',
|
||||
files: {
|
||||
'skills/gsd-../../../x/SKILL.md': 'a',
|
||||
'skills/gsd-plan-phase/SKILL.md': 'b',
|
||||
'skills/msd-../../../x/SKILL.md': 'a',
|
||||
'skills/msd-plan-phase/SKILL.md': 'b',
|
||||
},
|
||||
})],
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/gsd-plan-phase.md': 'a' } })],
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/msd-plan-phase.md': 'a' } })],
|
||||
]);
|
||||
const report = buildShadowReport('claude', baseOpts(home, cwd, { readManifest: mkReadManifest(byConfigHome) }));
|
||||
// Only the legitimate stem is present — the traversal key contributed nothing.
|
||||
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['gsd-plan-phase']);
|
||||
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['msd-plan-phase']);
|
||||
for (const line of renderShadowReport(report)) {
|
||||
assert.ok(!line.includes('..'), `rendered output must never carry a traversal payload: ${JSON.stringify(line)}`);
|
||||
}
|
||||
@@ -258,11 +258,11 @@ describe('buildShadowReport — manifest KEY hostility and normalization (B12-B1
|
||||
const cwd = '/fixture/b13-cwd';
|
||||
const homes = scopeHomes('claude', home, cwd);
|
||||
const byConfigHome = new Map([
|
||||
[homes.global, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills\\gsd-foo\\SKILL.md': 'a' } })],
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/gsd-foo.md': 'a' } })],
|
||||
[homes.global, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills\\msd-foo\\SKILL.md': 'a' } })],
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/msd-foo.md': 'a' } })],
|
||||
]);
|
||||
const report = buildShadowReport('claude', baseOpts(home, cwd, { readManifest: mkReadManifest(byConfigHome) }));
|
||||
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['gsd-foo']);
|
||||
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['msd-foo']);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -274,10 +274,10 @@ describe('buildShadowReport — the lstatSync symlink guard (B14-B16)', () => {
|
||||
const cwd = '/fixture/b14-cwd';
|
||||
const homes = scopeHomes('claude', home, cwd);
|
||||
const byConfigHome = new Map([
|
||||
[homes.global, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/gsd-plan-phase/SKILL.md': 'a' } })],
|
||||
[homes.global, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/msd-plan-phase/SKILL.md': 'a' } })],
|
||||
// A manifest IS present at the local configHome per this readManifest
|
||||
// stub — proving the guard, not the reader, is what refuses it below.
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/gsd-plan-phase.md': 'a' } })],
|
||||
[homes.local, manifest({ manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/msd-plan-phase.md': 'a' } })],
|
||||
]);
|
||||
// Injected lstatSync reports the local configHome itself as a symlink.
|
||||
const lstatSync = (p) => ({ isSymbolicLink: () => p === homes.local });
|
||||
@@ -287,9 +287,9 @@ describe('buildShadowReport — the lstatSync symlink guard (B14-B16)', () => {
|
||||
});
|
||||
|
||||
test('a symlinked manifest file is not followed, real symlink on disk (B15)', (t) => {
|
||||
const home = createTempDir('gsd-shadow-sec-b15-home-');
|
||||
const cwd = createTempDir('gsd-shadow-sec-b15-cwd-');
|
||||
const outOfTreeDir = createTempDir('gsd-shadow-sec-b15-outoftree-');
|
||||
const home = createTempDir('msd-shadow-sec-b15-home-');
|
||||
const cwd = createTempDir('msd-shadow-sec-b15-cwd-');
|
||||
const outOfTreeDir = createTempDir('msd-shadow-sec-b15-outoftree-');
|
||||
t.after(() => { cleanup(home); cleanup(cwd); cleanup(outOfTreeDir); });
|
||||
|
||||
const globalDir = path.join(home, '.claude');
|
||||
@@ -297,11 +297,11 @@ describe('buildShadowReport — the lstatSync symlink guard (B14-B16)', () => {
|
||||
fs.mkdirSync(globalDir, { recursive: true });
|
||||
fs.mkdirSync(localDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(globalDir, MANIFEST_NAME), JSON.stringify({
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/gsd-plan-phase/SKILL.md': 'a' },
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/msd-plan-phase/SKILL.md': 'a' },
|
||||
}));
|
||||
const outOfTreeManifest = path.join(outOfTreeDir, 'real-manifest.json');
|
||||
fs.writeFileSync(outOfTreeManifest, JSON.stringify({
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/gsd-plan-phase.md': 'a' },
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/msd-plan-phase.md': 'a' },
|
||||
}));
|
||||
// The local config DIR is real; only the manifest FILE inside it is a
|
||||
// symlink pointing OUTSIDE the config dir — proves the guard checks the
|
||||
@@ -314,8 +314,8 @@ describe('buildShadowReport — the lstatSync symlink guard (B14-B16)', () => {
|
||||
});
|
||||
|
||||
test('an unsymlinked local config still reads (B16, negative proof)', (t) => {
|
||||
const home = createTempDir('gsd-shadow-sec-b16-home-');
|
||||
const cwd = createTempDir('gsd-shadow-sec-b16-cwd-');
|
||||
const home = createTempDir('msd-shadow-sec-b16-home-');
|
||||
const cwd = createTempDir('msd-shadow-sec-b16-cwd-');
|
||||
t.after(() => { cleanup(home); cleanup(cwd); });
|
||||
|
||||
const globalDir = path.join(home, '.claude');
|
||||
@@ -323,10 +323,10 @@ describe('buildShadowReport — the lstatSync symlink guard (B14-B16)', () => {
|
||||
fs.mkdirSync(globalDir, { recursive: true });
|
||||
fs.mkdirSync(localDir, { recursive: true });
|
||||
fs.writeFileSync(path.join(globalDir, MANIFEST_NAME), JSON.stringify({
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/gsd-plan-phase/SKILL.md': 'a' },
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'global', files: { 'skills/msd-plan-phase/SKILL.md': 'a' },
|
||||
}));
|
||||
fs.writeFileSync(path.join(localDir, MANIFEST_NAME), JSON.stringify({
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/gsd-plan-phase.md': 'a' },
|
||||
manifestVersion: 2, runtime: 'claude', scope: 'local', files: { 'commands/msd-plan-phase.md': 'a' },
|
||||
}));
|
||||
|
||||
const report = buildShadowReport('claude', { home, cwd });
|
||||
|
||||
Reference in New Issue
Block a user