diff --git a/src/ml/imf/registry.ts b/src/ml/imf/registry.ts index e98b960..4284704 100644 --- a/src/ml/imf/registry.ts +++ b/src/ml/imf/registry.ts @@ -9,14 +9,14 @@ * * Node persists to ~/.cache/interscript/models// (fs, atomic * rename); browsers keep the verified bytes in memory (the Cache API - * integration is future work). Overrides: SECRYST_INDEX, - * SECRYST_CACHE. + * integration is future work). Overrides: INTERSCRIPT_ML_INDEX / INTERSCRIPT_ML_CACHE + * (SECRYST_INDEX / SECRYST_CACHE are deprecated legacy aliases). */ import { load as loadYaml } from "js-yaml" export const DEFAULT_INDEX_URL = - "https://github.com/interscript/interscript-ml/releases/download/index-v6/models-index.yaml" + "https://github.com/interscript/interscript-ml/releases/download/index-v7/models-index.yaml" export interface Part { url: string @@ -52,7 +52,7 @@ function cacheDir(): string { const env = (globalThis as { process?: { env?: Record } }).process ?.env const home = env?.["HOME"] ?? env?.["USERPROFILE"] ?? "." - return env?.["SECRYST_CACHE"] ?? `${home}/.cache/interscript` + return env?.["INTERSCRIPT_ML_CACHE"] ?? env?.["SECRYST_CACHE"] ?? `${home}/.cache/interscript` } async function fetchHttpBytes(url: string): Promise { @@ -297,7 +297,7 @@ export async function resolve( ): Promise { const env = (globalThis as { process?: { env?: Record } }).process ?.env - const source = indexUrl ?? env?.["SECRYST_INDEX"] ?? DEFAULT_INDEX_URL + const source = indexUrl ?? env?.["INTERSCRIPT_ML_INDEX"] ?? env?.["SECRYST_INDEX"] ?? DEFAULT_INDEX_URL let entries: Record try { entries = await fetchIndex(source) diff --git a/test/imf.test.ts b/test/imf.test.ts index bb69f01..6f5642c 100644 --- a/test/imf.test.ts +++ b/test/imf.test.ts @@ -259,11 +259,33 @@ describe("registry", () => { it("DEFAULT_INDEX_URL pins a GitHub Release asset, never raw", async () => { const { DEFAULT_INDEX_URL } = await import("../src/ml/imf/registry.js") expect(DEFAULT_INDEX_URL).toMatch( - /^https:\/\/github\.com\/interscript\/interscript-ml\/releases\/download\/index-v6\/models-index\.yaml$/, + /^https:\/\/github\.com\/interscript\/interscript-ml\/releases\/download\/index-v7\/models-index\.yaml$/, ) expect(DEFAULT_INDEX_URL).not.toMatch(/raw\.githubusercontent/) }) + it("INTERSCRIPT_ML_INDEX is the primary override, SECRYST_INDEX a legacy alias", async () => { + const { mkdtempSync, writeFileSync, rmSync } = await import("node:fs") + const { tmpdir } = await import("node:os") + const { join } = await import("node:path") + const { resolve } = await import("../src/ml/imf/registry.js") + const dir = mkdtempSync(join(tmpdir(), "imf-envvar-")) + writeFileSync(join(dir, "models.yaml"), "version: 1\nmodels:\n tiny-1.0:\n filename: t.zip\n sha256: x\n") + const prev = process.env["SECRYST_INDEX"] + try { + process.env["INTERSCRIPT_ML_INDEX"] = join(dir, "models.yaml") + await expect(resolve("nope-9.9")).rejects.toThrow(/unknown model id/) + delete process.env["INTERSCRIPT_ML_INDEX"] + process.env["SECRYST_INDEX"] = join(dir, "models.yaml") + await expect(resolve("nope-9.9")).rejects.toThrow(/unknown model id/) + } finally { + delete process.env["INTERSCRIPT_ML_INDEX"] + if (prev === undefined) delete process.env["SECRYST_INDEX"] + else process.env["SECRYST_INDEX"] = prev + rmSync(dir, { recursive: true, force: true }) + } + }) + it("HTTP index fetch verifies the .sha256 sidecar before parsing", async () => { const { createHash } = await import("node:crypto") const { createServer } = await import("node:http") @@ -367,7 +389,7 @@ describe("registry", () => { expect(typeof imf!["resolve"]).toBe("function") expect(typeof imf!["IMFModel"]).toBe("function") expect(imf!["DEFAULT_INDEX_URL"]).toMatch( - /github\.com\/interscript\/interscript-ml\/releases\/download\/index-v6\/models-index\.yaml/, + /github\.com\/interscript\/interscript-ml\/releases\/download\/index-v7\/models-index\.yaml/, ) }) })