Files
msd-core/tests/injection-blocking-config.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

79 lines
3.4 KiB
JavaScript

'use strict';
/**
* #1577 — `security.injection_blocking` is a first-class config key.
*
* The msd-read-injection-scanner hook reads `.planning/config.json`
* `security.injection_blocking` to decide whether a HIGH detection blocks
* (opt-in) vs. stays advisory (default). Before this, the key was unregistered:
* `isValidConfigKey` returned false and `msd config-set security.injection_blocking`
* was rejected as "Unknown config key" — the knob was settable only by hand-editing
* config.json. These tests lock the registration + the nested write shape the hook
* reads, and the advisory-by-default contract.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { createTempProject, cleanup, runMsdTools } = require('./helpers.cjs');
const { isValidConfigKey } = require('../msd-core/bin/lib/config-schema.cjs');
const { CONFIG_DEFAULTS } = require('../msd-core/bin/lib/configuration.cjs');
describe('#1577 — security.injection_blocking config key', () => {
test('isValidConfigKey accepts security.injection_blocking', () => {
assert.ok(
isValidConfigKey('security.injection_blocking'),
'security.injection_blocking must be a valid config key',
);
});
test('bare security section is not a settable leaf key', () => {
assert.ok(
!isValidConfigKey('security'),
'bare "security" must be rejected (use security.injection_blocking)',
);
});
test('CONFIG_DEFAULTS ships injection_blocking = false (advisory by default)', () => {
assert.equal(
CONFIG_DEFAULTS.security && CONFIG_DEFAULTS.security.injection_blocking,
false,
'default must be false so the hook stays advisory unless explicitly opted in',
);
});
test('config-set writes the nested shape the hook reads, and round-trips', () => {
const proj = createTempProject();
try {
const res = runMsdTools(['config-set', 'security.injection_blocking', 'true'], proj);
assert.ok(res.success, `config-set should succeed: ${res.output || ''}`);
// The hook reads cfg.security?.injection_blocking === true — assert the
// on-disk shape is the nested object it expects, not a flat dotted key.
const cfg = JSON.parse(fs.readFileSync(path.join(proj, '.planning', 'config.json'), 'utf8'));
assert.equal(cfg.security.injection_blocking, true, 'must persist nested security.injection_blocking');
assert.equal(cfg['security.injection_blocking'], undefined, 'must NOT persist a flat dotted key');
const get = runMsdTools(['config-get', 'security.injection_blocking'], proj);
assert.ok(get.success, `config-get should succeed: ${get.output || ''}`);
assert.match(String(get.output || ''), /true/, 'config-get should read back true');
} finally {
cleanup(proj);
}
});
test('a fresh project has no injection_blocking key — hook sees absent → advisory', () => {
const proj = createTempProject();
try {
const cfgPath = path.join(proj, '.planning', 'config.json');
const cfg = fs.existsSync(cfgPath) ? JSON.parse(fs.readFileSync(cfgPath, 'utf8')) : {};
// The hook's exact guard: cfg.security?.injection_blocking === true.
const blocking = cfg.security && cfg.security.injection_blocking === true;
assert.ok(!blocking, 'absent key must evaluate to advisory (not blocking)');
} finally {
cleanup(proj);
}
});
});