Files
zooqueenandHanzo Dev f717dd89ad keys: the key a user pastes is sk-, not the retired hk-
28 apps told the user to paste an `hk-` key — input placeholders, settings
help text, READMEs, the error thrown when the field is empty — and five of
them validated that paste against /^hk-/ before sending it as a bearer.
Nothing mints that prefix any more: cloud accepts pk- and sk-, IAM mints
sk-. So the guard admitted a credential that authenticates nothing, and the
panel failed later at the gateway with nothing on screen to explain it.

The three leak detectors keep hk- and gain sk-. Salesforce's source scan
and the two Zendesk tests exist to catch a key committed to source or
echoed back through a request; retired keys are still in circulation and
leak exactly as badly, while a detector that only knew hk- would have gone
blind to every key minted from here on.

`sk-` used to be the example of the foreign key the guard screened out — an
OpenAI key. It cannot mean that now, and shape alone cannot tell one
vendor's sk- from another's, so those comments say what the check really
proves and point at the /v1/models call that proves the rest. The three
tests that pinned "sk- is rejected" now pin "hk- is rejected", which is the
invariant that survived.

Verified: 2029 tests pass across the 28 packages; typecheck clean on 25 of
them (hubspot, jupyter and teams fail identically at HEAD on JSX and ESM
type conflicts in files this does not touch); salesforce validate-source
green.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-13 18:07:16 -07:00

101 lines
3.6 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
DEFAULT_SETTINGS,
parseSettings,
mergeSettings,
serializeSettings,
type Settings,
} from "../src/store";
const KEY = "sk-" + "a".repeat(20);
const KEY2 = "sk-" + "b".repeat(20);
describe("parseSettings", () => {
it("returns defaults for null / empty", () => {
expect(parseSettings(null)).toEqual(DEFAULT_SETTINGS);
expect(parseSettings("")).toEqual(DEFAULT_SETTINGS);
});
it("returns defaults for invalid JSON", () => {
expect(parseSettings("{not json")).toEqual(DEFAULT_SETTINGS);
});
it("returns defaults for a non-object payload", () => {
expect(parseSettings("42")).toEqual(DEFAULT_SETTINGS);
expect(parseSettings("null")).toEqual(DEFAULT_SETTINGS);
expect(parseSettings('"a string"')).toEqual(DEFAULT_SETTINGS);
});
it("reads a valid stored key + model", () => {
const raw = JSON.stringify({ apiKey: KEY, model: "zen5-coder" });
expect(parseSettings(raw)).toEqual({ apiKey: KEY, model: "zen5-coder" });
});
it("drops a stored key that no longer matches the sk- shape", () => {
const raw = JSON.stringify({ apiKey: "hk-" + "a".repeat(20), model: "zen5" });
expect(parseSettings(raw)).toEqual({ apiKey: "", model: "zen5" });
});
it("trims the stored key and falls back to the default model when missing/blank", () => {
const raw = JSON.stringify({ apiKey: ` ${KEY} `, model: " " });
expect(parseSettings(raw)).toEqual({ apiKey: KEY, model: DEFAULT_SETTINGS.model });
});
it("fills defaults for wrong-typed fields", () => {
const raw = JSON.stringify({ apiKey: 123, model: [] });
expect(parseSettings(raw)).toEqual(DEFAULT_SETTINGS);
});
});
describe("mergeSettings", () => {
const base: Settings = { apiKey: "", model: "zen5" };
it("accepts a valid key patch", () => {
const { settings, error } = mergeSettings(base, { apiKey: KEY });
expect(error).toBeUndefined();
expect(settings.apiKey).toBe(KEY);
});
it("trims the key before validating and storing", () => {
const { settings } = mergeSettings(base, { apiKey: ` ${KEY2} ` });
expect(settings.apiKey).toBe(KEY2);
});
it("clears the key on an empty patch (explicit removal)", () => {
const withKey: Settings = { apiKey: KEY, model: "zen5" };
const { settings, error } = mergeSettings(withKey, { apiKey: " " });
expect(error).toBeUndefined();
expect(settings.apiKey).toBe("");
});
it("rejects a malformed key WITHOUT mutating current settings", () => {
const { settings, error } = mergeSettings(base, { apiKey: "hk-" + "a".repeat(20) });
expect(error).toMatch(/Not a Hanzo key/);
expect(settings).toBe(base); // returns the untouched original
});
it("normalizes a blank model back to the default", () => {
const { settings } = mergeSettings(base, { model: " " });
expect(settings.model).toBe(DEFAULT_SETTINGS.model);
});
it("applies a model patch and leaves the key untouched", () => {
const withKey: Settings = { apiKey: KEY, model: "zen5" };
const { settings } = mergeSettings(withKey, { model: "zen5-mini" });
expect(settings).toEqual({ apiKey: KEY, model: "zen5-mini" });
});
it("applies key + model together", () => {
const { settings, error } = mergeSettings(base, { apiKey: KEY, model: "zen5-coder" });
expect(error).toBeUndefined();
expect(settings).toEqual({ apiKey: KEY, model: "zen5-coder" });
});
});
describe("serializeSettings <-> parseSettings round-trip", () => {
it("round-trips a valid settings object", () => {
const s: Settings = { apiKey: KEY, model: "zen5-coder" };
expect(parseSettings(serializeSettings(s))).toEqual(s);
});
});