mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 23:02:02 +03:00
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>
This commit is contained in:
@@ -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.
|
- 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.
|
- 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
|
## 2026.2.9
|
||||||
|
|
||||||
|
|||||||
@@ -109,6 +109,40 @@ describe("redactConfigSnapshot", () => {
|
|||||||
expect(result.config).toEqual(snapshot.config);
|
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<string, unknown>;
|
||||||
|
const providerList = ((
|
||||||
|
(models.providers as Record<string, unknown>).openai as Record<string, unknown>
|
||||||
|
).models ?? []) as Array<Record<string, unknown>>;
|
||||||
|
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<string, Record<string, string>>) ?? {};
|
||||||
|
expect(providers.openai.apiKey).toBe(REDACTED_SENTINEL);
|
||||||
|
expect(providers.openai.accessToken).toBe(REDACTED_SENTINEL);
|
||||||
|
});
|
||||||
|
|
||||||
it("preserves hash unchanged", () => {
|
it("preserves hash unchanged", () => {
|
||||||
const snapshot = makeSnapshot({ gateway: { auth: { token: "secret-token-value-here" } } });
|
const snapshot = makeSnapshot({ gateway: { auth: { token: "secret-token-value-here" } } });
|
||||||
const result = redactConfigSnapshot(snapshot);
|
const result = redactConfigSnapshot(snapshot);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export const REDACTED_SENTINEL = "__OPENCLAW_REDACTED__";
|
|||||||
* Patterns that identify sensitive config field names.
|
* Patterns that identify sensitive config field names.
|
||||||
* Aligned with the UI-hint logic in schema.ts.
|
* 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 {
|
function isSensitiveKey(key: string): boolean {
|
||||||
return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
|
||||||
|
|||||||
@@ -731,7 +731,7 @@ export const FIELD_PLACEHOLDERS: Record<string, string> = {
|
|||||||
"agents.list[].identity.avatar": "avatars/openclaw.png",
|
"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 {
|
export function isSensitivePath(path: string): boolean {
|
||||||
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));
|
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));
|
||||||
|
|||||||
@@ -745,7 +745,7 @@ const FIELD_PLACEHOLDERS: Record<string, string> = {
|
|||||||
"agents.list[].identity.avatar": "avatars/openclaw.png",
|
"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 {
|
function isSensitiveConfigPath(path: string): boolean {
|
||||||
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));
|
return SENSITIVE_PATTERNS.some((pattern) => pattern.test(path));
|
||||||
|
|||||||
Reference in New Issue
Block a user