fix(cli): prevent config set/unset from leaking runtime defaults#11949
Conversation
Additional Comments (1)
Prompt To Fix With AIThis is a comment left during a code review.
Path: src/config/io.ts
Line: 489:496
Comment:
**Defaults still written**
`writeConfigFile` currently validates with `validateConfigObjectWithPlugins(cfg)` and then serializes `stampConfigVersion(cfg)` (the original input), not `validated.config`. If the caller passes a runtime-merged object (with defaults already applied), those defaults will still be persisted even though `applyModelDefaults` was removed here. Consider serializing `validated.config` (or explicitly stripping defaults) to ensure the invariant “user config should only contain explicitly set values” actually holds.
How can I resolve this? If you propose a fix, please make it concise. |
|
Thanks for the review! You raise a valid concern about However, the scope of this PR is specifically issue #6070, which reports that
This ensures the CLI commands pass the correct pre-defaults config to You're correct that other call sites (like Making
Happy to discuss if you think the broader fix should be in this PR! |
|
@greptile review |
1cefb2b to
d209559
Compare
…et/unset Fixes openclaw#6070 The config set/unset commands were using snapshot.config (which contains runtime-merged defaults) instead of snapshot.parsed (the raw user config). This caused runtime defaults like agents.defaults to leak into the written config file when any value was set or unset. Changed both set and unset commands to use structuredClone(snapshot.parsed) to preserve only user-specified config values.
…s config
The initial fix using snapshot.parsed broke configs with $include directives.
This commit adds a new 'resolved' field to ConfigFileSnapshot that contains
the config after $include and ${ENV} substitution but BEFORE runtime defaults
are applied. This is now used by config set/unset to avoid:
1. Breaking configs with $include directives
2. Leaking runtime defaults into the written config file
Also removes applyModelDefaults from writeConfigFile since runtime defaults
should only be applied when loading, not when writing.
The newly added 'resolved' field contains secrets after ${ENV}
substitution. This commit ensures redactConfigSnapshot also redacts
the resolved field to prevent credential leaks in config.get responses.
d209559 to
a58c767
Compare
Summary
Fixes #6070
config setandconfig unsetnow use the resolved config (after$includeand${ENV}substitution) instead of the runtime-merged config with defaultsresolvedfield toConfigFileSnapshotcontaining the config before runtime defaults are appliedapplyModelDefaultsfromwriteConfigFilesince runtime defaults should only be applied at load timeresolvedfield to prevent credential leaksThe bug caused runtime defaults (like
agents.defaults.maxConcurrent) to leak into the user's config file wheneverconfig setorconfig unsetwas used.Test plan
config-cli.test.tsfail before fix, pass afterresolvedredaction inredact-snapshot.test.tspassespnpm build && pnpm checkpassesresolvedfield)Changes
src/config/types.openclaw.ts: Addedresolvedfield toConfigFileSnapshotsrc/config/io.ts: Populateresolvedfield with pre-defaults config; removedapplyModelDefaultsfromwriteConfigFilesrc/config/validation.ts: AddedvalidateConfigObjectRawfor validation without defaultssrc/cli/config-cli.ts: Usesnapshot.resolvedinstead ofsnapshot.configsrc/config/redact-snapshot.ts: Redact the newresolvedfieldsrc/config/config.ts: ExportvalidateConfigObjectRawGreptile Overview
Greptile Summary
This PR fixes
openclaw config set/unsetwriting back runtime-merged config (including defaults) by introducing aresolvedsnapshot (post$include+${ENV}substitution, pre-runtime-defaults) and using that for mutations before persisting. It also removes applying runtime defaults at write time, adds a raw validation entrypoint (validateConfigObjectRaw) to validate without defaults, and updates snapshot redaction to coverresolvedso secrets substituted from env don’t leak into logs/snapshots.These changes fit the existing config pipeline by separating: (1) raw/parsed/resolved config used for persistence and user-facing edits vs (2) runtime config used for execution with defaults and path normalization applied only on load.
Confidence Score: 5/5
validateConfigObjectwhile enabling pre-default validation where needed.Context used:
dashboard- CLAUDE.md (source)dashboard- AGENTS.md (source)