2026-09-19 20:54:16 +03:00
|
|
|
/**
|
2026-09-22 00:02:07 +03:00
|
|
|
* The curated auth-key catalog + shape rules (auth-keys wave, 2026-09-19;
|
|
|
|
|
* search wave 2026-09-20: the Google CSE pair retired, Tavily + Brave in)
|
2026-09-19 20:54:16 +03:00
|
|
|
* — PURE module, so this file owns no fs. Owner decisions being pinned:
|
2026-09-22 00:02:07 +03:00
|
|
|
* - the catalog is exactly the three known keys, ids = env-var names;
|
2026-09-19 20:54:16 +03:00
|
|
|
* - validation is SHAPE-ONLY (no live pings) and bad pastes are 400s;
|
|
|
|
|
* - masking is last-4 + length — plaintext never leaves the store.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import assert from "node:assert/strict";
|
|
|
|
|
import { describe, it } from "node:test";
|
2026-09-19 22:52:40 +03:00
|
|
|
import { AUTH_KEYS, genericProviderKeyGuard, isKnownAuthKey, maskKey, validateKeyShape } from "../src/core/auth-keys.ts";
|
2026-09-19 20:54:16 +03:00
|
|
|
|
|
|
|
|
describe("the catalog", () => {
|
2026-09-19 22:52:40 +03:00
|
|
|
it("is exactly the three CURATED app-service keys (provider keys live in the provider table)", () => {
|
2026-09-19 20:54:16 +03:00
|
|
|
assert.deepEqual(
|
|
|
|
|
AUTH_KEYS.map((k) => k.id),
|
2026-09-22 00:02:07 +03:00
|
|
|
["DEEPGRAM_API_KEY", "TAVILY_API_KEY", "BRAVE_API_KEY"],
|
2026-09-19 20:54:16 +03:00
|
|
|
);
|
|
|
|
|
for (const k of AUTH_KEYS) {
|
|
|
|
|
assert.ok(k.label.length > 0, `${k.id} has a label`);
|
|
|
|
|
assert.ok(k.description.length > 0, `${k.id} has a description`);
|
|
|
|
|
assert.ok(k.docsUrl.startsWith("https://"), `${k.id} has a docs link`);
|
|
|
|
|
}
|
2026-09-19 22:52:40 +03:00
|
|
|
// OPENROUTER_API_KEY graduated to the provider table (owner decision,
|
2026-09-22 00:02:07 +03:00
|
|
|
// provider-keys interlude) — not curated anymore. The Google CSE
|
|
|
|
|
// pair retired with its engine (search wave, 2026-09-20).
|
2026-09-19 22:52:40 +03:00
|
|
|
assert.ok(!isKnownAuthKey("OPENROUTER_API_KEY"));
|
2026-09-22 00:02:07 +03:00
|
|
|
assert.ok(!isKnownAuthKey("GOOGLE_SEARCH_API_KEY"), "the CSE pair is retired");
|
|
|
|
|
assert.ok(!isKnownAuthKey("GOOGLE_CSE_ID"));
|
2026-09-19 20:54:16 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("isKnownAuthKey: catalog yes, everything else no", () => {
|
2026-09-19 22:52:40 +03:00
|
|
|
assert.ok(isKnownAuthKey("DEEPGRAM_API_KEY"));
|
2026-09-22 00:02:07 +03:00
|
|
|
assert.ok(isKnownAuthKey("TAVILY_API_KEY"));
|
|
|
|
|
assert.ok(isKnownAuthKey("BRAVE_API_KEY"));
|
2026-09-19 22:52:40 +03:00
|
|
|
assert.ok(!isKnownAuthKey("OPENROUTER_API_KEY"));
|
|
|
|
|
assert.ok(!isKnownAuthKey("OPENAI_API_KEY"), "provider vars are a separate surface");
|
2026-09-19 20:54:16 +03:00
|
|
|
assert.ok(!isKnownAuthKey("FUTURE_PLANS_TOKEN"));
|
|
|
|
|
assert.ok(!isKnownAuthKey(""));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2026-09-19 22:52:40 +03:00
|
|
|
describe("validateKeyShape (the 400 gate — curated keys)", () => {
|
2026-09-22 00:02:07 +03:00
|
|
|
it("Tavily: tvly- prefix required, length floor past it", () => {
|
|
|
|
|
assert.ok(validateKeyShape("TAVILY_API_KEY", "tvly-abc123def456ghi78").ok);
|
|
|
|
|
assert.ok(!validateKeyShape("TAVILY_API_KEY", "sk-or-v1-abcdefghij").ok, "wrong family");
|
|
|
|
|
assert.ok(!validateKeyShape("TAVILY_API_KEY", "tvly-").ok, "prefix alone is a truncation");
|
|
|
|
|
assert.ok(!validateKeyShape("TAVILY_API_KEY", " ").ok, "empty fails");
|
2026-09-19 20:54:16 +03:00
|
|
|
});
|
|
|
|
|
|
2026-09-22 00:02:07 +03:00
|
|
|
it("Brave: no public format — a ≥20-char truncation guard, no whitespace", () => {
|
|
|
|
|
assert.ok(validateKeyShape("BRAVE_API_KEY", "b".repeat(40)).ok);
|
|
|
|
|
assert.ok(!validateKeyShape("BRAVE_API_KEY", "b".repeat(19)).ok, "truncated paste");
|
|
|
|
|
assert.ok(!validateKeyShape("BRAVE_API_KEY", "has whitespace here").ok);
|
2026-09-19 20:54:16 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("Deepgram: no public format — a ≥20-char truncation guard, no whitespace", () => {
|
|
|
|
|
assert.ok(validateKeyShape("DEEPGRAM_API_KEY", "a".repeat(40)).ok);
|
|
|
|
|
assert.ok(!validateKeyShape("DEEPGRAM_API_KEY", "a".repeat(19)).ok, "truncated paste");
|
|
|
|
|
assert.ok(!validateKeyShape("DEEPGRAM_API_KEY", "a b c d e f g h i j k l m n o p q r s").ok, "whitespace");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("trims surrounding paste whitespace before checking", () => {
|
2026-09-19 22:52:40 +03:00
|
|
|
assert.ok(validateKeyShape("DEEPGRAM_API_KEY", ` ${"d".repeat(40)} `).ok);
|
2026-09-19 20:54:16 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("unknown ids are rejected with the supported list", () => {
|
|
|
|
|
const r = validateKeyShape("SOMETHING_ELSE", "whatever");
|
|
|
|
|
assert.ok(!r.ok);
|
2026-09-19 22:52:40 +03:00
|
|
|
if (!r.ok) assert.match(r.error, /SOMETHING_ELSE.*DEEPGRAM_API_KEY/);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("genericProviderKeyGuard (model-provider keys — paste hygiene only)", () => {
|
|
|
|
|
it("accepts any ≥12-char whitespace-free value (families vary)", () => {
|
|
|
|
|
assert.deepEqual(genericProviderKeyGuard("OPENROUTER_API_KEY", "sk-or-v1-abc123"), { ok: true });
|
|
|
|
|
assert.deepEqual(genericProviderKeyGuard("OPENAI_API_KEY", "whaterver-value-here"), { ok: true });
|
|
|
|
|
assert.deepEqual(genericProviderKeyGuard("HF_TOKEN", "hf_xxxxxxxx9999"), { ok: true });
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("rejects truncations and whitespace — the only guards", () => {
|
|
|
|
|
const short = genericProviderKeyGuard("ZAI_API_KEY", "short");
|
|
|
|
|
assert.ok(!short.ok);
|
|
|
|
|
if (!short.ok) assert.match(short.error, /at least 12/);
|
|
|
|
|
assert.ok(!genericProviderKeyGuard("OPENAI_API_KEY", "has whitespace now").ok);
|
|
|
|
|
assert.ok(!genericProviderKeyGuard("OPENAI_API_KEY", " ").ok);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("trims before checking", () => {
|
|
|
|
|
assert.ok(genericProviderKeyGuard("OPENROUTER_API_KEY", " sk-or-v1-xyz999 ").ok);
|
2026-09-19 20:54:16 +03:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe("maskKey (plaintext never leaves)", () => {
|
|
|
|
|
it("shows the last 4 only", () => {
|
|
|
|
|
assert.equal(maskKey("sk-or-v1-abcdefgh1234"), "…1234");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("never reveals a degenerate short value in full", () => {
|
|
|
|
|
assert.equal(maskKey("ab"), "…ab");
|
|
|
|
|
assert.equal(maskKey("abcd"), "…abcd");
|
|
|
|
|
assert.equal(maskKey("abcde"), "…bcde");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("trims before masking", () => {
|
|
|
|
|
assert.equal(maskKey(" sk-or-v1-xyzw9 "), "…yzw9");
|
|
|
|
|
});
|
|
|
|
|
});
|