diff --git a/modules/lab/test/runs.test.ts b/modules/lab/test/runs.test.ts index 196a9c45..6be1063b 100644 --- a/modules/lab/test/runs.test.ts +++ b/modules/lab/test/runs.test.ts @@ -370,3 +370,14 @@ test("the public root is read from the binding, and only an https root at the np assert.match(publicRootOf(undefined).problem ?? "", /no npm-package-registry binding/); rmSync(dir, { recursive: true, force: true }); }); + +// A forge setting that is not http(s) is never a trusted origin (review of #280): a `file:` tarball's origin +// is "null", as is a `file:` forge's, and the two must not match. +test("a forge setting that is not http(s) trusts no origin of its own", async () => { + const got = await npmRegistry("file:///srv/forge", aRegistry(() => packument("file:///api/packages/novox/npm/x.tgz")).get); + assert.match(got.problem ?? "", /neither the forge's public root nor its own address/); + const root = "https://git.example.org/api/packages/novox/npm/"; + const viaRoot = await npmRegistry("ftp://novox.internal", aRegistry(() => + packument("ftp://novox.internal/api/packages/novox/npm/x.tgz")).get, root); + assert.match(viaRoot.problem ?? "", /neither/); +}); diff --git a/modules/lab/tools/runs.ts b/modules/lab/tools/runs.ts index c048fa60..e3eb1b9d 100644 --- a/modules/lab/tools/runs.ts +++ b/modules/lab/tools/runs.ts @@ -126,7 +126,9 @@ export async function npmRegistry(forge: string, get: typeof fetch = fetch, publ } catch { return fallback(`the forge ${JSON.stringify(forge)} is not a URL`); } - const trusted = [own.origin]; + // The forge setting's own origin is trusted only as an http(s) one: any other scheme's origin is + // "null", or names no registry npm would fetch from. + const trusted = own.protocol === "https:" || own.protocol === "http:" ? [own.origin] : []; if (publicRoot) { try { trusted.unshift(new URL(publicRoot).origin);