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

@@ -5,7 +5,7 @@
*
* Tests for resolveCapabilitySource + parseSpec:
* - parseSpec kind-detection table (all kinds + error cases)
* - local adapter: happy path, invalid manifest, engines.gsd incompatibility
* - local adapter: happy path, invalid manifest, engines.msd incompatibility
* - registry kind: throws 'not yet implemented'
* - tarball adapter: integrity matching / mismatching (via injected HTTP seam)
* - security: shell metacharacters in specs/args → only reach exec override as
@@ -24,7 +24,7 @@ const crypto = require('node:crypto');
const { cleanup, createTempDir } = require('./helpers.cjs');
// The module under test — loaded from the built .cjs artifact.
const capSource = require('../gsd-core/bin/lib/capability-source.cjs');
const capSource = require('../msd-core/bin/lib/capability-source.cjs');
const {
resolveCapabilitySource,
parseSpec,
@@ -65,7 +65,7 @@ function featureCap(id, extra = {}) {
description: 'test capability',
tier: 'standard',
requires: [],
engines: { gsd: '>=1.0.0' },
engines: { msd: '>=1.0.0' },
runtimeCompat: { supported: ['*'], unsupported: [] },
skills: [],
agents: [],
@@ -83,7 +83,7 @@ function featureCap(id, extra = {}) {
* Returns the directory path.
*/
function makeLocalCap(cap) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-cap-local-'));
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'msd-cap-local-'));
fs.writeFileSync(path.join(dir, 'capability.json'), JSON.stringify(cap), 'utf8');
return dir;
}
@@ -193,21 +193,21 @@ describe('parseSpec — kind detection', () => {
// ---------------------------------------------------------------------------
describe('local adapter — happy path', () => {
let gsdHome = '';
let msdHome = '';
let capDir = '';
beforeEach(() => {
gsdHome = createTempDir('gsd-home-');
msdHome = createTempDir('msd-home-');
capDir = makeLocalCap(featureCap('test-cap-local'));
});
afterEach(() => {
cleanup(gsdHome);
cleanup(msdHome);
cleanup(capDir);
});
test('resolves a valid local capability — staged dir exists with capability.json', async () => {
const result = await resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' });
const result = await resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' });
assert.strictEqual(result.id, 'test-cap-local');
assert.strictEqual(result.version, '1.0.0');
assert.ok(fs.existsSync(result.stagedDir), 'staged dir must exist');
@@ -218,24 +218,24 @@ describe('local adapter — happy path', () => {
assert.strictEqual(result.source, capDir);
});
test('staging creates the capability under <gsdHome>/.gsd/capabilities/<id>/', async () => {
const result = await resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' });
const expectedDir = path.join(gsdHome, '.gsd', 'capabilities', 'test-cap-local');
test('staging creates the capability under <msdHome>/.msd/capabilities/<id>/', async () => {
const result = await resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' });
const expectedDir = path.join(msdHome, '.msd', 'capabilities', 'test-cap-local');
assert.strictEqual(result.stagedDir, expectedDir);
assert.ok(fs.existsSync(expectedDir));
});
test('skipEnginesGate:true stages an engines-incompatible capability without throwing', async () => {
const cap = featureCap('test-cap-local');
cap.engines = { gsd: '>=99.0.0' };
cap.engines = { msd: '>=99.0.0' };
const incompatDir = makeLocalCap(cap);
// Default: the engines gate throws.
await assert.rejects(
() => resolveCapabilitySource(incompatDir, { gsdHome, hostVersion: '1.6.0' }),
/engines\.gsd/,
() => resolveCapabilitySource(incompatDir, { msdHome, hostVersion: '1.6.0' }),
/engines\.msd/,
);
// skipEnginesGate: the resolver stages it (copy-only) and leaves the gate to the caller.
const r = await resolveCapabilitySource(incompatDir, { gsdHome, hostVersion: '1.6.0', skipEnginesGate: true, promote: false });
const r = await resolveCapabilitySource(incompatDir, { msdHome, hostVersion: '1.6.0', skipEnginesGate: true, promote: false });
assert.strictEqual(r.id, 'test-cap-local');
assert.ok(fs.existsSync(path.join(r.stagedDir, 'capability.json')));
cleanup(incompatDir);
@@ -243,9 +243,9 @@ describe('local adapter — happy path', () => {
});
test('promote:false validates but does NOT promote — returns the staging dir, final dir absent', async () => {
const result = await resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0', promote: false });
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'test-cap-local');
const stagingRoot = path.join(gsdHome, '.gsd', 'capabilities', '.staging');
const result = await resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0', promote: false });
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'test-cap-local');
const stagingRoot = path.join(msdHome, '.msd', 'capabilities', '.staging');
assert.notStrictEqual(result.stagedDir, finalDir, 'must not be the final dir');
assert.ok(result.stagedDir.startsWith(stagingRoot), 'staged dir is under .staging');
assert.ok(fs.existsSync(path.join(result.stagedDir, 'capability.json')), 'staged manifest present');
@@ -254,10 +254,10 @@ describe('local adapter — happy path', () => {
});
describe('local adapter — invalid manifest', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('manifest missing "version" field → throws AND no staged dir remains', async () => {
const cap = featureCap('no-version-cap');
@@ -266,7 +266,7 @@ describe('local adapter — invalid manifest', () => {
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
(err) => {
assert.ok(err instanceof Error, 'must throw an Error');
return true;
@@ -277,7 +277,7 @@ describe('local adapter — invalid manifest', () => {
}
// No staged dir should remain.
const capabilitiesDir = path.join(gsdHome, '.gsd', 'capabilities');
const capabilitiesDir = path.join(msdHome, '.msd', 'capabilities');
if (fs.existsSync(capabilitiesDir)) {
const entries = fs.readdirSync(capabilitiesDir).filter((e) => e !== '.staging');
assert.strictEqual(entries.length, 0, 'No capability dirs must remain after failure');
@@ -291,14 +291,14 @@ describe('local adapter — invalid manifest', () => {
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
/valid|role|validation/i
);
} finally {
cleanup(capDir);
}
const capabilitiesDir = path.join(gsdHome, '.gsd', 'capabilities');
const capabilitiesDir = path.join(msdHome, '.msd', 'capabilities');
if (fs.existsSync(capabilitiesDir)) {
const entries = fs.readdirSync(capabilitiesDir).filter((e) => e !== '.staging');
assert.strictEqual(entries.length, 0, 'No capability dirs must remain after failure');
@@ -309,7 +309,7 @@ describe('local adapter — invalid manifest', () => {
const dir = createTempDir('no-manifest-');
try {
await assert.rejects(
() => resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' }),
/capability\.json/i
);
} finally {
@@ -318,27 +318,27 @@ describe('local adapter — invalid manifest', () => {
});
});
describe('local adapter — engines.gsd incompatibility', () => {
let gsdHome = '';
describe('local adapter — engines.msd incompatibility', () => {
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('engines.gsd ">=99.0.0" with hostVersion 1.5.0 → throws before staging', async () => {
const cap = featureCap('incompat-cap', { engines: { gsd: '>=99.0.0' } });
test('engines.msd ">=99.0.0" with hostVersion 1.5.0 → throws before staging', async () => {
const cap = featureCap('incompat-cap', { engines: { msd: '>=99.0.0' } });
const capDir = makeLocalCap(cap);
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
/engines\.gsd|requires|incompatible/i
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
/engines\.msd|requires|incompatible/i
);
} finally {
cleanup(capDir);
}
// No staged directory should exist.
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'incompat-cap');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'incompat-cap');
assert.ok(!fs.existsSync(finalDir), 'staged dir must not exist for incompatible capability');
});
});
@@ -350,7 +350,7 @@ describe('local adapter — engines.gsd incompatibility', () => {
describe('registry kind', () => {
test('throws "not yet implemented" for registry specs', async () => {
await assert.rejects(
() => resolveCapabilitySource('my-cap@1.0.0', { gsdHome: os.tmpdir(), hostVersion: '1.5.0' }),
() => resolveCapabilitySource('my-cap@1.0.0', { msdHome: os.tmpdir(), hostVersion: '1.5.0' }),
/not yet implemented/i
);
});
@@ -361,12 +361,12 @@ describe('registry kind', () => {
// ---------------------------------------------------------------------------
describe('tarball adapter — integrity via _setCapabilitySourceHttpGet', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => {
_setCapabilitySourceHttpGet(null); // restore real transport
cleanup(gsdHome);
cleanup(msdHome);
});
test('matching integrity → resolves successfully', async () => {
@@ -380,7 +380,7 @@ describe('tarball adapter — integrity via _setCapabilitySourceHttpGet', () =>
const result = await resolveCapabilitySource(
'https://example.com/tarball-cap.tgz',
{
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity,
execOverrides: {
@@ -422,7 +422,7 @@ describe('tarball adapter — integrity via _setCapabilitySourceHttpGet', () =>
await assert.rejects(
() =>
resolveCapabilitySource('https://example.com/tarball-mismatch.tgz', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity: badIntegrity,
execOverrides: {
@@ -446,7 +446,7 @@ describe('tarball adapter — integrity via _setCapabilitySourceHttpGet', () =>
assert.strictEqual(tarCalls, 0, 'tar must NOT be invoked — integrity verified over the .tgz bytes before extraction');
// No staged directory must exist.
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'tarball-mismatch');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'tarball-mismatch');
assert.ok(!fs.existsSync(finalDir), 'staged dir must NOT exist after integrity mismatch');
});
});
@@ -462,9 +462,9 @@ describe('tarball adapter — integrity via _setCapabilitySourceHttpGet', () =>
// ---------------------------------------------------------------------------
describe('#1460 CS-1 — supplied --integrity is verified or rejected per source (never silently dropped)', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
/** Build a fake `npm pack` that writes a real .tgz of `tgzBytes` to the --pack-destination. */
function fakeNpmPack(tgzBytes) {
@@ -499,7 +499,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
const integrity = sha512b64(tgzBytes);
const result = await resolveCapabilitySource('npm:@org/npm-int-ok@^1.0.0', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity,
execOverrides: { npm: fakeNpmPack(tgzBytes), tar: fakeTar(cap) },
@@ -524,7 +524,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
await assert.rejects(
() => resolveCapabilitySource('npm:@org/npm-int-bad@^1.0.0', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity: badIntegrity,
execOverrides: { npm: fakeNpmPack(tgzBytes), tar: instrumentedTar },
@@ -535,7 +535,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
// Integrity is verified over the raw .tgz bytes BEFORE any tar call — ordering invariant.
assert.strictEqual(tarCalls, 0, 'tar extraction must NOT run — integrity verified over the .tgz bytes before extraction');
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'npm-int-bad');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'npm-int-bad');
assert.ok(!fs.existsSync(finalDir), 'no final dir after integrity mismatch');
});
@@ -549,7 +549,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
await assert.rejects(
() => resolveCapabilitySource('https://github.com/org/repo.git#v1.0.0', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity: 'sha512-' + Buffer.from('anything').toString('base64'),
execOverrides: { git: fakeGit },
@@ -558,7 +558,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
);
assert.strictEqual(gitCalls.length, 0, 'execGit must NOT run — rejection fires before the clone');
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'repo');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'repo');
assert.ok(!fs.existsSync(finalDir), 'no final dir after git integrity rejection');
});
@@ -567,7 +567,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, {
gsdHome,
msdHome,
hostVersion: '1.5.0',
integrity: 'sha512-' + Buffer.from('anything').toString('base64'),
}),
@@ -577,7 +577,7 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
cleanup(capDir);
}
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'local-int-cap');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'local-int-cap');
assert.ok(!fs.existsSync(finalDir), 'no final dir after local integrity rejection');
});
});
@@ -587,10 +587,10 @@ describe('#1460 CS-1 — supplied --integrity is verified or rejected per source
// ---------------------------------------------------------------------------
describe('security: shell metacharacters do not escape into a shell string', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('git spec with shell metacharacters — captured as argv array, not shell string', async () => {
const capturedCalls = [];
@@ -608,7 +608,7 @@ describe('security: shell metacharacters do not escape into a shell string', ()
await assert.rejects(
() =>
resolveCapabilitySource(`git+${maliciousUrl}`, {
gsdHome,
msdHome,
hostVersion: '1.5.0',
execOverrides: { git: fakeGit },
}),
@@ -639,7 +639,7 @@ describe('security: shell metacharacters do not escape into a shell string', ()
};
for (const evil of ['`rm -rf /`', 'pkg; rm -rf', 'pkg && calc', 'pkg|cat /etc/passwd', 'pkg$(whoami)', 'pkg >out', "pkg'", 'pkg"x']) {
await assert.rejects(
() => resolveCapabilitySource(`npm:${evil}`, { gsdHome, hostVersion: '1.5.0', execOverrides: { npm: fakeNpm } }),
() => resolveCapabilitySource(`npm:${evil}`, { msdHome, hostVersion: '1.5.0', execOverrides: { npm: fakeNpm } }),
/unsafe npm package spec/i,
`npm:${evil} must be rejected at parse`
);
@@ -654,7 +654,7 @@ describe('security: shell metacharacters do not escape into a shell string', ()
return { exitCode: 1, stdout: '', stderr: 'not found', signal: null, error: null };
};
await assert.rejects(
() => resolveCapabilitySource('npm:@org/cap@^1.2.0', { gsdHome, hostVersion: '1.5.0', execOverrides: { npm: fakeNpm } }),
() => resolveCapabilitySource('npm:@org/cap@^1.2.0', { msdHome, hostVersion: '1.5.0', execOverrides: { npm: fakeNpm } }),
/npm pack failed|not found/i
);
const packCall = capturedCalls[0];
@@ -666,7 +666,7 @@ describe('security: shell metacharacters do not escape into a shell string', ()
test('git transport allowlist: ext::/file:// transports are rejected at parse', async () => {
for (const evil of ['git+ext::sh -c "evil"', 'git+file:///etc', 'git+fd::7']) {
await assert.rejects(
() => resolveCapabilitySource(evil, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(evil, { msdHome, hostVersion: '1.5.0' }),
/unsupported git transport/i,
`${evil} must be rejected`
);
@@ -679,16 +679,16 @@ describe('security: shell metacharacters do not escape into a shell string', ()
// ---------------------------------------------------------------------------
describe('security: symlink and tar-slip rejection', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('local bundle containing a symlink is refused (copyFileSync would follow it)', async (t) => {
const dir = createTempDir('gsd-local-symlink-');
const dir = createTempDir('msd-local-symlink-');
t.after(() => cleanup(dir));
fs.writeFileSync(path.join(dir, 'capability.json'), JSON.stringify(featureCap('symlink-cap')), 'utf8');
// Plant a symlink pointing at a host file.
const secret = createTempDir('gsd-secret-');
const secret = createTempDir('msd-secret-');
t.after(() => cleanup(secret));
fs.writeFileSync(path.join(secret, 'id_rsa'), 'PRIVATE', 'utf8');
try {
@@ -698,10 +698,10 @@ describe('security: symlink and tar-slip rejection', () => {
return;
}
await assert.rejects(
() => resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' }),
/symlink/i
);
assert.ok(!fs.existsSync(path.join(gsdHome, '.gsd', 'capabilities', 'symlink-cap')), 'no staged dir after symlink refusal');
assert.ok(!fs.existsSync(path.join(msdHome, '.msd', 'capabilities', 'symlink-cap')), 'no staged dir after symlink refusal');
});
test('tarball with a tar-slip member (..) is refused before extraction', async () => {
@@ -711,7 +711,7 @@ describe('security: symlink and tar-slip rejection', () => {
let extracted = false;
await assert.rejects(
() => resolveCapabilitySource('https://example.com/slip.tgz', {
gsdHome, hostVersion: '1.5.0',
msdHome, hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
if (args[0] === '-tzf') {
@@ -735,7 +735,7 @@ describe('security: symlink and tar-slip rejection', () => {
let extracted = false;
await assert.rejects(
() => resolveCapabilitySource('https://example.com/sym.tgz', {
gsdHome, hostVersion: '1.5.0',
msdHome, hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
if (args[0] === '-tzf') {
@@ -762,10 +762,10 @@ describe('security: symlink and tar-slip rejection', () => {
// ---------------------------------------------------------------------------
describe('security: path traversal in capability id', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('capability id containing ../ is rejected before staging', async () => {
// Build a local dir with a capability.json whose id contains path traversal.
@@ -774,15 +774,15 @@ describe('security: path traversal in capability id', () => {
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
/invalid|path separator|kebab-case|\.\./i
);
} finally {
cleanup(capDir);
}
// Nothing must have been written under gsdHome.
const capRoot = path.join(gsdHome, '.gsd', 'capabilities');
// Nothing must have been written under msdHome.
const capRoot = path.join(msdHome, '.msd', 'capabilities');
if (fs.existsSync(capRoot)) {
const entries = fs.readdirSync(capRoot).filter((e) => e !== '.staging');
assert.strictEqual(entries.length, 0, 'no capability must be staged with traversal id');
@@ -795,7 +795,7 @@ describe('security: path traversal in capability id', () => {
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
/invalid|path separator|kebab-case/i
);
} finally {
@@ -809,10 +809,10 @@ describe('security: path traversal in capability id', () => {
// ---------------------------------------------------------------------------
describe('staging atomicity', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-home-'); });
afterEach(() => { cleanup(gsdHome); });
beforeEach(() => { msdHome = createTempDir('msd-home-'); });
afterEach(() => { cleanup(msdHome); });
test('validation failure leaves no directory under capabilities/ (only .staging may exist briefly)', async () => {
// Deliberately invalid cap: missing required fields beyond id/version.
@@ -821,7 +821,7 @@ describe('staging atomicity', () => {
try {
await assert.rejects(
() => resolveCapabilitySource(capDir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(capDir, { msdHome, hostVersion: '1.5.0' }),
(err) => err instanceof Error
);
} finally {
@@ -829,11 +829,11 @@ describe('staging atomicity', () => {
}
// The final capability directory must NOT exist.
const finalDir = path.join(gsdHome, '.gsd', 'capabilities', 'atomicity-test');
const finalDir = path.join(msdHome, '.msd', 'capabilities', 'atomicity-test');
assert.ok(!fs.existsSync(finalDir), 'Final capability dir must be absent after validation failure');
// .staging dir should be cleaned up too (best-effort assertion — it's async).
const stagingRoot = path.join(gsdHome, '.gsd', 'capabilities', '.staging');
const stagingRoot = path.join(msdHome, '.msd', 'capabilities', '.staging');
if (fs.existsSync(stagingRoot)) {
const stagingEntries = fs.readdirSync(stagingRoot);
assert.strictEqual(stagingEntries.length, 0, '.staging must be empty after cleanup');
@@ -900,12 +900,12 @@ function makeFakeHttpsGet(chunks, headers = {}, statusCode = 200) {
}
describe('#1461 DOS-1 — realHttpsGet bounds the response size (MAX_RESPONSE_BYTES)', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-dos-home-'); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-dos-home-'); });
afterEach(() => {
_setHttpsGetImpl(null); // restore the real https.get
_setCapabilitySourceHttpGet(null);
cleanup(gsdHome);
cleanup(msdHome);
});
test('MAX_RESPONSE_BYTES is a sane bounded cap (64 MiB)', () => {
@@ -926,7 +926,7 @@ describe('#1461 DOS-1 — realHttpsGet bounds the response size (MAX_RESPONSE_BY
// and the promise RESOLVES with an oversized body (then proceeds to integrity/extraction) —
// assert.rejects below fails because nothing rejected.
await assert.rejects(
() => resolveCapabilitySource('https://example.com/huge.tgz', { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource('https://example.com/huge.tgz', { msdHome, hostVersion: '1.5.0' }),
/exceeds .*bytes/i,
'an oversized streamed body must reject with the size error'
);
@@ -945,7 +945,7 @@ describe('#1461 DOS-1 — realHttpsGet bounds the response size (MAX_RESPONSE_BY
// REVERT-FAILS: without the content-length pre-check in realHttpsGet, the (empty) stream simply
// ends and the promise RESOLVES — assert.rejects fails because nothing rejected.
await assert.rejects(
() => resolveCapabilitySource('https://example.com/lying.tgz', { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource('https://example.com/lying.tgz', { msdHome, hostVersion: '1.5.0' }),
/exceeds .*bytes|content-length/i,
'an over-cap content-length must reject before buffering'
);
@@ -963,7 +963,7 @@ describe('#1461 DOS-1 — realHttpsGet bounds the response size (MAX_RESPONSE_BY
_setHttpsGetImpl(fake);
const result = await resolveCapabilitySource('https://example.com/dos-control-cap.tgz', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
@@ -994,9 +994,9 @@ describe('#1461 DOS-1 — realHttpsGet bounds the response size (MAX_RESPONSE_BY
// A null/oversized/non-regular read → reject the source with a clear error.
// ---------------------------------------------------------------------------
describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (no OOM/hang)', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-cap-manifest-bound-'); });
afterEach(() => { cleanup(gsdHome); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-cap-manifest-bound-'); });
afterEach(() => { cleanup(msdHome); });
test('MANIFEST_MAX_BYTES is a sane bounded cap (8 MiB)', () => {
assert.strictEqual(MANIFEST_MAX_BYTES, 8 * 1024 * 1024, 'manifest cap is generous but bounded');
@@ -1005,7 +1005,7 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
test('local: an OVERSIZED capability.json fails closed with a clear error (no OOM)', async () => {
// Build a local bundle whose capability.json EXCEEDS the cap. The bounded reader's fstat-size
// check refuses it WITHOUT reading the whole file into memory.
const dir = createTempDir('gsd-cap-oversized-local-');
const dir = createTempDir('msd-cap-oversized-local-');
try {
// One byte over the cap is enough for the size check to refuse.
const oversized = Buffer.alloc(MANIFEST_MAX_BYTES + 1, 0x20); // spaces (still "JSON-ish" length-wise)
@@ -1015,22 +1015,22 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
// into memory and JSON.parse fails with a SYNTAX error (not the bounded-reader size error). The
// bounded reader rejects on the fstat size BEFORE reading — so the error message names the size.
await assert.rejects(
() => resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' }),
/exceeds|size|maximum|not a regular file|cannot read/i,
'an oversized local capability.json must be refused by the bounded reader',
);
} finally {
cleanup(dir);
}
assert.ok(!fs.existsSync(path.join(gsdHome, '.gsd', 'capabilities')) ||
fs.readdirSync(path.join(gsdHome, '.gsd', 'capabilities')).filter((e) => e !== '.staging').length === 0,
assert.ok(!fs.existsSync(path.join(msdHome, '.msd', 'capabilities')) ||
fs.readdirSync(path.join(msdHome, '.msd', 'capabilities')).filter((e) => e !== '.staging').length === 0,
'no capability is staged after an oversized manifest is refused');
});
test('CONTROL: a small valid local capability.json still resolves through the bounded reader', async () => {
const dir = makeLocalCap(featureCap('bounded-control-cap'));
try {
const result = await resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' });
const result = await resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' });
assert.strictEqual(result.id, 'bounded-control-cap', 'a small valid manifest still resolves');
assert.ok(fs.existsSync(path.join(result.stagedDir, 'capability.json')), 'staged manifest present');
} finally {
@@ -1044,7 +1044,7 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
// so this proves the LOCAL PRE-READ bound, NOT the stageValidated staged re-read (an earlier
// version of this test falsely claimed to exercise the staged re-read). The staged re-read is
// covered directly below via _readManifestBounded.
const dir = createTempDir('gsd-cap-oversized-stage-');
const dir = createTempDir('msd-cap-oversized-stage-');
try {
const cap = featureCap('oversized-stage-cap');
// A valid manifest padded past the cap via a large filler field — still parseable JSON shape but
@@ -1052,7 +1052,7 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
const padded = JSON.stringify({ ...cap, _filler: 'x'.repeat(MANIFEST_MAX_BYTES) });
fs.writeFileSync(path.join(dir, 'capability.json'), padded);
await assert.rejects(
() => resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' }),
/exceeds|size|maximum|cannot read/i,
'an oversized local capability.json must be refused by the bounded pre-read',
);
@@ -1068,7 +1068,7 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
//
// REVERT-FAILS: with a raw fs.readFileSync in the staged re-read, this would read the whole
// oversized file and either OOM or surface a JSON SyntaxError, not the bounded size refusal.
const dir = createTempDir('gsd-cap-stagedread-direct-');
const dir = createTempDir('msd-cap-stagedread-direct-');
try {
const padded = Buffer.alloc(MANIFEST_MAX_BYTES + 1, 0x20); // spaces — over the cap by one byte.
fs.writeFileSync(path.join(dir, 'capability.json'), padded);
@@ -1093,11 +1093,11 @@ describe('#1461 finding 2 — untrusted capability.json reads are size-bounded (
// chokepoint that covers EVERY adapter (tar / npm / git / local).
// ---------------------------------------------------------------------------
describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (uniform DoS bound)', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-cap-stagebudget-'); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-cap-stagebudget-'); });
afterEach(() => {
_setCapabilitySourceHttpGet(null);
cleanup(gsdHome);
cleanup(msdHome);
});
test('MAX_STAGED_BUNDLE_BYTES is a sane bounded cap (128 MiB)', () => {
@@ -1112,7 +1112,7 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
// REVERT-FAILS: without the staged-dir aggregate budget, copyDirRecursive copies the oversized
// artifact into staging and the source resolves+promotes normally — the oversized bundle lands on
// disk. With the budget, the bounded walk throws and the source never resolves.
const dir = createTempDir('gsd-cap-stagebudget-local-');
const dir = createTempDir('msd-cap-stagebudget-local-');
try {
fs.writeFileSync(path.join(dir, 'capability.json'), JSON.stringify(featureCap('stagebudget-cap')), 'utf8');
// One byte over the budget across a single artifact is enough for the cumulative counter to trip.
@@ -1123,14 +1123,14 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
try { fs.ftruncateSync(fd, MAX_STAGED_BUNDLE_BYTES + 1); } finally { fs.closeSync(fd); }
await assert.rejects(
() => resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' }),
/staged bundle|exceeds|budget|maximum|too large/i,
'an over-budget staged bundle must be refused before promotion',
);
} finally {
cleanup(dir);
}
const capRoot = path.join(gsdHome, '.gsd', 'capabilities');
const capRoot = path.join(msdHome, '.msd', 'capabilities');
assert.ok(!fs.existsSync(capRoot) ||
fs.readdirSync(capRoot).filter((e) => e !== '.staging').length === 0,
'no capability is promoted after an over-budget bundle is refused');
@@ -1150,7 +1150,7 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
_setCapabilitySourceHttpGet(() => Promise.resolve({ statusCode: 200, body: tgzBuf }));
await assert.rejects(
() => resolveCapabilitySource('https://example.com/big.tgz', {
gsdHome, hostVersion: '1.5.0',
msdHome, hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
if (args[0] === '-tzf') {
@@ -1177,7 +1177,7 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
/staged bundle|exceeds|budget|maximum|too large/i,
'an over-budget extracted tarball must be refused at the staging chokepoint',
);
const capRoot = path.join(gsdHome, '.gsd', 'capabilities');
const capRoot = path.join(msdHome, '.msd', 'capabilities');
assert.ok(!fs.existsSync(capRoot) ||
fs.readdirSync(capRoot).filter((e) => e !== '.staging').length === 0,
'no capability is promoted after an over-budget tarball is refused');
@@ -1186,7 +1186,7 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
test('CONTROL: a within-budget bundle still resolves + promotes normally', async () => {
const dir = makeLocalCap(featureCap('stagebudget-control-cap'));
try {
const result = await resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' });
const result = await resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' });
assert.strictEqual(result.id, 'stagebudget-control-cap', 'a within-budget bundle resolves');
assert.ok(fs.existsSync(path.join(result.stagedDir, 'capability.json')), 'staged manifest present');
} finally {
@@ -1211,11 +1211,11 @@ describe('#1461 finding 1 — the staged bundle dir is aggregate-byte-bounded (u
// DURING the copy, before reading/copying the rest.
// ---------------------------------------------------------------------------
describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the copy (no full materialization)', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-cap-copybudget-'); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-cap-copybudget-'); });
afterEach(() => {
_setCapabilitySourceHttpGet(null);
cleanup(gsdHome);
cleanup(msdHome);
});
test('MAX_STAGED_BUNDLE_ENTRIES is exported as a sane bounded cap (100k)', () => {
@@ -1237,7 +1237,7 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
// REVERT-FAILS: reverting copyDirRecursive to `fs.readdirSync(src, { withFileTypes:true })` makes the
// copy call readdirSync on the source (assertion (2) fails) AND would materialize the entire (here
// synthetic, effectively unbounded) dirent array before any cap could trip.
const src = createTempDir('gsd-cap-copybudget-src-');
const src = createTempDir('msd-cap-copybudget-src-');
try {
fs.writeFileSync(path.join(src, 'capability.json'), JSON.stringify(featureCap('copybudget-cap')), 'utf8');
@@ -1294,7 +1294,7 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
try {
await assert.rejects(
() => resolveCapabilitySource(src, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(src, { msdHome, hostVersion: '1.5.0' }),
/entry count exceeds|maximum of 100000|too many entries/i,
'a source with more than the entry cap must be refused during the streaming copy',
);
@@ -1319,7 +1319,7 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
cleanup(src);
}
// Atomicity: nothing promoted; .staging cleaned up.
const capRoot = path.join(gsdHome, '.gsd', 'capabilities');
const capRoot = path.join(msdHome, '.msd', 'capabilities');
assert.ok(!fs.existsSync(capRoot) ||
fs.readdirSync(capRoot).filter((e) => e !== '.staging').length === 0,
'no capability is promoted after an over-entry-budget bundle is refused');
@@ -1336,7 +1336,7 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
// REVERT-FAILS: the old copyDirRecursive copied everything unconditionally and relied solely on the
// post-copy walk; if that post-copy walk were ALSO removed (and copy not budgeted), the oversized
// artifact would land in staging. With the in-copy byte budget the copy itself fails closed.
const src = createTempDir('gsd-cap-copybudget-bytes-');
const src = createTempDir('msd-cap-copybudget-bytes-');
try {
fs.writeFileSync(path.join(src, 'capability.json'), JSON.stringify(featureCap('copybudget-bytes-cap')), 'utf8');
const big = path.join(src, 'artifact.bin');
@@ -1344,27 +1344,27 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
try { fs.ftruncateSync(fd, MAX_STAGED_BUNDLE_BYTES + 1); } finally { fs.closeSync(fd); }
await assert.rejects(
() => resolveCapabilitySource(src, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(src, { msdHome, hostVersion: '1.5.0' }),
/exceeds|budget|maximum|too large|staged bundle/i,
'an over-byte-budget source must be refused during the streaming copy',
);
} finally {
cleanup(src);
}
const capRoot = path.join(gsdHome, '.gsd', 'capabilities');
const capRoot = path.join(msdHome, '.msd', 'capabilities');
assert.ok(!fs.existsSync(capRoot) ||
fs.readdirSync(capRoot).filter((e) => e !== '.staging').length === 0,
'no capability is promoted after an over-byte-budget bundle is refused');
});
test('CONTROL: a normal small source still stages through the streaming copy', async () => {
const dir = createTempDir('gsd-cap-copybudget-control-');
const dir = createTempDir('msd-cap-copybudget-control-');
try {
fs.writeFileSync(path.join(dir, 'capability.json'), JSON.stringify(featureCap('copybudget-control-cap')), 'utf8');
fs.mkdirSync(path.join(dir, 'nested'), { recursive: true });
fs.writeFileSync(path.join(dir, 'nested', 'extra.txt'), 'hello', 'utf8');
const result = await resolveCapabilitySource(dir, { gsdHome, hostVersion: '1.5.0' });
const result = await resolveCapabilitySource(dir, { msdHome, hostVersion: '1.5.0' });
assert.strictEqual(result.id, 'copybudget-control-cap', 'a within-budget bundle resolves');
assert.ok(fs.existsSync(path.join(result.stagedDir, 'capability.json')), 'staged manifest present');
assert.ok(fs.existsSync(path.join(result.stagedDir, 'nested', 'extra.txt')), 'nested file copied through the streaming copy');
@@ -1383,11 +1383,11 @@ describe('#1461 finding 1 (ROUND 2) — copyDirRecursive streams + budgets the c
// within-name/type tarball still resolves through extraction.
// ---------------------------------------------------------------------------
describe('#1461 finding 2 — tar header-size parse removed; NAME/TYPE guards remain', () => {
let gsdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-cap-tarsize-removed-'); });
let msdHome = '';
beforeEach(() => { msdHome = createTempDir('msd-cap-tarsize-removed-'); });
afterEach(() => {
_setCapabilitySourceHttpGet(null);
cleanup(gsdHome);
cleanup(msdHome);
});
test('the spoofable per-member size cap export (MAX_TAR_MEMBER_BYTES) is REMOVED', () => {
@@ -1404,7 +1404,7 @@ describe('#1461 finding 2 — tar header-size parse removed; NAME/TYPE guards re
const tgzBuf = _fakeTarball(cap);
_setCapabilitySourceHttpGet(() => Promise.resolve({ statusCode: 200, body: tgzBuf }));
const result = await resolveCapabilitySource('https://example.com/huge-decl.tgz', {
gsdHome, hostVersion: '1.5.0',
msdHome, hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
if (args[0] === '-tzf') {
@@ -1633,25 +1633,25 @@ describe('#1463 peekLatestVersion (D6 per-source matrix)', () => {
test('npm: RANGE spec — npm view prints EVERY matching version (real multi-line output) → highest matching is chosen', () => {
// npm's REAL behaviour for `npm view <pkg>@<range> version`: when the range matches multiple
// versions it prints one annotated line PER matching version, e.g.
// @org/gsd-cap-foo@1.0.0 '1.0.0'
// @org/gsd-cap-foo@1.3.0 '1.3.0'
// @org/gsd-cap-foo@1.10.0 '1.10.0'
// @org/msd-cap-foo@1.0.0 '1.0.0'
// @org/msd-cap-foo@1.3.0 '1.3.0'
// @org/msd-cap-foo@1.10.0 '1.10.0'
// (NOT a single bare token). The peek must parse ALL tokens and pick the HIGHEST numerically.
// revert-fails: the old single-token NPM_VERSION_RE.test(stdout.trim()) parse sees multi-line
// output as non-semver and DEGRADES to status 'unknown' — this assert then fails.
const multiLine = [
"@org/gsd-cap-foo@1.0.0 '1.0.0'",
"@org/gsd-cap-foo@1.3.0 '1.3.0'",
"@org/gsd-cap-foo@1.10.0 '1.10.0'",
"@org/msd-cap-foo@1.0.0 '1.0.0'",
"@org/msd-cap-foo@1.3.0 '1.3.0'",
"@org/msd-cap-foo@1.10.0 '1.10.0'",
].join('\n') + '\n';
const fakeNpm = (args, o) => {
assert.ok(args.includes('view'), 'must use npm view');
assert.ok(typeof o.timeout === 'number' && o.timeout <= 60_000, 'npm peek must be bounded ≤60s');
// Invocation shape is unchanged: ['view','--',<target>,'version'] with the range still on target.
assert.deepStrictEqual(args, ['view', '--', '@org/gsd-cap-foo@^1', 'version']);
assert.deepStrictEqual(args, ['view', '--', '@org/msd-cap-foo@^1', 'version']);
return spawnOk(multiLine);
};
const r = peekLatestVersion('npm:@org/gsd-cap-foo@^1', { execOverrides: { npm: fakeNpm } });
const r = peekLatestVersion('npm:@org/msd-cap-foo@^1', { execOverrides: { npm: fakeNpm } });
// 1.10.0 must beat 1.3.0 numerically (not lexically), and it satisfies ^1.
assert.deepStrictEqual(r, { status: 'ok', version: '1.10.0' });
});
@@ -1681,10 +1681,10 @@ describe('#1463 peekLatestVersion (D6 per-source matrix)', () => {
test('npm: NO-version spec (tracks latest) — single bare latest line → status ok', () => {
const fakeNpm = (args) => {
// No version on the spec ⇒ target is just the bare name; npm view prints a single latest token.
assert.deepStrictEqual(args, ['view', '--', '@org/gsd-cap-foo', 'version']);
assert.deepStrictEqual(args, ['view', '--', '@org/msd-cap-foo', 'version']);
return spawnOk('2.4.1\n');
};
const r = peekLatestVersion('npm:@org/gsd-cap-foo', { execOverrides: { npm: fakeNpm } });
const r = peekLatestVersion('npm:@org/msd-cap-foo', { execOverrides: { npm: fakeNpm } });
assert.deepStrictEqual(r, { status: 'ok', version: '2.4.1' });
});
@@ -1693,7 +1693,7 @@ describe('#1463 peekLatestVersion (D6 per-source matrix)', () => {
// compare, so a pinned source could be reported outdated; this assert requires status 'pinned'.
let called = false;
const fakeNpm = () => { called = true; return spawnOk('9.9.9\n'); };
const r = peekLatestVersion('npm:@org/gsd-cap-foo@1.2.3', { execOverrides: { npm: fakeNpm } });
const r = peekLatestVersion('npm:@org/msd-cap-foo@1.2.3', { execOverrides: { npm: fakeNpm } });
assert.strictEqual(r.status, 'pinned');
assert.strictEqual(r.version, '1.2.3', 'pinned reports the pinned exact version');
assert.strictEqual(called, false, 'an exact-pinned npm source needs no remote peek (update will not move it)');
@@ -1733,7 +1733,7 @@ describe('#1463 peekLatestVersion (D6 per-source matrix)', () => {
});
test('registry: unimplemented → status unsupported', () => {
const r = peekLatestVersion('my-cap@gsd-registry');
const r = peekLatestVersion('my-cap@msd-registry');
assert.strictEqual(r.status, 'unsupported');
assert.strictEqual(r.version, null);
});
@@ -1835,12 +1835,12 @@ describe('#1463 pickHighestNpmVersion (robust multi-line range parse)', () => {
// ---------------------------------------------------------------------------
describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-3514-home-'); });
beforeEach(() => { msdHome = createTempDir('msd-3514-home-'); });
afterEach(() => {
_setHttpsGetImpl(null); // restore the real https.get
cleanup(gsdHome);
cleanup(msdHome);
});
/** Wrap makeFakeHttpsGet with a call counter so a test can prove the gate
@@ -1879,7 +1879,7 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
const fake = makeCountingFake([Buffer.from('x')]);
_setHttpsGetImpl(fake);
await assert.rejects(
() => resolveCapabilitySource(url, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(url, { msdHome, hostVersion: '1.5.0' }),
/internal host|loopback|link-local|metadata|denylist/i,
`${label} must be refused with the named denylist reason`
);
@@ -1905,7 +1905,7 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
const fake = makeCountingFake([Buffer.from('x')]);
_setHttpsGetImpl(fake);
await assert.rejects(
() => resolveCapabilitySource(url, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(url, { msdHome, hostVersion: '1.5.0' }),
/internal host|loopback|denylist/i,
`${label} must be refused — it is the loopback literal in another spelling`
);
@@ -1919,7 +1919,7 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
const fake = makeCountingFake([tgzBuf], { 'content-length': String(tgzBuf.length) });
_setHttpsGetImpl(fake);
const result = await resolveCapabilitySource('https://example.com/gate-control-cap.tgz', {
gsdHome,
msdHome,
hostVersion: '1.5.0',
execOverrides: {
tar: (_prog, args) => {
@@ -1943,7 +1943,7 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
const fake = makeCountingFake([Buffer.from('x')]);
_setHttpsGetImpl(fake);
await assert.rejects(
() => resolveCapabilitySource(`https://${host}/cap.tgz`, { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource(`https://${host}/cap.tgz`, { msdHome, hostVersion: '1.5.0' }),
(err) => !/internal host|denylist|loopback/i.test(String(err && err.message)),
`${host} is a domain, not an IPv6 literal — it must reach the transport`
);
@@ -1958,7 +1958,7 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
// downstream as a non-tarball — irrelevant here; the assertion is that the
// gate itself does not reject a private-range host).
await assert.rejects(
() => resolveCapabilitySource('https://192.168.1.10/cap.tgz', { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource('https://192.168.1.10/cap.tgz', { msdHome, hostVersion: '1.5.0' }),
(err) => !/internal host|denylist|loopback/i.test(String(err && err.message))
);
assert.strictEqual(fake.calls, 1, 'a private-range host must reach the transport');
@@ -1966,12 +1966,12 @@ describe('#3514 F21a — loopback/metadata denylist in realHttpsGet', () => {
});
describe('#3514 F21b — non-https tarball spec fails with a named reason', () => {
let gsdHome = '';
let msdHome = '';
beforeEach(() => { gsdHome = createTempDir('gsd-3514-http-home-'); });
beforeEach(() => { msdHome = createTempDir('msd-3514-http-home-'); });
afterEach(() => {
_setHttpsGetImpl(null);
cleanup(gsdHome);
cleanup(msdHome);
});
test('parseSpec STILL classifies an http:// tarball URL as tarball (no parse-time hard reject)', () => {
@@ -1984,7 +1984,7 @@ describe('#3514 F21b — non-https tarball spec fails with a named reason', () =
const fake = (url, opts, cb) => { calls += 1; return makeFakeHttpsGet([])(url, opts, cb); };
_setHttpsGetImpl(fake);
await assert.rejects(
() => resolveCapabilitySource('http://mirror.internal/cap.tgz', { gsdHome, hostVersion: '1.5.0' }),
() => resolveCapabilitySource('http://mirror.internal/cap.tgz', { msdHome, hostVersion: '1.5.0' }),
/requires https|plaintext|internal mirror/i,
'the failure must name the https-only transport and the mirror alternative'
);