{"record":{"id":"99dbedc06b97a5ed","repo":"Hmbown/CodeWhale","slug":"agent-profile-may-not-disable-approval-required","errorCode":null,"errorMessage":"agent profile {} may not disable approval_required","messagePattern":"agent profile (.+?) may not disable approval_required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/profile.rs","lineNumber":454,"sourceCode":"            ),\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            );\n        }\n        if permissions.approval_required == Some(false) {\n            bail!(\n                \"agent profile {} may not disable approval_required\",\n                path.display()\n            );\n        }\n    }\n    Ok(())\n}\n\nfn validate_agent_profile_token(path: &Path, field: &str, value: &str) -> Result<()> {\n    let trimmed = value.trim();\n    if trimmed.is_empty() {\n        bail!(\"agent profile {} {field} cannot be empty\", path.display());\n    }\n    if trimmed != value || !trimmed.chars().all(is_agent_profile_token_char) {\n        bail!(\n            \"agent profile {} {field} must be a simple token\",\n            path.display()\n        );","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/fleet/profile.rs#L436-L472","documentation":"Codewhale loads agent profile TOML files (project .codewhale/agents/*.toml and plugin components) through reject_permission_expansion (crates/tui/src/fleet/profile.rs:422). Workspace and plugin profiles are untrusted for security posture: they may not weaken the human-approval gate. A [permissions] table containing approval_required = false is rejected at load time, exactly like allow_shell = true and trust = true. Permission grants live only in the FleetProfile policy layer, never in profile files.","triggerScenarios":"Calling load_agent_profile_file (directly or via the profile-directory scan / plugin component load) on a TOML file whose [permissions] table sets approval_required = false. The check is exact: Some(false) bails; approval_required = true or an omitted key passes.","commonSituations":"Copying a profile written before this policy existed; trying to make a fleet worker run unattended by disabling approvals in its profile; a plugin shipping profiles that assumed self-approved execution.","solutions":["Open the profile file named in the error message and delete approval_required = false from [permissions] (or set it to true)","Move the permission change to the FleetProfile policy layer or launch-time flags that own grants - profiles can only inherit permissions, never widen them","For unattended runs, configure the approval policy at the fleet/launch level instead of per profile"],"exampleFix":"# before (.codewhale/agents/scout.toml)\n[permissions]\napproval_required = false\n\n# after\n[permissions]\napproval_required = true\n# or delete the key entirely","handlingStrategy":"validation","validationCode":"fn profile_disables_approval(raw: &str) -> bool {\n    let mut in_permissions = false;\n    for line in raw.lines() {\n        let t = line.trim();\n        if t.starts_with('[') {\n            in_permissions = t == \"[permissions]\";\n        } else if in_permissions && t.starts_with(\"approval_required\") && t.contains(\"false\") {\n            return true;\n        }\n    }\n    false\n}\n// run before load_agent_profile_file / roster scans","typeGuard":null,"tryCatchPattern":"match load_agent_profile_file(&path) {\n    Ok(profile) => profiles.push(profile),\n    Err(err) if err.to_string().contains(\"may not disable approval_required\") => {\n        report_policy_violation(&path); // guide author to policy layer\n    }\n    Err(err) => issues.push(format!(\"{err:#}\")),\n}","preventionTips":["Treat [permissions] in profile TOML as read-only: never generate allow_shell, trust, or approval_required=false","Lint .codewhale/agents/*.toml and plugin profile components in CI with the same rules","Route every request for fewer approvals through the FleetProfile policy layer, not profile files"],"tags":["agent-profile","permissions","security","toml","fleet"],"backgroundTag":"security-policy-violation","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}