Codex Handbook
prompts/src/permissions_instructions_tests.rs 471 lines
use super::*;use codex_execpolicy::Decision;use codex_protocol::permissions::FileSystemAccessMode;use codex_protocol::permissions::FileSystemPath;use codex_protocol::permissions::FileSystemSandboxEntry;use codex_protocol::permissions::FileSystemSandboxPolicy;use codex_protocol::permissions::NetworkSandboxPolicy;use codex_utils_absolute_path::AbsolutePathBuf;use codex_utils_absolute_path::test_support::test_path_buf;use pretty_assertions::assert_eq;use std::path::PathBuf;#[test]fn renders_sandbox_mode_text() {    assert_eq!(        sandbox_text(SandboxMode::WorkspaceWrite, NetworkAccess::Restricted),        "Filesystem sandboxing defines which files can be read or written. `sandbox_mode` is `workspace-write`: The sandbox permits reading files, and editing files in `cwd` and `writable_roots`. Editing files in other directories requires approval. Network access is restricted."    );    assert_eq!(        sandbox_text(SandboxMode::ReadOnly, NetworkAccess::Restricted),        "Filesystem sandboxing defines which files can be read or written. `sandbox_mode` is `read-only`: The sandbox only permits reading files. Network access is restricted."    );    assert_eq!(        sandbox_text(SandboxMode::DangerFullAccess, NetworkAccess::Enabled),        "Filesystem sandboxing defines which files can be read or written. `sandbox_mode` is `danger-full-access`: No filesystem sandboxing - all commands are permitted. Network access is enabled."    );}#[test]fn builds_permissions_with_network_access_override() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnRequest,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: false,            request_permissions_tool_enabled: false,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(        text.contains("Network access is enabled."),        "expected network access to be enabled in message"    );    assert!(        text.contains("How to request escalation"),        "expected approval guidance to be included"    );}#[test]fn builds_permissions_from_profile() {    let cwd = PathBuf::from("/tmp");    let writable_root =        AbsolutePathBuf::from_absolute_path(cwd.join("repo")).expect("absolute path");    let permission_profile = PermissionProfile::from_runtime_permissions(        &FileSystemSandboxPolicy::restricted(vec![FileSystemSandboxEntry {            path: FileSystemPath::Path {                path: writable_root.clone(),            },            access: FileSystemAccessMode::Write,        }]),        NetworkSandboxPolicy::Enabled,    );    let instructions = PermissionsInstructions::from_permission_profile(        &permission_profile,        AskForApproval::UnlessTrusted,        ApprovalsReviewer::User,        &Policy::empty(),        &cwd,        /*exec_permission_approvals_enabled*/ false,        /*request_permissions_tool_enabled*/ false,    );    let text = instructions.body();    assert!(text.contains("`sandbox_mode` is `workspace-write`"));    assert!(text.contains("Network access is enabled."));    assert!(text.contains(writable_root.to_string_lossy().as_ref()));}#[test]fn builds_permissions_from_profile_with_denied_reads() {    let cwd = test_path_buf("/tmp");    let denied_root =        AbsolutePathBuf::from_absolute_path(cwd.join("blocked")).expect("absolute path");    let denied_glob = cwd.join("blocked").join("**");    let permission_profile = PermissionProfile::from_runtime_permissions(        &FileSystemSandboxPolicy::restricted(vec![            FileSystemSandboxEntry {                path: FileSystemPath::Special {                    value: codex_protocol::permissions::FileSystemSpecialPath::Root,                },                access: FileSystemAccessMode::Read,            },            FileSystemSandboxEntry {                path: FileSystemPath::Path {                    path: denied_root.clone(),                },                access: FileSystemAccessMode::Deny,            },            FileSystemSandboxEntry {                path: FileSystemPath::GlobPattern {                    pattern: denied_glob.to_string_lossy().into_owned(),                },                access: FileSystemAccessMode::Deny,            },        ]),        NetworkSandboxPolicy::Restricted,    );    let instructions = PermissionsInstructions::from_permission_profile(        &permission_profile,        AskForApproval::OnRequest,        ApprovalsReviewer::AutoReview,        &Policy::empty(),        &cwd,        /*exec_permission_approvals_enabled*/ false,        /*request_permissions_tool_enabled*/ false,    );    let text = instructions.body();    assert!(text.contains("## Denied filesystem reads"));    assert!(text.contains("Do not request escalation or additional permissions"));    assert!(text.contains(denied_root.to_string_lossy().as_ref()));    assert!(text.contains(&format!("glob `{}`", denied_glob.to_string_lossy())));}#[test]fn includes_request_rule_instructions_for_on_request() {    let mut exec_policy = Policy::empty();    exec_policy        .add_prefix_rule(&["git".to_string(), "pull".to_string()], Decision::Allow)        .expect("add rule");    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnRequest,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &exec_policy,            exec_permission_approvals_enabled: false,            request_permissions_tool_enabled: false,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("prefix_rule"));    assert!(text.contains("Approved command prefixes"));    assert!(text.contains(r#"["git", "pull"]"#));}#[test]fn includes_request_permissions_tool_instructions_for_unless_trusted_when_enabled() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::UnlessTrusted,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: false,            request_permissions_tool_enabled: true,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("`approval_policy` is `unless-trusted`"));    assert!(text.contains("# request_permissions Tool"));}#[test]fn includes_request_permissions_tool_instructions_for_on_failure_when_enabled() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnFailure,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: false,            request_permissions_tool_enabled: true,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("`approval_policy` is `on-failure`"));    assert!(text.contains("# request_permissions Tool"));}#[test]fn includes_request_permission_rule_instructions_for_on_request_when_enabled() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnRequest,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: true,            request_permissions_tool_enabled: false,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("with_additional_permissions"));    assert!(text.contains("additional_permissions"));}#[test]fn includes_request_permissions_tool_instructions_for_on_request_when_tool_is_enabled() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnRequest,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: false,            request_permissions_tool_enabled: true,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("# request_permissions Tool"));    assert!(text.contains("The built-in `request_permissions` tool is available in this session."));}#[test]fn on_request_includes_tool_guidance_alongside_inline_permission_guidance_when_both_exist() {    let instructions = PermissionsInstructions::from_permissions_with_network(        SandboxMode::WorkspaceWrite,        NetworkAccess::Enabled,        PermissionsPromptConfig {            approval_policy: AskForApproval::OnRequest,            approvals_reviewer: ApprovalsReviewer::User,            exec_policy: &Policy::empty(),            exec_permission_approvals_enabled: true,            request_permissions_tool_enabled: true,        },        /*writable_roots*/ None,    );    let text = instructions.body();    assert!(text.contains("with_additional_permissions"));    assert!(text.contains("# request_permissions Tool"));}#[test]fn auto_review_approvals_append_auto_review_specific_guidance() {    let text = approval_text(        AskForApproval::OnRequest,        ApprovalsReviewer::AutoReview,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ false,        /*request_permissions_tool_enabled*/ false,    );    assert!(text.contains("`approvals_reviewer` is `auto_review`"));    assert!(!text.contains("`approvals_reviewer` is `guardian_subagent`"));    assert!(text.contains("materially safer alternative"));}#[test]fn auto_review_approvals_omit_auto_review_specific_guidance_when_approval_is_never() {    let text = approval_text(        AskForApproval::Never,        ApprovalsReviewer::AutoReview,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ false,        /*request_permissions_tool_enabled*/ false,    );    assert!(!text.contains("`approvals_reviewer` is `auto_review`"));    assert!(!text.contains("`approvals_reviewer` is `guardian_subagent`"));}fn granular_categories_section(title: &str, categories: &[&str]) -> String {    format!("{title}\n{}", categories.join("\n"))}fn granular_prompt_expected(    prompted_categories: &[&str],    rejected_categories: &[&str],    include_shell_permission_request_instructions: bool,    include_request_permissions_tool_section: bool,) -> String {    let mut sections = vec![granular_prompt_intro_text().to_string()];    if !prompted_categories.is_empty() {        sections.push(granular_categories_section(            "These approval categories may still prompt the user when needed:",            prompted_categories,        ));    }    if !rejected_categories.is_empty() {        sections.push(granular_categories_section(            "These approval categories are automatically rejected instead of prompting the user:",            rejected_categories,        ));    }    if include_shell_permission_request_instructions {        sections.push(APPROVAL_POLICY_ON_REQUEST_RULE_REQUEST_PERMISSION.to_string());    }    if include_request_permissions_tool_section {        sections.push(request_permissions_tool_prompt_section().to_string());    }    sections.join("\n\n")}#[test]fn granular_policy_lists_prompted_and_rejected_categories_separately() {    let text = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: false,            rules: true,            skill_approval: false,            request_permissions: true,            mcp_elicitations: false,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ true,        /*request_permissions_tool_enabled*/ false,    );    assert_eq!(        text,        [            granular_prompt_intro_text().to_string(),            granular_categories_section(                "These approval categories may still prompt the user when needed:",                &["- `rules`"],            ),            granular_categories_section(                "These approval categories are automatically rejected instead of prompting the user:",                &[                    "- `sandbox_approval`",                    "- `skill_approval`",                    "- `mcp_elicitations`",                ],            ),        ]        .join("\n\n")    );}#[test]fn granular_policy_includes_command_permission_instructions_when_sandbox_approval_can_prompt() {    let text = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: true,            rules: true,            skill_approval: true,            request_permissions: true,            mcp_elicitations: true,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ true,        /*request_permissions_tool_enabled*/ false,    );    assert_eq!(        text,        granular_prompt_expected(            &[                "- `sandbox_approval`",                "- `rules`",                "- `skill_approval`",                "- `mcp_elicitations`",            ],            &[],            /*include_shell_permission_request_instructions*/ true,            /*include_request_permissions_tool_section*/ false,        )    );}#[test]fn granular_policy_omits_shell_permission_instructions_when_inline_requests_are_disabled() {    let text = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: true,            rules: true,            skill_approval: true,            request_permissions: true,            mcp_elicitations: true,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ false,        /*request_permissions_tool_enabled*/ false,    );    assert_eq!(        text,        granular_prompt_expected(            &[                "- `sandbox_approval`",                "- `rules`",                "- `skill_approval`",                "- `mcp_elicitations`",            ],            &[],            /*include_shell_permission_request_instructions*/ false,            /*include_request_permissions_tool_section*/ false,        )    );}#[test]fn granular_policy_includes_request_permissions_tool_only_when_that_prompt_can_still_fire() {    let allowed = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: true,            rules: true,            skill_approval: true,            request_permissions: true,            mcp_elicitations: true,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ true,        /*request_permissions_tool_enabled*/ true,    );    assert!(allowed.contains("# request_permissions Tool"));    let rejected = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: true,            rules: true,            skill_approval: true,            request_permissions: false,            mcp_elicitations: true,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ true,        /*request_permissions_tool_enabled*/ true,    );    assert!(!rejected.contains("# request_permissions Tool"));}#[test]fn granular_policy_lists_request_permissions_category_without_tool_section_when_tool_unavailable() {    let text = approval_text(        AskForApproval::Granular(GranularApprovalConfig {            sandbox_approval: false,            rules: false,            skill_approval: false,            request_permissions: true,            mcp_elicitations: false,        }),        ApprovalsReviewer::User,        &Policy::empty(),        /*exec_permission_approvals_enabled*/ true,        /*request_permissions_tool_enabled*/ false,    );    assert!(!text.contains("- `request_permissions`"));    assert!(!text.contains("# request_permissions Tool"));}