diff --git a/.github/actions/kms-secrets/action.yml b/.github/actions/kms-secrets/action.yml index a274a93..8f750ab 100644 --- a/.github/actions/kms-secrets/action.yml +++ b/.github/actions/kms-secrets/action.yml @@ -20,9 +20,9 @@ inputs: trust the GitHub issuer; otherwise pass an IAM machine-identity token. required: true base-url: - description: Gateway base that serves /v1/kms (KMS owns this namespace). + description: KMS host that serves /v1/kms (its own host, not api.). required: false - default: https://api.hanzo.ai + default: https://kms.hanzo.ai export: description: "Where to put secrets: 'env' (job environment) or 'file'." required: false diff --git a/forks/lux/package.json b/forks/lux/package.json index a017f12..362b482 100644 --- a/forks/lux/package.json +++ b/forks/lux/package.json @@ -1,6 +1,6 @@ { "name": "@luxfi/helper", - "version": "1.0.5", + "version": "1.0.6", "description": "Lux CLI helper — sign in to Lux and use its AI models in Claude Code, Codex, and more", "type": "module", "bin": { @@ -28,6 +28,6 @@ }, "homepage": "https://lux.network", "dependencies": { - "@hanzo/helper": "^1.0.5" + "@hanzo/helper": "^1.0.6" } } diff --git a/forks/zen/package.json b/forks/zen/package.json index 28442ad..11f169d 100644 --- a/forks/zen/package.json +++ b/forks/zen/package.json @@ -1,6 +1,6 @@ { "name": "@zenlm/helper", - "version": "1.0.5", + "version": "1.0.6", "description": "Zen CLI helper — sign in to Zen and use its AI models in Claude Code, Codex, and more", "type": "module", "bin": { @@ -29,6 +29,6 @@ }, "homepage": "https://zenlm.org", "dependencies": { - "@hanzo/helper": "^1.0.5" + "@hanzo/helper": "^1.0.6" } } diff --git a/forks/zoo/package.json b/forks/zoo/package.json index f8f1f5e..43fa0e8 100644 --- a/forks/zoo/package.json +++ b/forks/zoo/package.json @@ -1,6 +1,6 @@ { "name": "@zooai/helper", - "version": "1.0.5", + "version": "1.0.6", "description": "Zoo CLI helper — sign in to Zoo and use its AI models in Claude Code, Codex, and more", "type": "module", "bin": { @@ -28,6 +28,6 @@ }, "homepage": "https://zoo.ngo", "dependencies": { - "@hanzo/helper": "^1.0.5" + "@hanzo/helper": "^1.0.6" } } diff --git a/package.json b/package.json index 0c15849..1b31ccd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hanzo/helper", - "version": "1.0.5", + "version": "1.0.6", "description": "Hanzo CLI helper for API access, cloud services, MCP, and plugins", "type": "module", "main": "./dist/index.js", diff --git a/packages/kms/package.json b/packages/kms/package.json index 48eea75..9de21b1 100644 --- a/packages/kms/package.json +++ b/packages/kms/package.json @@ -1,6 +1,6 @@ { "name": "@hanzo/kms", - "version": "1.0.5", + "version": "1.0.6", "description": "Standalone `kms` CLI — sign in with IAM and pull environment secrets for local dev", "type": "module", "bin": { @@ -31,6 +31,6 @@ }, "homepage": "https://hanzo.ai", "dependencies": { - "@hanzo/helper": "^1.0.5" + "@hanzo/helper": "^1.0.6" } } diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index ad19797..2333b2d 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -19,8 +19,10 @@ export const doctorCmd = new Command('doctor') .action(async () => { const checks: Check[] = []; - checks.push(await reachable('IAM', `${endpoints.iam}/health`)); - checks.push(await reachable('Cloud API', `${endpoints.api}/health`)); + // Probe the real endpoints the tool depends on (stable), not a bare /health + // path (which varies by gateway config): IAM issuer discovery + the model list. + checks.push(await reachable('IAM', `${endpoints.iam}/.well-known/openid-configuration`)); + checks.push(await reachable('Cloud API', `${endpoints.api}/v1/models`)); const { apiKey, user } = await getConfig(); checks.push({ diff --git a/src/lib/brand.ts b/src/lib/brand.ts index 0f27f43..59a9054 100644 --- a/src/lib/brand.ts +++ b/src/lib/brand.ts @@ -25,6 +25,9 @@ export interface Brand { clientId: string; /** Public web root — ecosystem install/download pages hang off it. */ site: string; + /** KMS host (secrets). KMS owns its own host; matches IAM's per-brand KMSHost + * (iam cmd/iam/cli/init_apps.go brandSpecs). */ + kms: string; } const BRANDS: Record = { @@ -36,6 +39,7 @@ const BRANDS: Record = { api: 'https://api.hanzo.ai', clientId: 'hanzo-app', site: 'https://hanzo.ai', + kms: 'https://kms.hanzo.ai', }, lux: { id: 'lux', @@ -45,6 +49,7 @@ const BRANDS: Record = { api: 'https://api.lux.network', clientId: 'lux-app', site: 'https://lux.network', + kms: 'https://kms.lux.network', }, zoo: { id: 'zoo', @@ -54,6 +59,7 @@ const BRANDS: Record = { api: 'https://api.zoo.ngo', clientId: 'zoo-app', site: 'https://zoo.ngo', + kms: 'https://kms.zoo.network', }, zen: { id: 'zen', @@ -63,6 +69,7 @@ const BRANDS: Record = { api: 'https://api.zenlm.org', clientId: 'zen-app', site: 'https://zenlm.org', + kms: 'https://kms.zenlm.org', }, }; diff --git a/src/lib/endpoints.ts b/src/lib/endpoints.ts index c427473..55e0387 100644 --- a/src/lib/endpoints.ts +++ b/src/lib/endpoints.ts @@ -41,6 +41,14 @@ export const endpoints = { get pricing(): string { return env('HANZO_PRICING_URL', `https://pricing.${new URL(brand.site).host}`); }, + /** + * KMS — secrets, on its own host (`kms.`, per IAM's KMSHost). KMS is + * NOT proxied under api./v1/kms today, so target the dedicated host; + * HANZO_KMS_URL overrides if a deployment fronts it elsewhere. + */ + get kms(): string { + return env('HANZO_KMS_URL', brand.kms); + }, } as const; /** IAM ops, all relative to the issuer base. */ diff --git a/src/lib/kms.ts b/src/lib/kms.ts index 5e20c65..48ad852 100644 --- a/src/lib/kms.ts +++ b/src/lib/kms.ts @@ -10,7 +10,8 @@ * * By KMS's design the bulk list returns KEYS ONLY; values are read one at a * time. `pullSecrets` composes the two: list the env, then read each value. - * IAM lives under /v1/iam/*, KMS under /v1/kms/* — the helper never crosses them. + * KMS runs on its own host (`kms.`, endpoints.kms) — it is not proxied + * under api./v1/kms — and IAM lives under /v1/iam/*; never crossed. */ import { endpoints } from './endpoints'; @@ -32,7 +33,7 @@ interface SecretMeta { env: string; } -const base = (org: string) => `${endpoints.api}/v1/kms/orgs/${encodeURIComponent(org)}/secrets`; +const base = (org: string) => `${endpoints.kms}/v1/kms/orgs/${encodeURIComponent(org)}/secrets`; const authFail = (res: Response, what: string): KmsError => res.status === 401 || res.status === 403