Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions codex-rs/app-server/tests/suite/v2/turn_start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1004,10 +1004,14 @@ async fn turn_start_rejects_invalid_permission_selection_before_starting_turn()
assert!(
err.error
.message
.contains("invalid thread settings override")
.contains("`approval_policy = \"never\"` cannot be used"),
"unexpected error message: {}",
err.error.message
);
assert!(
err.error.message.contains("allowed set [ReadOnly]"),
err.error
.message
.contains("requirements do not allow `sandbox_mode = \"danger-full-access\"`"),
"unexpected error message: {}",
err.error.message
);
Expand Down
67 changes: 67 additions & 0 deletions codex-rs/core/src/config/config_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9712,6 +9712,73 @@ async fn explicit_sandbox_mode_falls_back_when_disallowed_by_requirements() -> s
Ok(())
}

#[tokio::test]
async fn danger_full_access_with_never_is_rejected_when_requirements_force_read_only()
-> std::io::Result<()> {
let codex_home = TempDir::new()?;
std::fs::write(
codex_home.path().join(CONFIG_TOML_FILE),
r#"approval_policy = "never"
sandbox_mode = "danger-full-access"
"#,
)?;

let err = ConfigBuilder::without_managed_config_for_tests()
.codex_home(codex_home.path().to_path_buf())
.fallback_cwd(Some(codex_home.path().to_path_buf()))
.cloud_requirements(CloudRequirementsLoader::new(async {
Ok(Some(codex_config::ConfigRequirementsToml {
allowed_sandbox_modes: Some(vec![codex_config::SandboxModeRequirement::ReadOnly]),
..Default::default()
}))
}))
.build()
.await
.expect_err("requirements-constrained yolo should require sandbox approval");

assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
assert_eq!(
err.to_string(),
"`approval_policy = \"never\"` cannot be used because requirements do not allow `sandbox_mode = \"danger-full-access\"`; Codex would fall back to read-only permissions with approvals disabled. Choose an `approval_policy` based on what you need, such as `on-request`, or choose an allowed sandbox mode."
);
Ok(())
}

#[tokio::test]
async fn named_full_access_profile_with_never_is_rejected_when_requirements_force_read_only()
-> std::io::Result<()> {
let codex_home = TempDir::new()?;
std::fs::write(
codex_home.path().join(CONFIG_TOML_FILE),
r#"approval_policy = "never"
default_permissions = "dev"

[permissions.dev.filesystem]
":root" = "write"
"#,
)?;

let err = ConfigBuilder::without_managed_config_for_tests()
.codex_home(codex_home.path().to_path_buf())
.fallback_cwd(Some(codex_home.path().to_path_buf()))
.cloud_requirements(CloudRequirementsLoader::new(async {
Ok(Some(codex_config::ConfigRequirementsToml {
allowed_sandbox_modes: Some(vec![codex_config::SandboxModeRequirement::ReadOnly]),
..Default::default()
}))
}))
.build()
.await
.expect_err("requirements-constrained full-access profile should require sandbox approval");

assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput);
assert_eq!(
err.to_string(),
"`approval_policy = \"never\"` cannot be used because requirements do not allow `sandbox_mode = \"danger-full-access\"`; Codex would fall back to read-only permissions with approvals disabled. Choose an `approval_policy` based on what you need, such as `on-request`, or choose an allowed sandbox mode."
);
Ok(())
}

#[tokio::test]
async fn permission_profile_override_falls_back_when_disallowed_by_requirements()
-> std::io::Result<()> {
Expand Down
11 changes: 11 additions & 0 deletions codex-rs/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3304,6 +3304,17 @@ impl Config {
&mut constrained_permission_profile,
&mut startup_warnings,
)?;
if permission_profile_was_constrained
&& sandbox_mode_requirement_for_permission_profile(&original_permission_profile)
== SandboxModeRequirement::DangerFullAccess
&& constrained_permission_profile.get() == &PermissionProfile::read_only()
&& constrained_approval_policy.value() == AskForApproval::Never
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"`approval_policy = \"never\"` cannot be used because requirements do not allow `sandbox_mode = \"danger-full-access\"`; Codex would fall back to read-only permissions with approvals disabled. Choose an `approval_policy` based on what you need, such as `on-request`, or choose an allowed sandbox mode.",
));
}
if permission_profile_was_constrained {
// The selected profile no longer describes the effective
// permissions after requirements forced a fallback.
Expand Down
Loading