mirror of
https://github.com/openai/codex.git
synced 2026-11-12 21:20:34 +00:00
rename Desktop distribution crate to installation
This commit is contained in:
Generated
+2
-2
@@ -2291,7 +2291,7 @@ dependencies = [
|
||||
"codex-config",
|
||||
"codex-core",
|
||||
"codex-core-plugins",
|
||||
"codex-desktop-distribution",
|
||||
"codex-desktop-installation",
|
||||
"codex-exec",
|
||||
"codex-exec-server",
|
||||
"codex-execpolicy",
|
||||
@@ -2784,7 +2784,7 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codex-desktop-distribution"
|
||||
name = "codex-desktop-installation"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-utils-absolute-path",
|
||||
|
||||
+2
-2
@@ -33,7 +33,7 @@ members = [
|
||||
"connectors",
|
||||
"config",
|
||||
"context-fragments",
|
||||
"desktop-distribution",
|
||||
"desktop-installation",
|
||||
"shell-command",
|
||||
"shell-escalation",
|
||||
"skills",
|
||||
@@ -166,7 +166,7 @@ codex-home = { path = "codex-home" }
|
||||
codex-config = { path = "config" }
|
||||
codex-connectors = { path = "connectors" }
|
||||
codex-context-fragments = { path = "context-fragments" }
|
||||
codex-desktop-distribution = { path = "desktop-distribution" }
|
||||
codex-desktop-installation = { path = "desktop-installation" }
|
||||
codex-core = { path = "core" }
|
||||
codex-core-api = { path = "core-api" }
|
||||
codex-core-plugins = { path = "core-plugins" }
|
||||
|
||||
@@ -31,7 +31,7 @@ codex-chatgpt = { workspace = true }
|
||||
codex-cloud-tasks = { path = "../cloud-tasks" }
|
||||
codex-utils-cli = { workspace = true }
|
||||
codex-config = { workspace = true }
|
||||
codex-desktop-distribution = { workspace = true }
|
||||
codex-desktop-installation = { workspace = true }
|
||||
codex-core = { workspace = true }
|
||||
codex-core-plugins = { workspace = true }
|
||||
codex-home = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use anyhow::Context as _;
|
||||
use codex_desktop_distribution::discover_installed_distribution;
|
||||
use codex_desktop_distribution::validate_installed_distribution_at;
|
||||
use codex_desktop_installation::discover_desktop_installation;
|
||||
use codex_desktop_installation::validate_desktop_installation_at;
|
||||
use std::ffi::CString;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
@@ -66,10 +66,10 @@ fn is_apple_silicon_mac() -> bool {
|
||||
}
|
||||
|
||||
async fn find_existing_codex_app_path() -> anyhow::Result<Option<PathBuf>> {
|
||||
let distribution = tokio::task::spawn_blocking(discover_installed_distribution)
|
||||
let installation = tokio::task::spawn_blocking(discover_desktop_installation)
|
||||
.await
|
||||
.context("Desktop discovery task failed")??;
|
||||
Ok(distribution.map(|distribution| distribution.app_root().to_path_buf()))
|
||||
Ok(installation.map(|installation| installation.app_root().to_path_buf()))
|
||||
}
|
||||
|
||||
async fn open_codex_app(app_path: &Path, workspace: &Path) -> anyhow::Result<()> {
|
||||
@@ -174,15 +174,15 @@ async fn install_codex_app_bundle(app_in_volume: &Path) -> anyhow::Result<PathBu
|
||||
|
||||
async fn validate_installed_codex_app(app_path: PathBuf) -> anyhow::Result<PathBuf> {
|
||||
let candidate = app_path.clone();
|
||||
let distribution =
|
||||
tokio::task::spawn_blocking(move || validate_installed_distribution_at(candidate))
|
||||
let installation =
|
||||
tokio::task::spawn_blocking(move || validate_desktop_installation_at(candidate))
|
||||
.await
|
||||
.context("Desktop validation task failed")??;
|
||||
let app_path_display = app_path.display();
|
||||
let distribution = distribution.with_context(|| {
|
||||
let installation = installation.with_context(|| {
|
||||
format!("refusing to launch unverified Codex Desktop at {app_path_display}")
|
||||
})?;
|
||||
Ok(distribution.app_root().to_path_buf())
|
||||
Ok(installation.app_root().to_path_buf())
|
||||
}
|
||||
|
||||
fn candidate_applications_dirs() -> anyhow::Result<Vec<PathBuf>> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use anyhow::Context as _;
|
||||
use codex_desktop_distribution::discover_installed_distribution;
|
||||
use codex_desktop_installation::discover_desktop_installation;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use tokio::process::Command;
|
||||
@@ -32,7 +32,7 @@ pub async fn run_windows_app_open_or_install(
|
||||
}
|
||||
|
||||
async fn codex_app_is_installed() -> anyhow::Result<bool> {
|
||||
Ok(tokio::task::spawn_blocking(discover_installed_distribution)
|
||||
Ok(tokio::task::spawn_blocking(discover_desktop_installation)
|
||||
.await
|
||||
.context("Desktop discovery task failed")??
|
||||
.is_some())
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "desktop-distribution",
|
||||
crate_name = "codex_desktop_distribution",
|
||||
)
|
||||
@@ -1,6 +0,0 @@
|
||||
use crate::DesktopDistributionError;
|
||||
use crate::InstalledDesktop;
|
||||
|
||||
pub(crate) fn discover() -> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
Ok(None)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
load("//:defs.bzl", "codex_rust_crate")
|
||||
|
||||
codex_rust_crate(
|
||||
name = "desktop-installation",
|
||||
crate_name = "codex_desktop_installation",
|
||||
)
|
||||
@@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "codex-desktop-distribution"
|
||||
name = "codex-desktop-installation"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "codex_desktop_distribution"
|
||||
name = "codex_desktop_installation"
|
||||
path = "src/lib.rs"
|
||||
doctest = false
|
||||
|
||||
+23
-23
@@ -22,10 +22,10 @@ mod platform;
|
||||
const DESKTOP_RESOURCES_PATH_ENV_VAR: &str = "CODEX_DESKTOP_RESOURCES_PATH";
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum DesktopDistributionError {
|
||||
pub enum DesktopInstallationError {
|
||||
/// No launcher hint was provided and no installed Codex Desktop app was found. This can
|
||||
/// happen, for example, when Desktop was uninstalled after installing a bundled plugin.
|
||||
#[error("no installed Codex Desktop distribution was found")]
|
||||
#[error("no Codex Desktop installation was found")]
|
||||
NotFound,
|
||||
/// The platform app-discovery mechanism could not be queried successfully.
|
||||
#[error("Codex Desktop discovery failed: {0}")]
|
||||
@@ -52,19 +52,19 @@ impl DesktopResources {
|
||||
pub fn contained_file(
|
||||
&self,
|
||||
relative_path: impl AsRef<Path>,
|
||||
) -> Result<AbsolutePathBuf, DesktopDistributionError> {
|
||||
) -> Result<AbsolutePathBuf, DesktopInstallationError> {
|
||||
contained_path(&self.root, relative_path.as_ref(), ResourceKind::File)
|
||||
}
|
||||
|
||||
pub fn contained_directory(
|
||||
&self,
|
||||
relative_path: impl AsRef<Path>,
|
||||
) -> Result<AbsolutePathBuf, DesktopDistributionError> {
|
||||
) -> Result<AbsolutePathBuf, DesktopInstallationError> {
|
||||
contained_path(&self.root, relative_path.as_ref(), ResourceKind::Directory)
|
||||
}
|
||||
|
||||
/// Uses a resources directory supplied by the trusted Desktop launcher.
|
||||
pub fn from_trusted_path(root: PathBuf) -> Result<Self, DesktopDistributionError> {
|
||||
pub fn from_trusted_path(root: PathBuf) -> Result<Self, DesktopInstallationError> {
|
||||
let root = canonical(&root, "resources root")?;
|
||||
if !root.as_path().is_dir() {
|
||||
return Err(containment("expected the resources root to be a directory"));
|
||||
@@ -74,12 +74,12 @@ impl DesktopResources {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InstalledDesktop {
|
||||
pub struct VerifiedDesktopInstallation {
|
||||
app_root: AbsolutePathBuf,
|
||||
resources: DesktopResources,
|
||||
}
|
||||
|
||||
impl InstalledDesktop {
|
||||
impl VerifiedDesktopInstallation {
|
||||
pub fn app_root(&self) -> &Path {
|
||||
self.app_root.as_path()
|
||||
}
|
||||
@@ -88,7 +88,7 @@ impl InstalledDesktop {
|
||||
fn from_paths(
|
||||
app_root: PathBuf,
|
||||
resources_root: PathBuf,
|
||||
) -> Result<Self, DesktopDistributionError> {
|
||||
) -> Result<Self, DesktopInstallationError> {
|
||||
let app_root = canonical(&app_root, "application root")?;
|
||||
let resources = DesktopResources::from_trusted_path(resources_root)?;
|
||||
if resources.root == app_root || !resources.root.as_path().starts_with(app_root.as_path()) {
|
||||
@@ -104,29 +104,29 @@ impl InstalledDesktop {
|
||||
}
|
||||
|
||||
/// Uses resources supplied by Desktop, otherwise discovers the installed stable app.
|
||||
pub fn locate_current_or_installed_resources() -> Result<DesktopResources, DesktopDistributionError>
|
||||
pub fn locate_current_or_installed_resources() -> Result<DesktopResources, DesktopInstallationError>
|
||||
{
|
||||
if let Some(resources_root) = std::env::var_os(DESKTOP_RESOURCES_PATH_ENV_VAR) {
|
||||
return DesktopResources::from_trusted_path(PathBuf::from(resources_root));
|
||||
}
|
||||
discover_installed_distribution()?
|
||||
.map(|distribution| distribution.resources)
|
||||
.ok_or(DesktopDistributionError::NotFound)
|
||||
discover_desktop_installation()?
|
||||
.map(|installation| installation.resources)
|
||||
.ok_or(DesktopInstallationError::NotFound)
|
||||
}
|
||||
|
||||
/// Discovers an installed Desktop app without consulting the launcher resources hint.
|
||||
pub fn discover_installed_distribution()
|
||||
-> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
pub fn discover_desktop_installation()
|
||||
-> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
platform::discover()
|
||||
}
|
||||
|
||||
/// Validates a macOS Codex app bundle at a known path using the same identity and containment
|
||||
/// checks as installed-app discovery. Returns `Ok(None)` when the path is not a trusted Codex
|
||||
/// Desktop distribution.
|
||||
/// Desktop installation.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn validate_installed_distribution_at(
|
||||
pub fn validate_desktop_installation_at(
|
||||
app_root: impl AsRef<Path>,
|
||||
) -> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
) -> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
platform::validate_candidate(app_root.as_ref())
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ fn contained_path(
|
||||
root: &AbsolutePathBuf,
|
||||
relative_path: &Path,
|
||||
kind: ResourceKind,
|
||||
) -> Result<AbsolutePathBuf, DesktopDistributionError> {
|
||||
) -> Result<AbsolutePathBuf, DesktopInstallationError> {
|
||||
if relative_path.as_os_str().is_empty()
|
||||
|| relative_path
|
||||
.components()
|
||||
@@ -162,7 +162,7 @@ fn contained_path(
|
||||
));
|
||||
}
|
||||
let metadata =
|
||||
fs::metadata(path.as_path()).map_err(|source| DesktopDistributionError::Filesystem {
|
||||
fs::metadata(path.as_path()).map_err(|source| DesktopInstallationError::Filesystem {
|
||||
stage: "resource metadata",
|
||||
source,
|
||||
})?;
|
||||
@@ -182,14 +182,14 @@ fn contained_path(
|
||||
fn canonical(
|
||||
path: &Path,
|
||||
stage: &'static str,
|
||||
) -> Result<AbsolutePathBuf, DesktopDistributionError> {
|
||||
) -> Result<AbsolutePathBuf, DesktopInstallationError> {
|
||||
AbsolutePathBuf::from_absolute_path_checked(path)
|
||||
.and_then(|path| path.canonicalize())
|
||||
.map_err(|source| DesktopDistributionError::Filesystem { stage, source })
|
||||
.map_err(|source| DesktopInstallationError::Filesystem { stage, source })
|
||||
}
|
||||
|
||||
fn containment(message: impl Into<String>) -> DesktopDistributionError {
|
||||
DesktopDistributionError::Containment(message.into())
|
||||
fn containment(message: impl Into<String>) -> DesktopInstallationError {
|
||||
DesktopInstallationError::Containment(message.into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
+7
-7
@@ -1,10 +1,10 @@
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs;
|
||||
|
||||
use super::DesktopDistributionError;
|
||||
use super::DesktopInstallationError;
|
||||
use super::DesktopResources;
|
||||
#[cfg(unix)]
|
||||
use super::InstalledDesktop;
|
||||
use super::VerifiedDesktopInstallation;
|
||||
use super::canonical;
|
||||
|
||||
#[test]
|
||||
@@ -41,12 +41,12 @@ fn rejects_non_normal_and_wrong_kind_paths() {
|
||||
for path in ["", ".", "../resources/plugins", "/tmp"] {
|
||||
assert!(matches!(
|
||||
resources.contained_directory(path),
|
||||
Err(DesktopDistributionError::Containment(_))
|
||||
Err(DesktopInstallationError::Containment(_))
|
||||
));
|
||||
}
|
||||
assert!(matches!(
|
||||
resources.contained_file("plugins"),
|
||||
Err(DesktopDistributionError::Containment(_))
|
||||
Err(DesktopInstallationError::Containment(_))
|
||||
));
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ fn rejects_symlink_traversal() {
|
||||
|
||||
assert!(matches!(
|
||||
resources.contained_file("plugins/hook.json"),
|
||||
Err(DesktopDistributionError::Containment(_))
|
||||
Err(DesktopInstallationError::Containment(_))
|
||||
));
|
||||
|
||||
let app_root = temp.path().join("Codex.app");
|
||||
@@ -75,7 +75,7 @@ fn rejects_symlink_traversal() {
|
||||
.expect("create app contents");
|
||||
symlink(&outside, &resources_link).expect("create resources symlink");
|
||||
assert!(matches!(
|
||||
InstalledDesktop::from_paths(app_root, resources_link),
|
||||
Err(DesktopDistributionError::Containment(_))
|
||||
VerifiedDesktopInstallation::from_paths(app_root, resources_link),
|
||||
Err(DesktopInstallationError::Containment(_))
|
||||
));
|
||||
}
|
||||
+9
-8
@@ -2,19 +2,19 @@ use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::DesktopDistributionError;
|
||||
use crate::InstalledDesktop;
|
||||
use crate::DesktopInstallationError;
|
||||
use crate::VerifiedDesktopInstallation;
|
||||
|
||||
const BUNDLE_IDENTIFIER: &str = "com.openai.codex";
|
||||
const TEAM_IDENTIFIER: &str = "2DC432GLL2";
|
||||
|
||||
/// Asks LaunchServices for the signed stable Codex app, independent of name or location.
|
||||
pub(crate) fn discover() -> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
pub(crate) fn discover() -> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
let script = format!(r#"POSIX path of (path to application id "{BUNDLE_IDENTIFIER}")"#);
|
||||
let output = Command::new("/usr/bin/osascript")
|
||||
.args(["-e", &script])
|
||||
.output()
|
||||
.map_err(|error| DesktopDistributionError::Discovery(error.to_string()))?;
|
||||
.map_err(|error| DesktopInstallationError::Discovery(error.to_string()))?;
|
||||
if !output.status.success() {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -24,18 +24,19 @@ pub(crate) fn discover() -> Result<Option<InstalledDesktop>, DesktopDistribution
|
||||
|
||||
pub(crate) fn validate_candidate(
|
||||
app_root: &Path,
|
||||
) -> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
) -> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
let resources_root = app_root.join("Contents/Resources");
|
||||
if app_root.extension().is_some_and(|value| value == "app")
|
||||
&& resources_root.is_dir()
|
||||
&& has_openai_signature(app_root)?
|
||||
{
|
||||
return InstalledDesktop::from_paths(app_root.to_path_buf(), resources_root).map(Some);
|
||||
return VerifiedDesktopInstallation::from_paths(app_root.to_path_buf(), resources_root)
|
||||
.map(Some);
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn has_openai_signature(app_root: &std::path::Path) -> Result<bool, DesktopDistributionError> {
|
||||
fn has_openai_signature(app_root: &std::path::Path) -> Result<bool, DesktopInstallationError> {
|
||||
let requirement = format!(
|
||||
r#"=identifier "{BUNDLE_IDENTIFIER}" and anchor apple generic and certificate leaf[subject.OU] = "{TEAM_IDENTIFIER}""#
|
||||
);
|
||||
@@ -43,6 +44,6 @@ fn has_openai_signature(app_root: &std::path::Path) -> Result<bool, DesktopDistr
|
||||
.args(["--verify", "--strict", "-R", &requirement])
|
||||
.arg(app_root)
|
||||
.status()
|
||||
.map_err(|error| DesktopDistributionError::Discovery(error.to_string()))?;
|
||||
.map_err(|error| DesktopInstallationError::Discovery(error.to_string()))?;
|
||||
Ok(verification.success())
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
use crate::DesktopInstallationError;
|
||||
use crate::VerifiedDesktopInstallation;
|
||||
|
||||
pub(crate) fn discover() -> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
Ok(None)
|
||||
}
|
||||
+5
-5
@@ -1,13 +1,13 @@
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
use crate::DesktopDistributionError;
|
||||
use crate::InstalledDesktop;
|
||||
use crate::DesktopInstallationError;
|
||||
use crate::VerifiedDesktopInstallation;
|
||||
|
||||
const STORE_PUBLISHER_ID: &str = "2p2nqsd0c76g0";
|
||||
|
||||
/// Queries the signed stable MSIX identity and uses the package location as the app root.
|
||||
pub(crate) fn discover() -> Result<Option<InstalledDesktop>, DesktopDistributionError> {
|
||||
pub(crate) fn discover() -> Result<Option<VerifiedDesktopInstallation>, DesktopInstallationError> {
|
||||
let script = format!(
|
||||
r#"
|
||||
$location = Get-AppxPackage -Name 'OpenAI.Codex' -ErrorAction SilentlyContinue |
|
||||
@@ -22,7 +22,7 @@ if ($location) {{ $location }}
|
||||
.arg("-Command")
|
||||
.arg(script)
|
||||
.output()
|
||||
.map_err(|error| DesktopDistributionError::Discovery(error.to_string()))?;
|
||||
.map_err(|error| DesktopInstallationError::Discovery(error.to_string()))?;
|
||||
if !output.status.success() {
|
||||
return Ok(None);
|
||||
}
|
||||
@@ -32,5 +32,5 @@ if ($location) {{ $location }}
|
||||
}
|
||||
let app_root = PathBuf::from(install_location);
|
||||
let resources_root = app_root.join("app/resources");
|
||||
InstalledDesktop::from_paths(app_root, resources_root).map(Some)
|
||||
VerifiedDesktopInstallation::from_paths(app_root, resources_root).map(Some)
|
||||
}
|
||||
Reference in New Issue
Block a user