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:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -9,7 +9,7 @@ const assert = require('node:assert/strict');
const path = require('path');
const os = require('os');
const fs = require('fs');
const { runGsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const { runMsdTools, createTempProject, cleanup } = require('./helpers.cjs');
const fc = require('./helpers/fast-check-setup.cjs');
const {
@@ -26,7 +26,7 @@ const {
assertWithinRoot,
tryWithinRoot,
PathAcceptance,
} = require('../gsd-core/bin/lib/security.cjs');
} = require('../msd-core/bin/lib/security.cjs');
// ─── Path Traversal Prevention ──────────────────────────────────────────────
@@ -117,7 +117,7 @@ describe('assertWithinRoot / tryWithinRoot — engine invariance', () => {
}
function makeScratchDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-sec-validatepath-'));
return fs.mkdtempSync(path.join(os.tmpdir(), 'msd-sec-validatepath-'));
}
// Returns a `base` string that is guaranteed non-canonical relative to
@@ -130,7 +130,7 @@ describe('assertWithinRoot / tryWithinRoot — engine invariance', () => {
if (realCanonicalDir !== canonicalDir) {
return { base: canonicalDir, canonical: realCanonicalDir, symlinked: false, aliasParent: null };
}
const aliasParent = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-sec-alias-'));
const aliasParent = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-sec-alias-'));
const alias = path.join(aliasParent, 'link');
let ok = withSymlinkGuard(t, () => fs.symlinkSync(canonicalDir, alias, 'dir'));
if (!ok) {
@@ -176,7 +176,7 @@ describe('assertWithinRoot / tryWithinRoot — engine invariance', () => {
test('in-project DANGLING symlink to a non-existent OUTSIDE target: safe:false (BLOCKER-1 regression)', (t) => {
const scratch = makeScratchDir();
try {
const nonExistentOutsideTarget = path.join(os.tmpdir(), `gsd-sec-nonexistent-${process.pid}-${Date.now()}`);
const nonExistentOutsideTarget = path.join(os.tmpdir(), `msd-sec-nonexistent-${process.pid}-${Date.now()}`);
const linkPath = path.join(scratch, 'dangling-link.txt');
const ok = withSymlinkGuard(t, () => fs.symlinkSync(nonExistentOutsideTarget, linkPath, 'file'));
if (ok) {
@@ -648,13 +648,13 @@ describe('validateFieldName', () => {
});
// ─── Hook session_id path traversal (#1533) ────────────────────────────────
// Verify that gsd-context-monitor and gsd-statusline reject session_id values
// Verify that msd-context-monitor and msd-statusline reject session_id values
// containing path traversal sequences before constructing temp file paths.
const { runHook: runHookSeam } = require('./helpers/process-seam.cjs');
// Bounds a single advisory hook invocation (gsd-context-monitor.js or
// gsd-statusline.js) under a session_id path-traversal security test —
// Bounds a single advisory hook invocation (msd-context-monitor.js or
// msd-statusline.js) under a session_id path-traversal security test —
// trivial synchronous work, no subprocess fan-out, expected near-instant
// silent exit. The value (3000ms) is the tightest bound in this migration's
// security-scanners batch and unique to this file/class; preserved exactly,
@@ -670,8 +670,8 @@ function runHook(hookPath, inputJson) {
return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
}
describe('gsd-context-monitor session_id path traversal', () => {
const monitorPath = path.join(__dirname, '..', 'hooks', 'gsd-context-monitor.js');
describe('msd-context-monitor session_id path traversal', () => {
const monitorPath = path.join(__dirname, '..', 'hooks', 'msd-context-monitor.js');
const tmpDir = os.tmpdir();
test('exits silently for session_id with ../ traversal', () => {
@@ -698,8 +698,8 @@ describe('gsd-context-monitor session_id path traversal', () => {
});
});
describe('gsd-statusline session_id path traversal', () => {
const statuslinePath = path.join(__dirname, '..', 'hooks', 'gsd-statusline.js');
describe('msd-statusline session_id path traversal', () => {
const statuslinePath = path.join(__dirname, '..', 'hooks', 'msd-statusline.js');
const tmpDir = os.tmpdir();
const baseInput = {
@@ -709,7 +709,7 @@ describe('gsd-statusline session_id path traversal', () => {
};
test('does not write bridge file for session_id with ../ traversal', () => {
const maliciousId = '../../../etc/gsd-test';
const maliciousId = '../../../etc/msd-test';
const bridgePath = path.join(tmpDir, 'claude-ctx-' + maliciousId + '.json');
try { fs.unlinkSync(bridgePath); } catch { /* intentionally empty */ }
@@ -905,7 +905,7 @@ describe('validatePromptStructure', () => {
const text = [
'<purpose>Act as a planner</purpose>',
'<required_reading>PLAN.md</required_reading>',
'<available_agent_types>gsd-executor</available_agent_types>',
'<available_agent_types>msd-executor</available_agent_types>',
].join('\n');
const result = validatePromptStructure(text, 'agent');
assert.ok(result.valid);
@@ -995,7 +995,7 @@ const path = require('node:path');
const ROOT = path.join(__dirname, '..');
const AGENTS_DIR = path.join(ROOT, 'agents');
const REFS_DIR = path.join(ROOT, 'gsd-core', 'references');
const REFS_DIR = path.join(ROOT, 'msd-core', 'references');
const MANIFEST_PATH = path.join(ROOT, 'docs', 'INVENTORY-MANIFEST.json');
describe('SECURE: ASVS level scaling (#1627)', () => {
@@ -1005,7 +1005,7 @@ describe('SECURE: ASVS level scaling (#1627)', () => {
const refPath = path.join(REFS_DIR, 'security-asvs-levels.md');
test('file exists', () => {
assert.ok(fs.existsSync(refPath), 'gsd-core/references/security-asvs-levels.md must exist');
assert.ok(fs.existsSync(refPath), 'msd-core/references/security-asvs-levels.md must exist');
});
test('defines all three levels', () => {
@@ -1063,10 +1063,10 @@ describe('SECURE: ASVS level scaling (#1627)', () => {
});
});
// ── 2. gsd-planner.md — no hardcoded L1 in disposition ──────────────────
// ── 2. msd-planner.md — no hardcoded L1 in disposition ──────────────────
describe('gsd-planner.md security disposition', () => {
const plannerPath = path.join(AGENTS_DIR, 'gsd-planner.md');
describe('msd-planner.md security disposition', () => {
const plannerPath = path.join(AGENTS_DIR, 'msd-planner.md');
test('planner security instruction does not hardcode "ASVS L1"', () => {
const content = fs.readFileSync(plannerPath, 'utf-8');
@@ -1097,15 +1097,15 @@ describe('SECURE: ASVS level scaling (#1627)', () => {
const content = fs.readFileSync(plannerPath, 'utf-8').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
assert.ok(
content.length < 49152,
`gsd-planner.md must be < 49152 chars (LF-normalized); got ${content.length}`
`msd-planner.md must be < 49152 chars (LF-normalized); got ${content.length}`
);
});
});
// ── 3. gsd-security-auditor.md — scaled verification depth ──────────────
// ── 3. msd-security-auditor.md — scaled verification depth ──────────────
describe('gsd-security-auditor.md verification depth', () => {
const auditorPath = path.join(AGENTS_DIR, 'gsd-security-auditor.md');
describe('msd-security-auditor.md verification depth', () => {
const auditorPath = path.join(AGENTS_DIR, 'msd-security-auditor.md');
test('auditor scales verification depth by asvs_level', () => {
const content = fs.readFileSync(auditorPath, 'utf-8');
@@ -1143,7 +1143,7 @@ describe('SECURE: ASVS level scaling (#1627)', () => {
// ── 4. secure-phase.md — ASVS-aware short-circuit ──────────────────────
describe('secure-phase.md short-circuit conditioned on asvs_level', () => {
const wfPath = path.join(ROOT, 'gsd-core', 'workflows', 'secure-phase.md');
const wfPath = path.join(ROOT, 'msd-core', 'workflows', 'secure-phase.md');
test('short-circuit to Step 6 is gated on asvs_level == 1', () => {
const content = fs.readFileSync(wfPath, 'utf-8');
@@ -1231,7 +1231,7 @@ describe('containment properties (#4652)', () => {
fc.array(segmentArb, { minLength: 0, maxLength: 3 }), // trailing segments after escaping
(baseSegments, extraUp, tailSegments) => {
// Root sits `baseSegments.length` levels below a stable anchor.
const anchor = path.resolve('/gsd-root-anchor');
const anchor = path.resolve('/msd-root-anchor');
const root = path.join(anchor, ...baseSegments);
// Enough ".." to exit past the anchor itself, guaranteeing the resolved
// path is OUTSIDE root (and outside the anchor) regardless of anchor
@@ -1253,7 +1253,7 @@ describe('containment properties (#4652)', () => {
fc.assert(fc.property(
fc.array(segmentArb, { minLength: 1, maxLength: 5 }),
(segments) => {
const root = path.resolve('/gsd-root-anchor-in');
const root = path.resolve('/msd-root-anchor-in');
const relPath = path.join(...segments);
const result = tryWithinRoot(relPath, root);
@@ -1309,7 +1309,7 @@ describe('cross-boundary containment — shared escaping inputs, same rejection
const { tmpDir } = setupProject();
try {
// Boundary 1: todo complete <name>
const todoResult = runGsdTools(['--json-errors', 'todo', 'complete', escaping], tmpDir);
const todoResult = runMsdTools(['--json-errors', 'todo', 'complete', escaping], tmpDir);
assertUsageRejection(todoResult, `todo complete "${escaping}"`);
// Boundary 2: check predicate --phase-dir <dir>
@@ -1317,7 +1317,7 @@ describe('cross-boundary containment — shared escaping inputs, same rejection
kind: 'command-exit-zero',
command: 'true',
});
const predicateResult = runGsdTools(
const predicateResult = runMsdTools(
['--json-errors', 'check', 'predicate', '--predicate', predicate, '--phase-dir', escaping, '--raw'],
tmpDir,
);
@@ -1326,14 +1326,14 @@ describe('cross-boundary containment — shared escaping inputs, same rejection
// Boundary 3: check decision-coverage-plan <phase-dir> <context-path>
const contextPath = path.join(tmpDir, 'CONTEXT.md');
fs.writeFileSync(contextPath, '# Context\n\n<decisions>\n## Implementation Decisions\n\n- **D-01:** x\n</decisions>\n');
const decisionResult = runGsdTools(
const decisionResult = runMsdTools(
['--json-errors', 'query', 'check.decision-coverage-plan', escaping, contextPath],
tmpDir,
);
assertUsageRejection(decisionResult, `check decision-coverage-plan "${escaping}"`);
// Boundary 4: check gap-analysis.plan-post <phase-dir>
const gapResult = runGsdTools(
const gapResult = runMsdTools(
['--json-errors', 'check', 'gap-analysis.plan-post', escaping, '--raw'],
tmpDir,
);
@@ -1352,7 +1352,7 @@ describe('cross-boundary containment — shared escaping inputs, same rejection
// `assertWithinRoot` throws on escape (requireSafePath becomes a thin alias
// of it); `tryWithinRoot` returns null on escape. Neither export exists yet
// — this whole block is RED by construction (missing export, not a typo:
// verified against the compiled gsd-core/bin/lib/security.cjs export list,
// verified against the compiled msd-core/bin/lib/security.cjs export list,
// which lists only validatePath/loadTrustedGlobalRoots/requireSafePath/
// scanForInjection/sanitizeForPrompt/sanitizeForDisplay/sanitizeLabel/
// validateShellArg/safeJsonParse/validatePhaseNumber/validateFieldName/
@@ -1452,7 +1452,7 @@ describe('assertWithinRoot / tryWithinRoot — narrowed export (#4653)', () => {
// above in this same file).
test('parity: tryWithinRoot succeeds IFF assertWithinRoot does not throw, and values agree (#4653)', () => {
const root = path.resolve('/gsd-root-anchor-parity');
const root = path.resolve('/msd-root-anchor-parity');
fc.assert(fc.property(
fc.string(),
(candidate) => {