From 66ca5746ce84aeb6b51490f87aef7946f2f7599d Mon Sep 17 00:00:00 2001 From: constansino <65108260+constansino@users.noreply.github.com> Date: Wed, 11 Feb 2026 05:32:00 -0800 Subject: [PATCH] fix(config): avoid redacting maxTokens-like fields (#14006) * fix(config): avoid redacting maxTokens-like fields * fix(config): finalize redaction prep items (#14006) (thanks @constansino) --------- Co-authored-by: Sebastian <19554889+sebslight@users.noreply.github.com> --- CHANGELOG.md | 1 + src/config/redact-snapshot.test.ts | 34 +++++++++++++++++++++++++++++ src/config/redact-snapshot.ts | 2 +- src/config/schema.field-metadata.ts | 2 +- src/config/schema.hints.ts | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c38a8ccb4c8..23e88df1c3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ Docs: https://docs.openclaw.ai - Version alignment: bump manifests and package versions to `2026.2.10`; keep `appcast.xml` unchanged until the next macOS release cut. - CLI: add `openclaw logs --local-time` (plus `--localTime` compatibility alias) to display log timestamps in local timezone. (#13818) Thanks @xialonglee. +- Config: avoid redacting `maxTokens`-like fields during config snapshot redaction, preventing round-trip validation failures in `/config`. (#14006) Thanks @constansino. ## 2026.2.9 diff --git a/src/config/redact-snapshot.test.ts b/src/config/redact-snapshot.test.ts index 1bdc968a4e0..8d3b2cfdc78 100644 --- a/src/config/redact-snapshot.test.ts +++ b/src/config/redact-snapshot.test.ts @@ -109,6 +109,40 @@ describe("redactConfigSnapshot", () => { expect(result.config).toEqual(snapshot.config); }); + it("does not redact maxTokens-style fields", () => { + const snapshot = makeSnapshot({ + models: { + providers: { + openai: { + models: [ + { + id: "gpt-5", + maxTokens: 65536, + contextTokens: 200000, + maxTokensField: "max_completion_tokens", + }, + ], + apiKey: "sk-proj-abcdef1234567890ghij", + accessToken: "access-token-value-1234567890", + }, + }, + }, + }); + + const result = redactConfigSnapshot(snapshot); + const models = result.config.models as Record; + const providerList = (( + (models.providers as Record).openai as Record + ).models ?? []) as Array>; + expect(providerList[0]?.maxTokens).toBe(65536); + expect(providerList[0]?.contextTokens).toBe(200000); + expect(providerList[0]?.maxTokensField).toBe("max_completion_tokens"); + + const providers = (models.providers as Record>) ?? {}; + expect(providers.openai.apiKey).toBe(REDACTED_SENTINEL); + expect(providers.openai.accessToken).toBe(REDACTED_SENTINEL); + }); + it("preserves hash unchanged", () => { const snapshot = makeSnapshot({ gateway: { auth: { token: "secret-token-value-here" } } }); const result = redactConfigSnapshot(snapshot); diff --git a/src/config/redact-snapshot.ts b/src/config/redact-snapshot.ts index 2bbff9c590c..29bfb3ef565 100644 --- a/src/config/redact-snapshot.ts +++ b/src/config/redact-snapshot.ts @@ -12,7 +12,7 @@ export const REDACTED_SENTINEL = "__OPENCLAW_REDACTED__"; * Patterns that identify sensitive config field names. * Aligned with the UI-hint logic in schema.ts. */ -const SENSITIVE_KEY_PATTERNS = [/token/i, /password/i, /secret/i, /api.?key/i]; +const SENSITIVE_KEY_PATTERNS = [/token$/i, /password/i, /secret/i, /api.?key/i]; function isSensitiveKey(key: string): boolean { return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key)); diff --git a/src/config/schema.field-metadata.ts b/src/config/schema.field-metadata.ts index 96fdb5325f1..e85bed6796e 100644 --- a/src/config/schema.field-metadata.ts +++ b/src/config/schema.field-metadata.ts @@ -731,7 +731,7 @@ export const FIELD_PLACEHOLDERS: Record = { "agents.list[].identity.avatar": "avatars/openclaw.png", }; -export const SENSITIVE_PATTERNS = [/token/i, /password/i, /secret/i, /api.?key/i]; +export const SENSITIVE_PATTERNS = [/token$/i, /password/i, /secret/i, /api.?key/i]; export function isSensitivePath(path: string): boolean { return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path)); diff --git a/src/config/schema.hints.ts b/src/config/schema.hints.ts index fdcc20f34e5..56f704b6d08 100644 --- a/src/config/schema.hints.ts +++ b/src/config/schema.hints.ts @@ -745,7 +745,7 @@ const FIELD_PLACEHOLDERS: Record = { "agents.list[].identity.avatar": "avatars/openclaw.png", }; -const SENSITIVE_PATTERNS = [/token/i, /password/i, /secret/i, /api.?key/i]; +const SENSITIVE_PATTERNS = [/token$/i, /password/i, /secret/i, /api.?key/i]; function isSensitiveConfigPath(path: string): boolean { return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));