'use strict'; /** * capability-command-dispatch.test.cjs — unit tests for dispatchCapabilityCommand. * * ADR-959 phase 4d-impl-1. * Tests use synthetic registry + requireModule injections — no real bin/lib/ modules loaded. * Covers: happy path dispatch, unknown command fallback, empty/missing registry, prototype * pollution guard, router-not-a-function handling, module-load failure handling. */ const { describe, test } = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const { dispatchCapabilityCommand, dispatchOverlayCapabilityCommand, defaultRequireFromInstallRoot, } = require('../gsd-core/bin/gsd-tools.cjs'); const { cleanup } = require('./helpers.cjs'); // ─── Helpers ────────────────────────────────────────────────────────────────── /** * Build a synthetic registry with a single commandFamilies entry. */ function makeRegistry(families) { return { commandFamilies: families }; } /** * Build a requireModule that returns a module with a named router function. * The router records its call ctx into `calls` array. */ function makeRequireModule(moduleName, routerName, calls) { return function requireModule(m) { if (m !== moduleName) throw new Error('unexpected module: ' + m); const mod = {}; mod[routerName] = function (ctx) { calls.push(ctx); }; return mod; }; } // ─── 1. Happy path dispatch ─────────────────────────────────────────────────── describe('dispatchCapabilityCommand — happy path', () => { test('dispatches to the registered router and returns true', () => { const calls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = makeRequireModule('fake.cjs', 'routeFoo', calls); const result = dispatchCapabilityCommand({ command: 'foo', args: ['bar', '--baz'], cwd: '/some/path', raw: false, error: () => {}, registry, requireModule, }); assert.strictEqual(result, true, 'dispatch should return true'); assert.strictEqual(calls.length, 1, 'router should have been called once'); assert.deepEqual(calls[0].args, ['bar', '--baz'], 'args forwarded'); assert.strictEqual(calls[0].cwd, '/some/path', 'cwd forwarded'); assert.strictEqual(calls[0].raw, false, 'raw forwarded'); assert.strictEqual(typeof calls[0].error, 'function', 'error function forwarded'); }); test('returns true and dispatches when raw=true', () => { const calls = []; const registry = makeRegistry({ myCmd: { capId: 'c1', module: 'mycmd.cjs', router: 'routeMyCmd' }, }); const requireModule = makeRequireModule('mycmd.cjs', 'routeMyCmd', calls); const result = dispatchCapabilityCommand({ command: 'myCmd', args: [], cwd: '/proj', raw: true, error: () => {}, registry, requireModule, }); assert.strictEqual(result, true); assert.strictEqual(calls.length, 1); assert.strictEqual(calls[0].raw, true); }); }); // ─── 2. Unknown command → returns false ────────────────────────────────────── describe('dispatchCapabilityCommand — unknown command', () => { test('returns false when command not in registry', () => { const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => { throw new Error('should not load'); }; const result = dispatchCapabilityCommand({ command: 'nonexistent', args: [], cwd: '/p', raw: false, error: () => {}, registry, requireModule, }); assert.strictEqual(result, false); }); test('returns false when commandFamilies is empty ({})', () => { const registry = makeRegistry({}); const requireModule = () => { throw new Error('should not load'); }; const result = dispatchCapabilityCommand({ command: 'anything', args: [], cwd: '/p', raw: false, error: () => {}, registry, requireModule, }); assert.strictEqual(result, false); }); }); // ─── 3. Missing/empty registry → false, no throw ───────────────────────────── describe('dispatchCapabilityCommand — missing/empty registry', () => { test('registry=null → false, no throw', () => { assert.doesNotThrow(() => { const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: () => {}, registry: null, requireModule: () => {}, }); assert.strictEqual(result, false); }); }); test('registry with no commandFamilies property → false, no throw', () => { assert.doesNotThrow(() => { const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: () => {}, registry: { version: '1' }, requireModule: () => {}, }); assert.strictEqual(result, false); }); }); test('registry.commandFamilies=null → false, no throw', () => { assert.doesNotThrow(() => { const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: () => {}, registry: { commandFamilies: null }, requireModule: () => {}, }); assert.strictEqual(result, false); }); }); }); // ─── 4. Prototype pollution guard ──────────────────────────────────────────── describe('dispatchCapabilityCommand — prototype pollution guard', () => { test('__proto__ command → false, no pollution', () => { const result = dispatchCapabilityCommand({ command: '__proto__', args: [], cwd: '/p', raw: false, error: () => {}, registry: makeRegistry({}), requireModule: () => {}, }); assert.strictEqual(result, false, '__proto__ must return false'); }); test('constructor command → false, no pollution', () => { const result = dispatchCapabilityCommand({ command: 'constructor', args: [], cwd: '/p', raw: false, error: () => {}, registry: makeRegistry({}), requireModule: () => {}, }); assert.strictEqual(result, false, 'constructor must return false'); }); test('prototype command → false, no pollution', () => { const result = dispatchCapabilityCommand({ command: 'prototype', args: [], cwd: '/p', raw: false, error: () => {}, registry: makeRegistry({}), requireModule: () => {}, }); assert.strictEqual(result, false, 'prototype must return false'); }); }); // ─── 5. Router not a function → handled, no throw ──────────────────────────── describe('dispatchCapabilityCommand — router not a function', () => { test('router export is missing → does not throw, returns true (consumed)', () => { const errors = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeNotPresent' }, }); const requireModule = () => ({ somethingElse: 'not-a-function' }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, requireModule, }); }); // Per ADR-959 design: router-not-a-function is a consumed dispatch (returns true) // with a diagnostic error, so we don't fall through to "Unknown command" assert.strictEqual(result, true, 'consumed dispatch even when router is not a function'); assert.ok(errors.length > 0, 'should emit a diagnostic error'); }); test('router export is null → does not throw', () => { const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => ({ routeFoo: null }); assert.doesNotThrow(() => { dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: () => {}, registry, requireModule, }); }); }); }); // ─── 6. Module load failure → handled, no uncaught throw ───────────────────── describe('dispatchCapabilityCommand — module load failure', () => { test('requireModule throws → does not propagate, returns true (consumed)', () => { const errors = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'nonexistent.cjs', router: 'routeFoo' }, }); const requireModule = () => { throw new Error('MODULE_NOT_FOUND'); }; let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, requireModule, }); }); assert.strictEqual(result, true, 'module-load failure returns true (consumed)'); assert.ok(errors.length > 0, 'should emit a diagnostic error'); }); }); // ─── 7. Module confinement — default requireModule refuses out-of-lib paths ─── describe('dispatchCapabilityCommand — module confinement (default requireModule)', () => { test('entry.module "../../evil.cjs" does not escape bin/lib/ — returns true (consumed), no require', () => { // Bypasses the generator's validation by hand-crafting a registry entry. // The default requireModule must refuse the path and treat it as a load failure // (returns true = consumed, emits a diagnostic error) rather than require()ing it. const errors = []; const registry = makeRegistry({ foo: { capId: 'x', module: '../../evil.cjs', router: 'routeFoo' }, }); // Use NO injected requireModule so the real default loader (with confinement check) runs. // But we cannot actually hit the real require() since the path wouldn't exist; // we verify the confinement check fires before any require by checking the error message. let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, // requireModule NOT injected → real default loader runs }); }); // Confinement violation: treated as a load failure → consumed (true), diagnostic emitted assert.strictEqual(result, true, 'confinement violation must return true (consumed)'); assert.ok(errors.length > 0, 'confinement violation must emit a diagnostic error'); // The diagnostic must mention the module (not a generic node MODULE_NOT_FOUND) assert.ok( errors[0].includes('../../evil.cjs') || errors[0].includes('evil.cjs'), 'diagnostic should reference the offending module; got: ' + errors[0], ); }); test('entry.module "../sibling.cjs" also refused by confinement check', () => { const errors = []; const registry = makeRegistry({ bar: { capId: 'y', module: '../sibling.cjs', router: 'routeBar' }, }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'bar', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, // requireModule NOT injected → real default loader runs }); }); assert.strictEqual(result, true, 'confinement violation must return true (consumed)'); assert.ok(errors.length > 0, 'confinement violation must emit a diagnostic error'); }); }); // ─── 7b. FIX 1: bare .cjs basename validation (no extension → refused) ───────── describe('dispatchCapabilityCommand — FIX 1: bare .cjs basename enforcement (default requireModule)', () => { test('entry.module "foo" (no .cjs) is refused by default requireModule — returns true (consumed), no require of foo.js', () => { // A hand-edited registry entry with module: "foo" (no extension) must be // rejected by the basename pattern check BEFORE any filesystem access. // The confinement test in section 7 verifies path-traversal; this verifies // the extension/basename invariant that prevents node resolving foo.js or // foo/index.js from inside bin/lib/. const errors = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'foo', router: 'routeFoo' }, }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, // requireModule NOT injected → real default loader runs }); }); // Refused → consumed (true), diagnostic emitted assert.strictEqual(result, true, 'bare-module-no-cjs must return true (consumed)'); assert.ok(errors.length > 0, 'must emit a diagnostic error'); // Diagnostic must mention the offending module name assert.ok( errors[0].includes('foo'), 'diagnostic should reference the offending module name; got: ' + errors[0], ); }); test('entry.module "foo.js" (wrong extension) is also refused', () => { const errors = []; const registry = makeRegistry({ bar: { capId: 'y', module: 'foo.js', router: 'routeBar' }, }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'bar', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, }); }); assert.strictEqual(result, true, 'wrong-extension must return true (consumed)'); assert.ok(errors.length > 0, 'must emit a diagnostic error'); }); }); // ─── 7c. FIX 2: own-property guard on router export ─────────────────────────── describe('dispatchCapabilityCommand — FIX 2: own-property guard on router export', () => { test('entry.router "constructor" (inherited prototype property) is not invoked — treated as miss, returns true (consumed)', () => { // A registry entry with router: "constructor" must be refused by the own- // property guard. The module's own exports do NOT include "constructor" as // an own property, but Object.prototype does via the prototype chain. // Without the guard, mod["constructor"] would return Function (the Object // constructor) — typeof Function === 'function' — and it would be invoked. const errors = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'constructor' }, }); // Injected module whose OWN exports do NOT include 'constructor' const requireModule = () => ({ someOwnProp: () => {} }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, requireModule, }); }); assert.strictEqual(result, true, 'inherited-constructor router must return true (consumed)'); assert.ok(errors.length > 0, 'must emit a diagnostic error'); }); test('entry.router "toString" (inherited prototype method) is not invoked', () => { const errors = []; const registry = makeRegistry({ bar: { capId: 'y', module: 'fake.cjs', router: 'toString' }, }); const requireModule = () => ({ realRouter: () => {} }); let result; assert.doesNotThrow(() => { result = dispatchCapabilityCommand({ command: 'bar', args: [], cwd: '/p', raw: false, error: (msg) => errors.push(msg), registry, requireModule, }); }); assert.strictEqual(result, true, 'inherited-toString router must return true (consumed)'); assert.ok(errors.length > 0, 'must emit a diagnostic error'); }); test('entry.router that IS an own property is still dispatched normally', () => { // Regression: ensure the own-property guard does not break the happy path. const calls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = makeRequireModule('fake.cjs', 'routeFoo', calls); const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: () => {}, registry, requireModule, }); assert.strictEqual(result, true, 'own-property router must still dispatch'); assert.strictEqual(calls.length, 1, 'router must have been called'); }); }); // ─── 8. Router throws — structured error handling ──────────────────────────── const { ExitError } = require('../gsd-core/bin/lib/cli-exit.cjs'); describe('dispatchCapabilityCommand — non-ExitError from router → structured error via error()', () => { test('router throws TypeError → injected error() called with attributed message, raw error does NOT propagate', () => { // A capability plug-in command's unexpected failure must surface as a // structured, attributed error (honoring --json-errors / SDK consumers), // not a raw stack trace bypassing the error formatter. const errorCalls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => ({ routeFoo: () => { throw new TypeError('boom'); }, }); // Must NOT throw — the raw TypeError must be caught and routed through error() assert.doesNotThrow(() => { dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); }); assert.strictEqual(errorCalls.length, 1, 'error() should be called exactly once'); const { msg, reason } = errorCalls[0]; // Message must name the command, router, module, and original error message assert.ok(msg.includes('foo'), 'message must name the command; got: ' + msg); assert.ok(msg.includes('routeFoo'), 'message must name the router; got: ' + msg); assert.ok(msg.includes('fake.cjs'), 'message must name the module; got: ' + msg); assert.ok(msg.includes('boom'), 'message must include original error message; got: ' + msg); // Reason must be SDK_FAIL_FAST const { ERROR_REASON } = require('../gsd-core/bin/lib/io.cjs'); assert.strictEqual(reason, ERROR_REASON.SDK_FAIL_FAST, 'reason must be SDK_FAIL_FAST'); }); test('router throws a generic Error → same structured attribution, does not propagate', () => { const errorCalls = []; const registry = makeRegistry({ bar: { capId: 'y', module: 'bar.cjs', router: 'routeBar' }, }); const requireModule = () => ({ routeBar: () => { throw new Error('unexpected failure'); }, }); assert.doesNotThrow(() => { dispatchCapabilityCommand({ command: 'bar', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); }); assert.strictEqual(errorCalls.length, 1, 'error() should be called exactly once'); assert.ok(errorCalls[0].msg.includes('bar'), 'message must name the command'); assert.ok(errorCalls[0].msg.includes('unexpected failure'), 'message must include original error'); }); test('router throws an ExitError → propagates unchanged, error() is NOT called', () => { // An ExitError comes from the router calling its own error() (intentional // structured exit). It must propagate untouched so message/code/json-mode // are preserved. const errorCalls = []; const thrown = new ExitError(1, 'intentional-exit'); const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => ({ routeFoo: () => { throw thrown; }, }); let caught; try { dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); } catch (e) { caught = e; } // The exact ExitError must have been rethrown assert.strictEqual(caught, thrown, 'the original ExitError must propagate unchanged'); // error() must NOT have been called assert.strictEqual(errorCalls.length, 0, 'error() must not be called when an ExitError propagates'); }); test('router returns normally → returns true, error() not called', () => { const errorCalls = []; const calls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = makeRequireModule('fake.cjs', 'routeFoo', calls); const result = dispatchCapabilityCommand({ command: 'foo', args: ['a'], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); assert.strictEqual(result, true, 'successful dispatch must return true'); assert.strictEqual(errorCalls.length, 0, 'error() must not be called on success'); assert.strictEqual(calls.length, 1, 'router must have been called once'); }); }); // ─── 10. Async router (thenable) → structured error ───────────────────────── describe('dispatchCapabilityCommand — async router returns a Promise → structured error', () => { const { ERROR_REASON } = require('../gsd-core/bin/lib/io.cjs'); test('router returns Promise.resolve() → error() called with "must be synchronous" + SDK_FAIL_FAST', () => { const errorCalls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => ({ routeFoo: () => Promise.resolve(), }); // Must NOT throw — the thenable check surfaces via error(), not an exception assert.doesNotThrow(() => { dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); }); assert.strictEqual(errorCalls.length, 1, 'error() should be called exactly once'); const { msg, reason } = errorCalls[0]; assert.ok(msg.includes('must be synchronous'), 'message must say "must be synchronous"; got: ' + msg); assert.ok(msg.includes('foo'), 'message must name the command; got: ' + msg); assert.ok(msg.includes('routeFoo'), 'message must name the router; got: ' + msg); assert.ok(msg.includes('fake.cjs'), 'message must name the module; got: ' + msg); assert.strictEqual(reason, ERROR_REASON.SDK_FAIL_FAST, 'reason must be SDK_FAIL_FAST'); }); test('router returns Promise.reject() → error() called with "must be synchronous", async rejection does NOT escape', () => { const errorCalls = []; const registry = makeRegistry({ bar: { capId: 'y', module: 'bar.cjs', router: 'routeBar' }, }); // Attach .catch(()=>{}) immediately so the test process does not log an // unhandled-rejection warning for the returned (un-awaited) rejected Promise. const rejectedPromise = Promise.reject(new Error('async failure')); rejectedPromise.catch(() => {}); const requireModule = () => ({ routeBar: () => rejectedPromise, }); assert.doesNotThrow(() => { dispatchCapabilityCommand({ command: 'bar', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); }); assert.strictEqual(errorCalls.length, 1, 'error() should be called exactly once'); const { msg, reason } = errorCalls[0]; assert.ok(msg.includes('must be synchronous'), 'message must say "must be synchronous"; got: ' + msg); assert.ok(msg.includes('bar'), 'message must name the command; got: ' + msg); assert.ok(msg.includes('routeBar'), 'message must name the router; got: ' + msg); assert.ok(msg.includes('bar.cjs'), 'message must name the module; got: ' + msg); assert.strictEqual(reason, ERROR_REASON.SDK_FAIL_FAST, 'reason must be SDK_FAIL_FAST'); }); test('sync router that returns undefined (normal) still dispatches without error', () => { // Regression: ensure the thenable guard does not fire on undefined return const errorCalls = []; const calls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = makeRequireModule('fake.cjs', 'routeFoo', calls); const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); assert.strictEqual(result, true, 'sync router must return true'); assert.strictEqual(errorCalls.length, 0, 'error() must not be called for sync router'); assert.strictEqual(calls.length, 1, 'router must have been called'); }); test('sync router that returns a non-thenable object does not trigger thenable guard', () => { // A router that returns a plain object (not a Promise) must not be rejected. const errorCalls = []; const registry = makeRegistry({ foo: { capId: 'x', module: 'fake.cjs', router: 'routeFoo' }, }); const requireModule = () => ({ routeFoo: () => ({ status: 'ok' }), // plain object, not thenable }); const result = dispatchCapabilityCommand({ command: 'foo', args: [], cwd: '/p', raw: false, error: (msg, reason) => { errorCalls.push({ msg, reason }); }, registry, requireModule, }); assert.strictEqual(result, true, 'sync router returning plain object must return true'); assert.strictEqual(errorCalls.length, 0, 'error() must not be called'); }); }); // ─── 9. Behavior-preservation: real registry commandFamilies ──────────────── describe('dispatchCapabilityCommand — real registry behavior-preservation', () => { test('real capability-registry.cjs commandFamilies is exported and is an object', () => { // Phase 4d-impl-2: graphify was the first capability to declare a command family. // This test was originally written as "commandFamilies must be empty today" but // now asserts the structural contract instead (exported, object) since the graphify // cutover populates it. const realRegistry = require('../gsd-core/bin/lib/capability-registry.cjs'); assert.ok(realRegistry.commandFamilies, 'commandFamilies must be exported'); assert.strictEqual(typeof realRegistry.commandFamilies, 'object', 'commandFamilies must be an object'); // graphify is the first (and currently only) real capability command family assert.ok( Object.prototype.hasOwnProperty.call(realRegistry.commandFamilies, 'graphify'), 'real registry commandFamilies must include graphify after 4d-impl-2 cutover', ); }); test('unknown command against real registry returns false (behavior-preserving)', () => { const realRegistry = require('../gsd-core/bin/lib/capability-registry.cjs'); const result = dispatchCapabilityCommand({ command: 'some-unknown-command-xyz', args: [], cwd: process.cwd(), raw: false, error: () => {}, registry: realRegistry, requireModule: () => { throw new Error('should not load'); }, }); assert.strictEqual(result, false, 'unknown command against real registry must return false'); }); }); // ═══════════════════════════════════════════════════════════════════════════════ // ADR-1244 Phase 5 (D7) — third-party overlay command dispatch // ═══════════════════════════════════════════════════════════════════════════════ /** Synthetic overlay registry: commandFamilies + _overlay.commandRoots (capId → install dir). */ function makeOverlayRegistry(families, commandRoots) { return { commandFamilies: families, _overlay: { warnings: [], incompatibleGateCapIds: [], blockedGates: [], commandRoots } }; } describe('dispatchOverlayCapabilityCommand — third-party overlay (Phase 5)', () => { test('happy path: a third-party family (capId in commandRoots) dispatches from its install root', () => { const calls = []; const loadRegistry = () => makeOverlayRegistry( { mycmd: { capId: 'thirdparty', module: 'router.cjs', router: 'run' } }, { thirdparty: '/install/root/thirdparty' }, ); const requireModule = (installRoot, m) => { assert.strictEqual(installRoot, '/install/root/thirdparty', 'module required FROM the install root'); assert.strictEqual(m, 'router.cjs'); return { run: (ctx) => calls.push(ctx) }; }; const result = dispatchOverlayCapabilityCommand({ command: 'mycmd', args: ['a'], cwd: '/p', raw: false, error: () => {}, loadRegistry, requireModule, }); assert.strictEqual(result, true); assert.strictEqual(calls.length, 1); assert.deepEqual(calls[0].args, ['a']); }); test('a FIRST-PARTY family (capId NOT in commandRoots) falls through (handled by frozen-registry dispatch)', () => { let required = false; const loadRegistry = () => makeOverlayRegistry( { graphify: { capId: 'graphify', module: 'graphify-command-router.cjs', router: 'routeGraphifyCommand' } }, {}, // graphify is first-party → not in commandRoots ); const result = dispatchOverlayCapabilityCommand({ command: 'graphify', args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry, requireModule: () => { required = true; return {}; }, }); assert.strictEqual(result, false, 'first-party must fall through, not be dispatched as overlay'); assert.strictEqual(required, false, 'first-party module must NOT be required from an install root'); }); test('unknown family → false', () => { const loadRegistry = () => makeOverlayRegistry({}, {}); assert.strictEqual(dispatchOverlayCapabilityCommand({ command: 'nope', args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry, requireModule: () => ({}) }), false); }); test('no _overlay / no commandRoots on the registry → false', () => { assert.strictEqual(dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry: () => ({ commandFamilies: { x: { capId: 'x', module: 'm.cjs', router: 'r' } } }), requireModule: () => ({}) }), false); }); test('loadRegistry throwing → false (falls through to Unknown)', () => { assert.strictEqual(dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry: () => { throw new Error('overlay scan failed'); }, requireModule: () => ({}) }), false); }); test('prototype-pollution command keys → false (never reach the registry)', () => { for (const command of ['__proto__', 'constructor', 'prototype']) { let loaded = false; const r = dispatchOverlayCapabilityCommand({ command, args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry: () => { loaded = true; return makeOverlayRegistry({}, {}); }, requireModule: () => ({}) }); assert.strictEqual(r, false); assert.strictEqual(loaded, false, command + ' must short-circuit before loadRegistry'); } }); test('CONSENT NEGATIVE PROOF: a family whose capId is absent from commandRoots is never require()d', () => { // Models an unconsented/_pending cap: the loader excludes it from commandRoots, so even though // the (synthetic) commandFamilies names it, dispatch must NOT load its module. let required = false; const loadRegistry = () => makeOverlayRegistry( { evil: { capId: 'evil', module: 'evil.cjs', router: 'run' } }, {}, // 'evil' NOT consented → absent from commandRoots ); const result = dispatchOverlayCapabilityCommand({ command: 'evil', args: [], cwd: '/p', raw: false, error: () => {}, loadRegistry, requireModule: () => { required = true; return { run() {} }; } }); assert.strictEqual(result, false); assert.strictEqual(required, false, 'an unconsented capability module must never be required'); }); test('module load failure → error diagnostic + consumed (true)', () => { const errs = []; const loadRegistry = () => makeOverlayRegistry({ x: { capId: 'tp', module: 'm.cjs', router: 'r' } }, { tp: '/root' }); const result = dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m) => errs.push(m), loadRegistry, requireModule: () => { throw new Error('boom'); } }); assert.strictEqual(result, true); assert.ok(errs.some((e) => /failed to load from its install root/.test(e))); }); test('router not an own export → error + consumed', () => { const errs = []; const loadRegistry = () => makeOverlayRegistry({ x: { capId: 'tp', module: 'm.cjs', router: 'toString' } }, { tp: '/root' }); const result = dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m) => errs.push(m), loadRegistry, requireModule: () => ({}) }); assert.strictEqual(result, true); assert.ok(errs.some((e) => /is not an own export/.test(e))); }); test('router not a function → error + consumed', () => { const errs = []; const loadRegistry = () => makeOverlayRegistry({ x: { capId: 'tp', module: 'm.cjs', router: 'r' } }, { tp: '/root' }); const result = dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m) => errs.push(m), loadRegistry, requireModule: () => ({ r: 42 }) }); assert.strictEqual(result, true); assert.ok(errs.some((e) => /is not a function/.test(e))); }); test('async router (returns a Promise) → SDK fail-fast diagnostic', () => { const errs = []; const loadRegistry = () => makeOverlayRegistry({ x: { capId: 'tp', module: 'm.cjs', router: 'r' } }, { tp: '/root' }); dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m) => errs.push(m), loadRegistry, requireModule: () => ({ r: () => Promise.resolve() }) }); assert.ok(errs.some((e) => /must be synchronous/.test(e))); }); }); // ─── defaultRequireFromInstallRoot — real-filesystem confinement (negative proof) ─── describe('defaultRequireFromInstallRoot — install-root confinement (Phase 5)', () => { const dirs = []; const mkroot = () => { const d = fs.mkdtempSync(path.join(os.tmpdir(), 'cap-disp-')); dirs.push(d); return d; }; test.after(() => { for (const d of dirs) cleanup(d); }); test('loads a bare .cjs module that lives inside the install root', () => { const root = mkroot(); fs.writeFileSync(path.join(root, 'router.cjs'), 'module.exports = { run: () => 7 };', 'utf8'); const mod = defaultRequireFromInstallRoot(root, 'router.cjs'); assert.strictEqual(mod.run(), 7); }); test('rejects a non-.cjs / path-separator / .. module name', () => { const root = mkroot(); assert.throws(() => defaultRequireFromInstallRoot(root, 'router.js'), /bare \.cjs basename/); assert.throws(() => defaultRequireFromInstallRoot(root, '../escape.cjs'), /bare \.cjs basename/); assert.throws(() => defaultRequireFromInstallRoot(root, 'sub/router.cjs'), /bare \.cjs basename/); assert.throws(() => defaultRequireFromInstallRoot(root, '/abs/router.cjs'), /bare \.cjs basename/); }); test('NEGATIVE PROOF: a symlinked module pointing OUTSIDE the install root is not loaded', () => { const root = mkroot(); const outside = mkroot(); const secret = path.join(outside, 'secret.cjs'); fs.writeFileSync(secret, 'module.exports = { run: () => "PWNED" };', 'utf8'); // A bare-basename symlink inside the root whose real target escapes the root. let linked = true; try { fs.symlinkSync(secret, path.join(root, 'router.cjs')); } catch { linked = false; } if (!linked) return; // platform without symlink perms — skip assert.throws(() => defaultRequireFromInstallRoot(root, 'router.cjs'), /outside its install root/); }); }); // ─── End-to-end: real loadRegistry + real require + real ledger (consent + confinement) ─── describe('dispatchOverlayCapabilityCommand — end-to-end (real loadRegistry, real require, real ledger)', () => { const homes = []; let savedGsdHome; const mkhome = () => { const h = fs.mkdtempSync(path.join(os.tmpdir(), 'cap-e2e-')); homes.push(h); return h; }; function validCap(id, family) { return { id, role: 'feature', version: '1.0.0', title: id, description: 'e2e cap', tier: 'standard', requires: [], engines: { gsd: '>=1.0.0' }, runtimeCompat: { supported: ['*'], unsupported: [] }, skills: [], agents: [], hooks: [], config: {}, steps: [], contributions: [], gates: [], commands: [{ family, module: 'router.cjs', router: 'run' }], }; } // The router writes a marker file so "did it execute?" is a filesystem fact (negative proof). const ROUTER_BODY = "module.exports = { run: (ctx) => { require('fs').writeFileSync(require('path').join(ctx.cwd, 'RAN.txt'), String((ctx.args||[]).join(','))); } };"; function placeBundle(home, id, family, { committed }) { const dir = path.join(home, '.gsd', 'capabilities', id); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(path.join(dir, 'capability.json'), JSON.stringify(validCap(id, family)), 'utf8'); fs.writeFileSync(path.join(dir, 'router.cjs'), ROUTER_BODY, 'utf8'); if (committed) { fs.writeFileSync( path.join(home, '.gsd-capabilities.json'), JSON.stringify({ version: '1', updatedAt: 'x', entries: { [id]: { id, version: '1.0.0', source: 's', integrity: '', files: [], sharedEdits: [] } } }), 'utf8', ); } } test.beforeEach(() => { savedGsdHome = process.env.GSD_HOME; }); test.afterEach(() => { if (savedGsdHome === undefined) delete process.env.GSD_HOME; else process.env.GSD_HOME = savedGsdHome; }); test.after(() => { for (const h of homes) cleanup(h); }); test('a COMMITTED (consented) third-party command runs, from its install root', () => { const home = mkhome(); placeBundle(home, 'e2ecap', 'e2e-cmd', { committed: true }); process.env.GSD_HOME = home; // global overlay scope = home/.gsd/capabilities const errs = []; const result = dispatchOverlayCapabilityCommand({ command: 'e2e-cmd', args: ['hello'], cwd: home, raw: false, error: (m) => errs.push(m) }); assert.strictEqual(result, true, 'consented command consumed: ' + JSON.stringify(errs)); assert.strictEqual(fs.readFileSync(path.join(home, 'RAN.txt'), 'utf8'), 'hello', 'router executed with forwarded args'); }); test('NEGATIVE PROOF: a dropped bundle with NO ledger entry is never dispatched / never executes', () => { const home = mkhome(); placeBundle(home, 'evilcap', 'evil-cmd', { committed: false }); // bundle on disk, NO ledger process.env.GSD_HOME = home; const result = dispatchOverlayCapabilityCommand({ command: 'evil-cmd', args: ['x'], cwd: home, raw: false, error: () => {} }); assert.strictEqual(result, false, 'unconsented family must fall through to Unknown'); assert.strictEqual(fs.existsSync(path.join(home, 'RAN.txt')), false, 'the dropped module must NEVER execute'); }); }); // ─── Overlay router error semantics (parity with the first-party path) ─── describe('dispatchOverlayCapabilityCommand — router error semantics', () => { function overlayReg() { return { commandFamilies: { x: { capId: 'tp', module: 'm.cjs', router: 'run' } }, _overlay: { warnings: [], incompatibleGateCapIds: [], blockedGates: [], commandRoots: { tp: '/root' } } }; } test('overlay router throwing an ExitError → propagates unchanged, error() NOT called', () => { const thrown = new ExitError(1, 'intentional-exit'); const errs = []; let caught; try { dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m) => errs.push(m), loadRegistry: overlayReg, requireModule: () => ({ run: () => { throw thrown; } }), }); } catch (e) { caught = e; } assert.strictEqual(caught, thrown, 'the original ExitError must propagate unchanged'); assert.strictEqual(errs.length, 0, 'error() must not be called when an ExitError propagates'); }); test('overlay router throwing a generic Error → attributed error() + consumed (true)', () => { const errs = []; const result = dispatchOverlayCapabilityCommand({ command: 'x', args: [], cwd: '/p', raw: false, error: (m, reason) => errs.push({ m, reason }), loadRegistry: overlayReg, requireModule: () => ({ run: () => { throw new Error('kaboom'); } }), }); assert.strictEqual(result, true, 'consumed'); assert.ok(errs.some((e) => /threw: kaboom/.test(e.m)), 'router throw attributed to the command'); }); });