{"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":433,"sourceCode":"pub(crate) fn canonical_public_role_name(role: &str) -> String {\n    match role.trim().to_ascii_lowercase().as_str() {\n        \"oracle\" | \"advisor\" => \"consultant\".to_string(),\n        _ => role.to_string(),\n    }\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":415,"sourceCodeEnd":451,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/profile.rs#L415-L451","documentation":"reject_permission_expansion only accepts tools.posture values \"read-only\", \"readonly\", or \"read_only\" in agent profile files; any other posture would widen what the profile may do. Granting beyond read-only is reserved to the FleetProfile policy layer, so an expansive posture in a TOML profile is rejected at load time.","triggerScenarios":"An agent profile TOML with tools.posture = \"full\", \"write\", \"interactive\", or any non-read-only spelling (e.g. \"read only\" with a space, \"Read-Only\").","commonSituations":"Porting a profile from another tool where postures like 'full-access' exist; attempting to grant shell/write via the profile instead of the fleet policy; typos in the posture string.","solutions":["Set tools.posture to \"read-only\" (or remove the key) in the profile TOML","Move any real grants into the FleetProfile policy configuration where they are auditable","Check exact spelling: only the three read-only variants are accepted"],"exampleFix":"# before\n[tools]\nposture = \"full\"\n\n# after\n[tools]\nposture = \"read-only\"\n# grants live in the FleetProfile policy, not here","handlingStrategy":"validation","validationCode":"fn posture_is_allowed(posture: &str) -> bool {\n    matches!(posture, \"read-only\" | \"readonly\" | \"read_only\")\n}\n\n// lint profile files before the loader does:\nassert!(posture_is_allowed(&profile.tools.posture.unwrap_or_default()));","typeGuard":null,"tryCatchPattern":"if let Err(err) = load_agent_profile_file(&path) {\n    if err.to_string().contains(\"would widen permissions\") {\n        eprintln!(\"set tools.posture = \\\"read-only\\\"; grant via FleetProfile policy instead\");\n    }\n    return Err(err.into());\n}","preventionTips":["Keep profile files read-only by default; omit tools.posture unless needed","Centralize all grants in FleetProfile policy where they can be reviewed","Lint profile TOMLs in CI for non-read-only postures"],"tags":["fleet","agent-profiles","permissions","configuration","rust","codewhale"],"backgroundTag":"permission-escalation-rejected","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}