mirror of
https://github.com/openai/codex.git
synced 2026-05-05 22:01:37 +03:00
## Summary - split `models-manager` out of `core` and add `ModelsManagerConfig` plus `Config::to_models_manager_config()` so model metadata paths stop depending on `core::Config` - move login-owned/auth-owned code out of `core` into `codex-login`, move model provider config into `codex-model-provider-info`, move API bridge mapping into `codex-api`, move protocol-owned types/impls into `codex-protocol`, and move response debug helpers into a dedicated `response-debug-context` crate - move feedback tag emission into `codex-feedback`, relocate tests to the crates that now own the code, and keep broad temporary re-exports so this PR avoids a giant import-only rewrite ## Major moves and decisions - created `codex-models-manager` as the owner for model cache/catalog/config/model info logic, including the new `ModelsManagerConfig` struct - created `codex-model-provider-info` as the owner for provider config parsing/defaults and kept temporary `codex-login`/`codex-core` re-exports for old import paths - moved `api_bridge` error mapping + `CoreAuthProvider` into `codex-api`, while `codex-login::api_bridge` temporarily re-exports those symbols and keeps the `auth_provider_from_auth` wrapper - moved `auth_env_telemetry` and `provider_auth` ownership to `codex-login` - moved `CodexErr` ownership to `codex-protocol::error`, plus `StreamOutput`, `bytes_to_string_smart`, and network policy helpers to protocol-owned modules - created `codex-response-debug-context` for `extract_response_debug_context`, `telemetry_transport_error_message`, and related response-debug plumbing instead of leaving that behavior in `core` - moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and `emit_feedback_request_tags_with_auth_env` to `codex-feedback` - deferred removal of temporary re-exports and the mechanical import rewrites to a stacked follow-up PR so this PR stays reviewable ## Test moves - moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to `login/tests/suite/auth_refresh.rs` - moved text encoding coverage from `core/tests/suite/text_encoding_fix.rs` to `protocol/src/exec_output_tests.rs` - moved model info override coverage from `core/tests/suite/model_info_overrides.rs` to `models-manager/src/model_info_overrides_tests.rs` --------- Co-authored-by: Codex <noreply@openai.com>
146 lines
4.3 KiB
Rust
146 lines
4.3 KiB
Rust
#![cfg(target_os = "macos")]
|
|
|
|
use std::collections::HashMap;
|
|
use std::string::ToString;
|
|
|
|
use crate::error::Result;
|
|
use codex_core::exec::ExecCapturePolicy;
|
|
use codex_core::exec::ExecParams;
|
|
use codex_core::exec::ExecToolCallOutput;
|
|
use codex_core::exec::process_exec_tool_call;
|
|
use codex_core::sandboxing::SandboxPermissions;
|
|
use codex_core::spawn::CODEX_SANDBOX_ENV_VAR;
|
|
use codex_protocol::config_types::WindowsSandboxLevel;
|
|
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
|
use codex_protocol::permissions::NetworkSandboxPolicy;
|
|
use codex_protocol::protocol::SandboxPolicy;
|
|
use codex_sandboxing::SandboxType;
|
|
use codex_sandboxing::get_platform_sandbox;
|
|
use tempfile::TempDir;
|
|
|
|
fn skip_test() -> bool {
|
|
if std::env::var(CODEX_SANDBOX_ENV_VAR) == Ok("seatbelt".to_string()) {
|
|
eprintln!("{CODEX_SANDBOX_ENV_VAR} is set to 'seatbelt', skipping test.");
|
|
return true;
|
|
}
|
|
|
|
false
|
|
}
|
|
|
|
#[expect(clippy::expect_used)]
|
|
async fn run_test_cmd(tmp: TempDir, cmd: Vec<&str>) -> Result<ExecToolCallOutput> {
|
|
let sandbox_type = get_platform_sandbox(/*windows_sandbox_enabled*/ false)
|
|
.expect("should be able to get sandbox type");
|
|
assert_eq!(sandbox_type, SandboxType::MacosSeatbelt);
|
|
|
|
let params = ExecParams {
|
|
command: cmd.iter().map(ToString::to_string).collect(),
|
|
cwd: tmp.path().to_path_buf(),
|
|
expiration: 1000.into(),
|
|
capture_policy: ExecCapturePolicy::ShellTool,
|
|
env: HashMap::new(),
|
|
network: None,
|
|
sandbox_permissions: SandboxPermissions::UseDefault,
|
|
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
|
windows_sandbox_private_desktop: false,
|
|
justification: None,
|
|
arg0: None,
|
|
};
|
|
|
|
let policy = SandboxPolicy::new_read_only_policy();
|
|
|
|
process_exec_tool_call(
|
|
params,
|
|
&policy,
|
|
&FileSystemSandboxPolicy::from(&policy),
|
|
NetworkSandboxPolicy::from(&policy),
|
|
tmp.path(),
|
|
&None,
|
|
/*use_legacy_landlock*/ false,
|
|
/*stdout_stream*/ None,
|
|
)
|
|
.await
|
|
}
|
|
|
|
/// Command succeeds with exit code 0 normally
|
|
#[tokio::test]
|
|
async fn exit_code_0_succeeds() {
|
|
if skip_test() {
|
|
return;
|
|
}
|
|
|
|
let tmp = TempDir::new().expect("should be able to create temp dir");
|
|
let cmd = vec!["echo", "hello"];
|
|
|
|
let output = run_test_cmd(tmp, cmd).await.unwrap();
|
|
assert_eq!(output.stdout.text, "hello\n");
|
|
assert_eq!(output.stderr.text, "");
|
|
assert_eq!(output.stdout.truncated_after_lines, None);
|
|
}
|
|
|
|
/// Command succeeds with exit code 0 normally
|
|
#[tokio::test]
|
|
async fn truncates_output_lines() {
|
|
if skip_test() {
|
|
return;
|
|
}
|
|
|
|
let tmp = TempDir::new().expect("should be able to create temp dir");
|
|
let cmd = vec!["seq", "300"];
|
|
|
|
let output = run_test_cmd(tmp, cmd).await.unwrap();
|
|
|
|
let expected_output = (1..=300)
|
|
.map(|i| format!("{i}\n"))
|
|
.collect::<Vec<_>>()
|
|
.join("");
|
|
assert_eq!(output.stdout.text, expected_output);
|
|
assert_eq!(output.stdout.truncated_after_lines, None);
|
|
}
|
|
|
|
/// Command succeeds with exit code 0 normally
|
|
#[tokio::test]
|
|
async fn truncates_output_bytes() {
|
|
if skip_test() {
|
|
return;
|
|
}
|
|
|
|
let tmp = TempDir::new().expect("should be able to create temp dir");
|
|
// each line is 1000 bytes
|
|
let cmd = vec!["bash", "-lc", "seq 15 | awk '{printf \"%-1000s\\n\", $0}'"];
|
|
|
|
let output = run_test_cmd(tmp, cmd).await.unwrap();
|
|
|
|
assert!(output.stdout.text.len() >= 15000);
|
|
assert_eq!(output.stdout.truncated_after_lines, None);
|
|
}
|
|
|
|
/// Command not found returns exit code 127, this is not considered a sandbox error
|
|
#[tokio::test]
|
|
async fn exit_command_not_found_is_ok() {
|
|
if skip_test() {
|
|
return;
|
|
}
|
|
|
|
let tmp = TempDir::new().expect("should be able to create temp dir");
|
|
let cmd = vec!["/bin/bash", "-c", "nonexistent_command_12345"];
|
|
run_test_cmd(tmp, cmd).await.unwrap();
|
|
}
|
|
|
|
/// Writing a file fails and should be considered a sandbox error
|
|
#[tokio::test]
|
|
async fn write_file_fails_as_sandbox_error() {
|
|
if skip_test() {
|
|
return;
|
|
}
|
|
|
|
let tmp = TempDir::new().expect("should be able to create temp dir");
|
|
let path = tmp.path().join("test.txt");
|
|
let cmd = vec![
|
|
"/user/bin/touch",
|
|
path.to_str().expect("should be able to get path"),
|
|
];
|
|
|
|
assert!(run_test_cmd(tmp, cmd).await.is_err());
|
|
}
|