fix(config): v32 migration flips baked-in verify_on_stop=true to false (#54740)

The first ship of verify-on-stop (config v30) defaulted
DEFAULT_CONFIG agent.verify_on_stop to a literal True, and migrate_config
persists defaults with strip_defaults=False — so every install that updated
through v30 had verify_on_stop: true written into config.yaml as a literal.

The v30->v31 migration only flipped missing/'auto' values to false and
deliberately preserved an explicit bool, so it skipped that entire population
and left verify-on-stop ON for everyone who had updated. A literal true was
never a user choice: the feature had no off-switch worth setting it against
until v31 introduced one, so a true persisted before v32 is always the old
machine default.

v32 migration flips a literal true -> false once, for both v30 (skipped v31)
and v31 (preserved-by-bug) installs. A true the user sets AFTER v32 is a
deliberate opt-in and is never touched.
This commit is contained in:
Teknium 2026-06-29 01:51:08 -07:00 committed by GitHub
parent 75317d82d0
commit bf0d8fed8e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 2 deletions

View file

@ -3013,7 +3013,7 @@ DEFAULT_CONFIG = {
# Config schema version - bump this when adding new required fields
"_config_version": 31,
"_config_version": 32,
}
# =============================================================================
@ -5462,6 +5462,34 @@ def migrate_config(interactive: bool = True, quiet: bool = False) -> Dict[str, A
"surface-aware behavior."
)
# ── Version 31 → 32: flip the BAKED-IN literal true to OFF (one-time) ──
# The v30→v31 flip above only caught missing/"auto" values. But the very
# first ship of verify-on-stop (config v30, commit 2f1a47b90) defaulted
# DEFAULT_CONFIG["agent"]["verify_on_stop"] to a literal True, and
# migrate_config persists defaults with strip_defaults=False — so every
# install that updated through v30 got `verify_on_stop: true` written into
# config.yaml as a literal. v31's guard deliberately preserves an explicit
# bool, so it skipped that whole population and left them ON. That literal
# true was never a user choice: the feature had no off-switch worth setting
# it against until v31 introduced one, so a true persisted before v32 is
# always the old machine default. Flip it off once here. A true the user
# sets AFTER v32 (config already at version 32) is never touched.
if current_ver < 32:
config = read_raw_config()
raw_agent = config.get("agent")
if isinstance(raw_agent, dict) and raw_agent.get("verify_on_stop") is True:
raw_agent["verify_on_stop"] = False
config["agent"] = raw_agent
save_config(config, strip_defaults=False)
results["config_added"].append("agent.verify_on_stop=false")
if not quiet:
print(
" ✓ Turned off verify-on-stop (agent.verify_on_stop: false) — "
"the old default was written into your config as a literal "
"true. Set it to true again to re-enable, or \"auto\" for the "
"legacy surface-aware behavior."
)
# ── Post-migration: disable exfiltration-shaped MCP stdio entries ──
# Users can hand-edit mcp_servers, and older installs may already contain a
# malicious entry. Preserve the stanza for auditability but mark it