{"record":{"id":"3d4797b7662cbf87","repo":"Hmbown/CodeWhale","slug":"agent-profile-tools-posture-other-would-wid","errorCode":null,"errorMessage":"agent profile {} tools.posture={other:?} would widen permissions; use FleetProfile policy for grants","messagePattern":"agent profile (.+?) tools\\.posture=(.+?) would widen permissions; use FleetProfile policy for grants","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/profile.rs","lineNumber":492,"sourceCode":"/// Profile ids remain untouched so an older file can still be addressed by\n/// its saved id. Only the semantic role is migrated; every new receipt and UI\n/// label derived from it therefore uses the canonical public token.\npub(crate) fn canonical_public_role_name(role: &str) -> String {\n    super::role::public_role_label(role)\n}\n\nfn reject_permission_expansion(\n    path: &Path,\n    tools: Option<&AgentProfileTools>,\n    permissions: Option<&AgentProfilePermissionsToml>,\n) -> Result<()> {\n    if let Some(posture) = tools\n        .and_then(|tools| tools.posture.as_deref())\n        .and_then(trimmed_non_empty)\n    {\n        match posture {\n            \"read-only\" | \"readonly\" | \"read_only\" => {}\n            other => bail!(\n                \"agent profile {} tools.posture={other:?} would widen permissions; use FleetProfile policy for grants\",\n                path.display()\n            ),\n        }\n    }\n\n    if let Some(permissions) = permissions {\n        if permissions.allow_shell.unwrap_or(false) {\n            bail!(\n                \"agent profile {} may not request allow_shell=true\",\n                path.display()\n            );\n        }\n        if permissions.trust.unwrap_or(false) {\n            bail!(\n                \"agent profile {} may not request trust=true\",\n                path.display()\n            );","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/profile.rs#L474-L510","documentation":"Agent profile TOML files may not widen permissions. tools.posture is accepted only as read-only (with the readonly/read_only aliases); any other posture value in an agent profile is rejected because granting postures belongs in FleetProfile policy, not per-agent profile files.","triggerScenarios":"Setting `tools.posture` in an agent profile TOML to anything other than the read-only variants — e.g. posture = \"full\", \"default\", \"standard\", or a typo like \"read-only\" with extra characters — then calling agent_profile_from_toml via the profile loader.","commonSituations":"Copying a FleetProfile policy section (with a broader posture) into an agent profile; assuming postures other than read-only are valid per-agent; misspelling the read-only value.","solutions":["Change tools.posture to \"read-only\" (or \"readonly\"/\"read_only\") in the agent profile","Remove the tools.posture line entirely if the default read-only posture is fine","Grant broader tool access through FleetProfile policy instead of the agent profile"],"exampleFix":"// before\n[tools]\nposture = \"full\"\n\n// after\n[tools]\nposture = \"read-only\"\n# broader grants go in FleetProfile policy","handlingStrategy":"validation","validationCode":"let posture = profile.get(\"tools\").and_then(|t| t.get(\"posture\")).and_then(|v| v.as_str());\nif let Some(p) = posture {\n    if !matches!(p, \"read-only\" | \"readonly\" | \"read_only\") {\n        eprintln!(\"agent profiles only allow read-only posture, got {p:?}\");\n    }\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"would widen permissions\") => {\n        eprintln!(\"move the tools.posture grant into FleetProfile policy\");\n    }\n    other => other?,\n}","preventionTips":["Only use \"read-only\" for tools.posture in agent profiles","Put broader tool grants in FleetProfile policy files, not per-agent profiles","Never copy policy permission sections into agent profile TOMLs"],"tags":["fleet","agent-profiles","permissions","config"],"backgroundTag":"permission-denied","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}