mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Add Windows sandbox readiness RPC (#20708)
## Why The desktop app on Windows needs a read-only way to tell, before the next tool call, whether the local Windows sandbox setup is in a state that should block the user and ask for setup again. The main case we want to cover is the elevated sandbox setup version bump. Today, if the app is configured for elevated Windows sandboxing and the installed setup is stale, the next sandboxed shell/exec path can end up triggering the elevated setup flow directly. That means the user can see an unexpected UAC prompt with no UI explanation. This change adds a small app-server preflight so the desktop app can ask “is Windows sandbox ready, not configured, or update-required?” during startup and show the appropriate blocking UI before the user hits a tool call. ## What changed - Added a new read-only app-server RPC: `windowsSandbox/readiness` - Added a new protocol enum and response type: - `WindowsSandboxReadiness` - `WindowsSandboxReadinessResponse` - Added core readiness logic in `core/src/windows_sandbox.rs`: - `ready` - `notConfigured` - `updateRequired` - Wired the new request through `codex_message_processor` - Regenerated the vendored app-server schema fixtures ## Readiness semantics This is intentionally a coarse startup/version-bump readiness check, not a full predictor of every runtime repair case. For now, readiness is determined from: - the configured Windows sandbox level - `sandbox_setup_is_complete()` for elevated mode That means: - `disabled` maps to `notConfigured` - `restricted token` maps to `ready` - `elevated` maps to `ready` or `updateRequired` depending on `sandbox_setup_is_complete()` This is deliberate for the first UI integration because the common case we want to catch is “the app updated, the elevated setup version bumped, and the user should see an update-required blocker instead of a surprise UAC prompt”. It does not attempt to model every case where the deeper runtime path might decide to repair or re-run setup. ## Testing - Ran `cargo fmt --all -- app-server-protocol/src/protocol/common.rs app-server-protocol/src/protocol/v2.rs app-server/src/codex_message_processor.rs core/src/windows_sandbox.rs core/src/windows_sandbox_tests.rs` - Added unit tests for the pure readiness mapping in `core/src/windows_sandbox_tests.rs` - Regenerated vendored schema fixtures with `cargo run -p codex-app-server-protocol --bin write_schema_fixtures -- --schema-root app-server-protocol/schema` - Did not run the full cargo test suite
This commit is contained in:
committed by
GitHub
Unverified
parent
f09e1936e0
commit
f35285dc78
@@ -5914,6 +5914,29 @@
|
||||
"title": "WindowsSandbox/setupStartRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"windowsSandbox/readiness"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
|
||||
+44
@@ -1577,6 +1577,29 @@
|
||||
"title": "WindowsSandbox/setupStartRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/v2/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"windowsSandbox/readiness"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -18355,6 +18378,27 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxReadiness": {
|
||||
"enum": [
|
||||
"ready",
|
||||
"notConfigured",
|
||||
"updateRequired"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WindowsSandboxReadinessResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"status": {
|
||||
"$ref": "#/definitions/v2/WindowsSandboxReadiness"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status"
|
||||
],
|
||||
"title": "WindowsSandboxReadinessResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxSetupCompletedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
+44
@@ -2336,6 +2336,29 @@
|
||||
"title": "WindowsSandbox/setupStartRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
"$ref": "#/definitions/RequestId"
|
||||
},
|
||||
"method": {
|
||||
"enum": [
|
||||
"windowsSandbox/readiness"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequestMethod",
|
||||
"type": "string"
|
||||
},
|
||||
"params": {
|
||||
"type": "null"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"method"
|
||||
],
|
||||
"title": "WindowsSandbox/readinessRequest",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -16241,6 +16264,27 @@
|
||||
},
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxReadiness": {
|
||||
"enum": [
|
||||
"ready",
|
||||
"notConfigured",
|
||||
"updateRequired"
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"WindowsSandboxReadinessResponse": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
"status": {
|
||||
"$ref": "#/definitions/WindowsSandboxReadiness"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status"
|
||||
],
|
||||
"title": "WindowsSandboxReadinessResponse",
|
||||
"type": "object"
|
||||
},
|
||||
"WindowsSandboxSetupCompletedNotification": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"properties": {
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"definitions": {
|
||||
"WindowsSandboxReadiness": {
|
||||
"enum": [
|
||||
"ready",
|
||||
"notConfigured",
|
||||
"updateRequired"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"status": {
|
||||
"$ref": "#/definitions/WindowsSandboxReadiness"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status"
|
||||
],
|
||||
"title": "WindowsSandboxReadinessResponse",
|
||||
"type": "object"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type WindowsSandboxReadiness = "ready" | "notConfigured" | "updateRequired";
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// GENERATED CODE! DO NOT MODIFY BY HAND!
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { WindowsSandboxReadiness } from "./WindowsSandboxReadiness";
|
||||
|
||||
export type WindowsSandboxReadinessResponse = { status: WindowsSandboxReadiness, };
|
||||
@@ -436,6 +436,8 @@ export type { TurnSteerResponse } from "./TurnSteerResponse";
|
||||
export type { UserInput } from "./UserInput";
|
||||
export type { WarningNotification } from "./WarningNotification";
|
||||
export type { WebSearchAction } from "./WebSearchAction";
|
||||
export type { WindowsSandboxReadiness } from "./WindowsSandboxReadiness";
|
||||
export type { WindowsSandboxReadinessResponse } from "./WindowsSandboxReadinessResponse";
|
||||
export type { WindowsSandboxSetupCompletedNotification } from "./WindowsSandboxSetupCompletedNotification";
|
||||
export type { WindowsSandboxSetupMode } from "./WindowsSandboxSetupMode";
|
||||
export type { WindowsSandboxSetupStartParams } from "./WindowsSandboxSetupStartParams";
|
||||
|
||||
@@ -843,6 +843,11 @@ client_request_definitions! {
|
||||
serialization: global("windows-sandbox-setup"),
|
||||
response: v2::WindowsSandboxSetupStartResponse,
|
||||
},
|
||||
WindowsSandboxReadiness => "windowsSandbox/readiness" {
|
||||
params: #[ts(type = "undefined")] #[serde(skip_serializing_if = "Option::is_none")] Option<()>,
|
||||
serialization: global("config"),
|
||||
response: v2::WindowsSandboxReadinessResponse,
|
||||
},
|
||||
|
||||
LoginAccount => "account/login/start" {
|
||||
params: v2::LoginAccountParams,
|
||||
|
||||
@@ -7405,6 +7405,15 @@ pub enum WindowsSandboxSetupMode {
|
||||
Unelevated,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub enum WindowsSandboxReadiness {
|
||||
Ready,
|
||||
NotConfigured,
|
||||
UpdateRequired,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
@@ -7421,6 +7430,13 @@ pub struct WindowsSandboxSetupStartResponse {
|
||||
pub started: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
pub struct WindowsSandboxReadinessResponse {
|
||||
pub status: WindowsSandboxReadiness,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export_to = "v2/")]
|
||||
|
||||
@@ -831,6 +831,11 @@ impl MessageProcessor {
|
||||
.read(params)
|
||||
.await
|
||||
.map(|response| Some(response.into())),
|
||||
ClientRequest::WindowsSandboxReadiness { .. } => self
|
||||
.windows_sandbox_processor
|
||||
.windows_sandbox_readiness()
|
||||
.await
|
||||
.map(|response| Some(response.into())),
|
||||
ClientRequest::ExternalAgentConfigDetect { params, .. } => self
|
||||
.external_agent_config_processor
|
||||
.detect(params)
|
||||
|
||||
@@ -230,6 +230,8 @@ use codex_app_server_protocol::TurnStatus;
|
||||
use codex_app_server_protocol::TurnSteerParams;
|
||||
use codex_app_server_protocol::TurnSteerResponse;
|
||||
use codex_app_server_protocol::UserInput as V2UserInput;
|
||||
use codex_app_server_protocol::WindowsSandboxReadiness;
|
||||
use codex_app_server_protocol::WindowsSandboxReadinessResponse;
|
||||
use codex_app_server_protocol::WindowsSandboxSetupCompletedNotification;
|
||||
use codex_app_server_protocol::WindowsSandboxSetupMode;
|
||||
use codex_app_server_protocol::WindowsSandboxSetupStartParams;
|
||||
@@ -274,6 +276,7 @@ use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_core::windows_sandbox::WindowsSandboxSetupMode as CoreWindowsSandboxSetupMode;
|
||||
use codex_core::windows_sandbox::WindowsSandboxSetupRequest;
|
||||
use codex_core::windows_sandbox::sandbox_setup_is_complete;
|
||||
use codex_core_plugins::OPENAI_CURATED_MARKETPLACE_NAME;
|
||||
use codex_core_plugins::PluginInstallError as CorePluginInstallError;
|
||||
use codex_core_plugins::PluginInstallRequest;
|
||||
|
||||
@@ -20,6 +20,12 @@ impl WindowsSandboxRequestProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn windows_sandbox_readiness(
|
||||
&self,
|
||||
) -> Result<WindowsSandboxReadinessResponse, JSONRPCErrorError> {
|
||||
Ok(determine_windows_sandbox_readiness(&self.config))
|
||||
}
|
||||
|
||||
pub(crate) async fn windows_sandbox_setup_start(
|
||||
&self,
|
||||
request_id: &ConnectionRequestId,
|
||||
@@ -101,3 +107,80 @@ impl WindowsSandboxRequestProcessor {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn determine_windows_sandbox_readiness(config: &Config) -> WindowsSandboxReadinessResponse {
|
||||
if !cfg!(windows) {
|
||||
return WindowsSandboxReadinessResponse {
|
||||
status: WindowsSandboxReadiness::NotConfigured,
|
||||
};
|
||||
}
|
||||
|
||||
determine_windows_sandbox_readiness_from_state(
|
||||
WindowsSandboxLevel::from_config(config),
|
||||
sandbox_setup_is_complete(config.codex_home.as_path()),
|
||||
)
|
||||
}
|
||||
|
||||
fn determine_windows_sandbox_readiness_from_state(
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
sandbox_setup_is_complete: bool,
|
||||
) -> WindowsSandboxReadinessResponse {
|
||||
let status = match windows_sandbox_level {
|
||||
WindowsSandboxLevel::Disabled => WindowsSandboxReadiness::NotConfigured,
|
||||
WindowsSandboxLevel::RestrictedToken => WindowsSandboxReadiness::Ready,
|
||||
WindowsSandboxLevel::Elevated => {
|
||||
if sandbox_setup_is_complete {
|
||||
WindowsSandboxReadiness::Ready
|
||||
} else {
|
||||
WindowsSandboxReadiness::UpdateRequired
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
WindowsSandboxReadinessResponse { status }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn determine_windows_sandbox_readiness_reports_not_configured_when_disabled() {
|
||||
let response = determine_windows_sandbox_readiness_from_state(
|
||||
WindowsSandboxLevel::Disabled,
|
||||
/*sandbox_setup_is_complete*/ false,
|
||||
);
|
||||
|
||||
assert_eq!(response.status, WindowsSandboxReadiness::NotConfigured);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_windows_sandbox_readiness_reports_ready_for_unelevated_mode() {
|
||||
let response = determine_windows_sandbox_readiness_from_state(
|
||||
WindowsSandboxLevel::RestrictedToken,
|
||||
/*sandbox_setup_is_complete*/ false,
|
||||
);
|
||||
|
||||
assert_eq!(response.status, WindowsSandboxReadiness::Ready);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_windows_sandbox_readiness_reports_ready_for_complete_elevated_mode() {
|
||||
let response = determine_windows_sandbox_readiness_from_state(
|
||||
WindowsSandboxLevel::Elevated,
|
||||
/*sandbox_setup_is_complete*/ true,
|
||||
);
|
||||
|
||||
assert_eq!(response.status, WindowsSandboxReadiness::Ready);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn determine_windows_sandbox_readiness_reports_update_required_when_elevated_setup_is_stale() {
|
||||
let response = determine_windows_sandbox_readiness_from_state(
|
||||
WindowsSandboxLevel::Elevated,
|
||||
/*sandbox_setup_is_complete*/ false,
|
||||
);
|
||||
|
||||
assert_eq!(response.status, WindowsSandboxReadiness::UpdateRequired);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user