mirror of
https://github.com/hanzoai/extension.git
synced 2026-10-31 21:57:06 +00:00
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]>
87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
HANZO_API_BASE_URL,
|
|
DEFAULT_MODEL,
|
|
pickBearer,
|
|
SMART_SCOPES,
|
|
scopeString,
|
|
smartConfigUrl,
|
|
normalizeBase,
|
|
FHIR_RESOURCES,
|
|
} from '../src/config.js';
|
|
|
|
describe('config: Hanzo gateway', () => {
|
|
it('points at api.hanzo.ai with no /api/ prefix', () => {
|
|
expect(HANZO_API_BASE_URL).toBe('https://api.hanzo.ai');
|
|
expect(HANZO_API_BASE_URL).not.toContain('/api/');
|
|
});
|
|
|
|
it('default model is a zen model', () => {
|
|
expect(DEFAULT_MODEL).toMatch(/^zen/);
|
|
});
|
|
});
|
|
|
|
describe('config: pickBearer', () => {
|
|
it('prefers the pasted key over the IAM token', () => {
|
|
expect(pickBearer('sk-key', 'iam-token')).toBe('sk-key');
|
|
});
|
|
it('falls back to the IAM token when no key', () => {
|
|
expect(pickBearer('', 'iam-token')).toBe('iam-token');
|
|
expect(pickBearer(' ', 'iam-token')).toBe('iam-token');
|
|
});
|
|
it('is empty (anonymous) when neither is present', () => {
|
|
expect(pickBearer('', '')).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('config: SMART scopes', () => {
|
|
it('requests launch + patient read scopes and NO write scope', () => {
|
|
const s = scopeString();
|
|
expect(s).toContain('launch');
|
|
expect(s).toContain('openid');
|
|
expect(s).toContain('fhirUser');
|
|
expect(s).toContain('patient/Patient.read');
|
|
expect(s).toContain('patient/Condition.read');
|
|
expect(s).toContain('patient/MedicationRequest.read');
|
|
expect(s).toContain('patient/Observation.read');
|
|
expect(s).toContain('patient/AllergyIntolerance.read');
|
|
expect(s).toContain('patient/DocumentReference.read');
|
|
// Read + assist only — a write scope must never be requested in v1.
|
|
expect(s).not.toMatch(/\.write/);
|
|
expect(s).not.toMatch(/\*\/\*/);
|
|
});
|
|
|
|
it('scopeString is space-delimited and deterministic', () => {
|
|
expect(scopeString(['a', 'b', 'c'])).toBe('a b c');
|
|
expect(scopeString()).toBe(SMART_SCOPES.join(' '));
|
|
});
|
|
});
|
|
|
|
describe('config: discovery URL', () => {
|
|
it('derives the well-known discovery URL from iss', () => {
|
|
expect(smartConfigUrl('https://fhir.example.org/r4')).toBe(
|
|
'https://fhir.example.org/r4/.well-known/smart-configuration',
|
|
);
|
|
});
|
|
it('normalizes a trailing slash on iss', () => {
|
|
expect(smartConfigUrl('https://fhir.example.org/r4/')).toBe(
|
|
'https://fhir.example.org/r4/.well-known/smart-configuration',
|
|
);
|
|
expect(normalizeBase('https://x/')).toBe('https://x');
|
|
expect(normalizeBase('https://x///')).toBe('https://x');
|
|
});
|
|
});
|
|
|
|
describe('config: FHIR resource names', () => {
|
|
it('names the six read resources', () => {
|
|
expect(Object.keys(FHIR_RESOURCES).sort()).toEqual([
|
|
'AllergyIntolerance',
|
|
'Condition',
|
|
'DocumentReference',
|
|
'MedicationRequest',
|
|
'Observation',
|
|
'Patient',
|
|
]);
|
|
});
|
|
});
|