fix: seed builtin_permissions.json on startup so Settings toggles persist

Without this the file was missing on first run, load_builtin_permissions()
returned {}, and the agent fell through to _DEFAULTS={Bash:'ask'} even
though the Settings UI showed green 'always_allow' checkmarks (because the
UI defaulted missing entries to always_allow for DISPLAY but the agent
defaults to ask for SAFETY). The mismatch meant users got prompted on
every ls/cd/pwd despite having flipped Bash to always_allow in the UI.

Lifespan now seeds the file with Bash=ask and everything else=always_allow,
matching agent_manager._DEFAULTS. Idempotent: only writes if a tool is
missing; never clobbers a policy the user already set.
This commit is contained in:
ciregenz
2026-05-20 19:37:42 -07:00
parent f59bf0db9b
commit 1628e09305
+26
View File
@@ -36,11 +36,37 @@ if os.environ.get("OPENSWARM_PACKAGED") == "1":
@asynccontextmanager
async def tools_lib_lifespan():
os.makedirs(DATA_DIR, exist_ok=True)
_ensure_default_permissions()
yield
tools_lib = SubApp("tools", tools_lib_lifespan)
# Bash defaults to "ask" because it can execute untrusted text from MCP tool
# outputs (Gmail, WebFetch); every other built-in is sandboxed by domain.
# Must match agent_manager._DEFAULTS so the Settings UI and the agent agree
# on what "no policy set" means.
_DEFAULT_BUILTIN_POLICIES = {"Bash": "ask"}
def _ensure_default_permissions() -> None:
"""Seed BUILTIN_PERMISSIONS_PATH so the user's Settings toggles persist
cleanly. Without this the file is missing on first run, load returns {},
every PUT-from-the-UI overwrites with the partial payload the click
sent, and the user never sees their preferred policy stick. Idempotent:
merges current defaults in for any tool missing from an existing file,
never clobbers a policy the user already set.
"""
existing = load_builtin_permissions()
desired = {
t.name: _DEFAULT_BUILTIN_POLICIES.get(t.name, "always_allow")
for t in BUILTIN_TOOLS
}
merged = {**desired, **existing}
if merged != existing:
save_builtin_permissions(merged)
# All providers go through the Fly cloud-proxy claim handoff. The
# v1.0.28 local Google callback was retired in v1.0.29 once the prod
# Google OAuth client added the cloud's redirect URI.