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:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user