From 149e71e9922e059d103be6eef35c23197423f893 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Mon, 14 Sep 2026 21:36:13 +0800 Subject: [PATCH] Read the health-check token from the keychain like the CLI does. `vp run health` still read the token from `~/.void/config.json`, but `void auth login` now stores it in the system keychain, so the check failed on a machine that had just logged in. The script now resolves the token in the same order as `getToken()` in the CLI: `VOID_TOKEN`, then the keychain (`dev.void.cli` / `token` or `stagingToken`), then the config file. It only reads; the CLI owns the file-to-keychain migration. The keyring addon is imported lazily so a missing native binary falls through to the env or file token instead of aborting the script. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01WNXbwieSdsSErZwQ7HWRwG --- platform/packages/api/package.json | 1 + platform/packages/api/scripts/health.ts | 27 +++++++++++++++++++++---- pnpm-lock.yaml | 3 +++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/platform/packages/api/package.json b/platform/packages/api/package.json index dd137f954..38886265d 100644 --- a/platform/packages/api/package.json +++ b/platform/packages/api/package.json @@ -45,6 +45,7 @@ "devDependencies": { "@cloudflare/workers-types": "catalog:platform", "@electric-sql/pglite": "0.5.8", + "@napi-rs/keyring": "2.0.0", "@types/pg": "8.23.1", "drizzle-kit": "^0.31.10", "miniflare": "^4.20260421.0", diff --git a/platform/packages/api/scripts/health.ts b/platform/packages/api/scripts/health.ts index 30a6051ca..e9cb3605a 100644 --- a/platform/packages/api/scripts/health.ts +++ b/platform/packages/api/scripts/health.ts @@ -7,6 +7,7 @@ * Usage: * node scripts/health.ts # production * node scripts/health.ts --staging # staging + * VOID_TOKEN=... node scripts/health.ts # CI / explicit token */ import { readFileSync, readdirSync } from 'node:fs'; @@ -17,6 +18,20 @@ import { join, resolve } from 'node:path'; const isStaging = process.argv.includes('--staging'); +const KEYRING_SERVICE = 'dev.void.cli'; + +// The keyring is a native addon. Load it lazily and treat a missing binary +// (CI, Docker, SSH) like an empty keychain, so VOID_TOKEN and the file +// fallback keep working without it. +async function keyringGet(account: string): Promise { + try { + const { Entry } = await import('@napi-rs/keyring'); + return new Entry(KEYRING_SERVICE, account).getPassword(); + } catch { + return null; + } +} + type Config = Readonly<{ token?: string; stagingToken?: string; @@ -31,13 +46,17 @@ function readConfig(): Config { } } -const config = readConfig(); -const token = isStaging ? config.stagingToken : config.token; +// Token resolution order: VOID_TOKEN env > system keychain > ~/.void/config.json. +// Mirrors getToken() in packages/void/src/cli/auth.ts (read-only: no migration here). +const account = isStaging ? 'stagingToken' : 'token'; +const token = process.env.VOID_TOKEN || (await keyringGet(account)) || readConfig()[account]; const baseUrl = isStaging ? 'https://api.staging.void.cloud' : 'https://api.void.cloud'; if (!token) { - console.error(`No ${isStaging ? 'stagingToken' : 'token'} found in ~/.void/config.json`); - console.error('Run `void login` first.'); + console.error(`No ${account} found in the system keychain or ~/.void/config.json.`); + console.error( + 'Run `void auth login` first (in a staging project for --staging), or set VOID_TOKEN.', + ); process.exit(1); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51240ccd0..c5d35e506 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -729,6 +729,9 @@ importers: '@electric-sql/pglite': specifier: 0.5.8 version: 0.5.8 + '@napi-rs/keyring': + specifier: 2.0.0 + version: 2.0.0 '@types/pg': specifier: 8.23.1 version: 8.23.1