Files
msd-core/tests/secure-phase-single-writer.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

74 lines
2.4 KiB
JavaScript

/**
* Regression test for #2119: /msd-secure-phase dual SECURITY.md writers.
*
* The msd-security-auditor agent must NOT have Write/Edit tools — the
* orchestrator (secure-phase.md Step 6) is the sole SECURITY.md writer.
* The auditor returns a structured verdict; it never writes files.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const AGENT_PATH = path.join(__dirname, '..', 'agents', 'msd-security-auditor.md');
function parseYamlTools(content) {
const lines = content.split(/\r?\n/);
let inFrontmatter = false;
let inTools = false;
const tools = [];
for (const line of lines) {
const trimmed = line.trim();
if (trimmed === '---') {
inFrontmatter = !inFrontmatter;
if (!inFrontmatter) break;
continue;
}
if (!inFrontmatter) continue;
if (trimmed.startsWith('tools:')) {
inTools = true;
continue;
}
if (inTools) {
if (trimmed.startsWith('- ')) {
tools.push(trimmed.slice(2).trim());
} else if (trimmed && !trimmed.startsWith('#')) {
inTools = false;
}
}
}
return tools;
}
describe('#2119 — security auditor is return-only (no file writes)', () => {
const content = fs.readFileSync(AGENT_PATH, 'utf-8');
test('auditor tools do not include Write or Edit', () => {
const tools = parseYamlTools(content);
assert.ok(tools.length > 0, 'tools list should be non-empty');
assert.ok(
!tools.includes('Write'),
`Write must not be in auditor tools (got: ${tools.join(', ')}) — orchestrator is the sole SECURITY.md writer (#2119)`,
);
assert.ok(
!tools.includes('Edit'),
`Edit must not be in auditor tools (got: ${tools.join(', ')}) — orchestrator is the sole SECURITY.md writer (#2119)`,
);
});
test('auditor description does not claim to produce SECURITY.md', () => {
const lines = content.split(/\r?\n/);
const descLine = lines.find((l) => l.startsWith('description:'));
assert.ok(descLine, 'description field must exist');
assert.ok(
!descLine.includes('Produces SECURITY.md'),
'description must not claim to produce SECURITY.md — auditor returns a verdict, orchestrator writes (#2119)',
);
assert.ok(
descLine.includes('Returns structured') || descLine.includes('returns'),
'description should state the auditor returns a structured verdict',
);
});
});