mirror of
https://github.com/volcengine/OpenViking.git
synced 2026-10-02 02:07:33 +08:00
Issue #3522 — the OpenClaw plugin's `config.apiKey` only accepted a plain string, resolved through local `${ENV_VAR}` interpolation. `INSTALL*.md` documented this as a known limitation: users who store their other OpenClaw provider credentials (LLM, TTS, MCP servers) through the standard `{source, id[, provider]}` SecretRef mechanism (env / file mount / exec-backed vault such as 1Password, Vault, gopass) had to keep the OpenViking key as cleartext inside `openclaw.json`. ### config.ts — `string | OpenVikingSecretRef` widening * Add `OpenVikingSecretRef = "env"|"file"|"exec"` discriminated union type, matching the shape OpenClaw core uses for its own credential fields (`env` + `file` implemented in-plugin, `exec` forwarded to `child_process` so providers like `@transmitt0r/openclaw-plugin-onepassword` can manage the OpenViking key without SDK coupling). * Add `resolveSecret()` resolver with explicit, actionable errors: - env: unset var = throw, no silent empty fallback - file: `~` expanded, UTF-8 read, whitespace trimmed; unreadable file rethrows with the OpenViking field name prefixed so config misconfigs surface with a clear label and path - exec: lazy `require("node:child_process").execFileSync(provider,[id])`, stdout trimmed, 15s timeout; errors prefixed with provider + id - unknown source / missing id / missing exec provider = explicit throw * `memoryOpenVikingConfigSchema.parse()` widens `rawApiKey` to `string | OpenVikingSecretRef`, then passes it through `resolveSecret(rawApiKey, "config.apiKey")` *before* the existing `resolveEnvVars` pass. Plain strings transparently fall through `resolveSecret` unchanged, so `${ENV_VAR}` interpolation is preserved 100% backward-compatibly. * `OPENVIKING_API_KEY` env fallback is unchanged and triggers only when the `apiKey` config key is absent — a user who deliberately sets `apiKey: ""` still gets "" (explicitly unauthenticated), not the env fallback. * `uiHints.apiKey.help` documents the SecretRef shape and recommends it. ### openclaw.plugin.json — widening schema + UI hints * `configSchema.properties.apiKey` becomes `oneOf: [string, env ref, file ref, exec ref]`. Each object variant has a `title`, `additionalProperties: false`, `required`, and explicit description per field, so OpenClaw's config UI can render them individually instead of showing a generic JSON object blob. * `uiHints.apiKey.help` matches the new config.ts wording. ### INSTALL.md / INSTALL-ZH.md — SecretRef usage tables Replace the old "plaintext / chmod 0600" caveat bullet with a 3-row table (env / file / exec) showing example JSON + notes (Kubernetes secretKeyRef mount for `file`, 1Password `op://` URL convention for `exec`). The backward-compat string path is retained at the end of the new bullet so existing deployments that haven't migrated yet still get the old permission advice — no surprise behaviour for upgrading users. ### tests/ut/config.test.ts — SecretRef regression suite (10 new cases) Under a new `describe("… SecretRef (#3522)")`: 1. Backward compat: `${OV_KEY}` interpolation still resolves. 2. env source — happy path with a fresh env var. 3. env source — unset var throws, no silent fallback. 4. file source — real `mkdtemp`-created file, trimmed whitespace. Cleanup in `afterEach`. 5. file source — missing-path error message contains readable label + path. 6. exec source — `vi.spyOn(child_process.execFileSync)` asserts provider + args, stdout trimmed. 7. exec source — missing `provider` field errors. 8. Schema validation — unknown `source` and missing `id` each throw with error messages that name the problem. 9. Env fallback boundary — explicit `apiKey: ""` is NOT overridden by OPENVIKING_API_KEY, but `apiKey` absent IS (backward-compat behaviour contract pinned with a test so future refactors can't regress). Covers every branch inside `resolveSecret()`, plus the backward-compat contracts issue #3522 called out.