mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
## Why Managed command policies need to require a human decision independently of automatic review, hook allowances, and saved approvals. ## What changed - Support `decision = "prompt-user"` in managed `requirements.toml` prefix rules, requiring a fresh, one-time human decision for matching commands. - Add experimental `humanCommand` approval requests for clients advertising both `experimentalApi` and `requiredHumanApproval`. Accept only `accept`, `decline`, or `cancel`; reject commands when no capable client is available. - Restrict responses to capable clients that received the request, and replay pending prompts to compatible clients on reconnect. - Enable the capability in the TUI and update protocol schemas and client bindings. ## Testing Add coverage for fresh decisions overriding saved allowances, hook allowances, and automatic review, plus child-thread approval routing and rejection of responses from incompatible or unrelated clients. GitOrigin-RevId: 0b95ff6aab7f8a04b7298c8a4329d1fddf6a603e
90 lines
3.3 KiB
Rust
90 lines
3.3 KiB
Rust
//! Resolves managed fork sources through the existing name/ID lookup before final configuration.
|
|
//! The temporary app-server never starts a thread or executes a turn.
|
|
|
|
use super::*;
|
|
|
|
pub(super) struct ForkNetwork {
|
|
pub cloud_config_bundle: CloudConfigBundleLoader,
|
|
pub policy: codex_app_server_client::EmbeddedNetworkPolicy,
|
|
}
|
|
|
|
pub(super) async fn fork_source(
|
|
args: &mut crate::cli::ForkArgs,
|
|
config: &Config,
|
|
arg0_paths: &Arg0DispatchPaths,
|
|
cli_overrides: &[(String, codex_config::TomlValue)],
|
|
loader_overrides: &LoaderOverrides,
|
|
network: ForkNetwork,
|
|
strict_config: bool,
|
|
) -> anyhow::Result<std::path::PathBuf> {
|
|
let state_db = codex_core::init_state_db(config).await;
|
|
let environment_manager = EnvironmentManager::from_codex_home(
|
|
config.codex_home.clone(),
|
|
Some(ExecServerRuntimeOptions::from_optional_paths(
|
|
arg0_paths.codex_self_exe.clone(),
|
|
arg0_paths.codex_linux_sandbox_exe.clone(),
|
|
)?),
|
|
network.policy.bind(config.http_client_factory()),
|
|
)
|
|
.await?;
|
|
let client = InProcessAppServerClient::start(InProcessClientStartArgs {
|
|
required_human_approval: false,
|
|
arg0_paths: arg0_paths.clone(),
|
|
config: std::sync::Arc::new(config.clone()),
|
|
cli_overrides: cli_overrides.to_vec(),
|
|
loader_overrides: LoaderOverrides {
|
|
ignore_project_config: true,
|
|
..loader_overrides.clone()
|
|
},
|
|
strict_config,
|
|
cloud_config_bundle: network.cloud_config_bundle,
|
|
embedded_network_policy: network.policy,
|
|
feedback: CodexFeedback::new(),
|
|
log_db: None,
|
|
state_db: state_db.clone(),
|
|
environment_manager: std::sync::Arc::new(environment_manager),
|
|
config_warnings: Vec::new(),
|
|
session_source: SessionSource::Exec,
|
|
enable_codex_api_key_env: true,
|
|
client_name: "codex_exec".to_string(),
|
|
client_version: env!("CARGO_PKG_VERSION").to_string(),
|
|
experimental_api: true,
|
|
mcp_server_openai_form_elicitation: false,
|
|
opt_out_notification_methods: Vec::new(),
|
|
channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY,
|
|
})
|
|
.await?;
|
|
let result = async {
|
|
let lookup = crate::cli::ResumeArgs {
|
|
session_id: Some(args.session_id.clone()),
|
|
last: false,
|
|
all: true,
|
|
images: Vec::new(),
|
|
prompt: None,
|
|
};
|
|
let thread_id = resolve_resume_thread_id(&client, config, state_db.as_ref(), &lookup)
|
|
.await?
|
|
.ok_or_else(|| anyhow::anyhow!("Session not found: {}", args.session_id))?;
|
|
let source: ThreadReadResponse = send_request_with_response(
|
|
&client,
|
|
ClientRequest::ThreadRead {
|
|
request_id: RequestId::Integer(1),
|
|
params: ThreadReadParams {
|
|
thread_id: thread_id.clone(),
|
|
include_turns: false,
|
|
},
|
|
},
|
|
"thread/read",
|
|
)
|
|
.await
|
|
.map_err(anyhow::Error::msg)?;
|
|
args.session_id = thread_id;
|
|
Ok::<_, anyhow::Error>(latest_thread_cwd(&source.thread).await)
|
|
}
|
|
.await;
|
|
let shutdown = client.shutdown().await;
|
|
let source_cwd = result?;
|
|
shutdown?;
|
|
Ok(source_cwd)
|
|
}
|