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
7 changes: 7 additions & 0 deletions .github/dotslash-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
"linux-x86_64": { "regex": "^codex-cli-x86_64-unknown-linux-musl\\.zst$", "path": "codex-cli" },
"linux-aarch64": { "regex": "^codex-cli-aarch64-unknown-linux-gnu\\.zst$", "path": "codex-cli" }
}
},

"codex-linux-sandbox": {
"platforms": {
"linux-x86_64": { "regex": "^codex-linux-sandbox-x86_64-unknown-linux-musl\\.zst$", "path": "codex-linux-sandbox" },
"linux-aarch64": { "regex": "^codex-linux-sandbox-aarch64-unknown-linux-gnu\\.zst$", "path": "codex-linux-sandbox" }
}
}
}
}
9 changes: 9 additions & 0 deletions .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ jobs:
cp target/${{ matrix.target }}/release/codex-exec "$dest/codex-exec-${{ matrix.target }}"
cp target/${{ matrix.target }}/release/codex-cli "$dest/codex-cli-${{ matrix.target }}"

- if: ${{ matrix.target == 'x86_64-unknown-linux-musl' }} || ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
name: Stage Linux-only artifacts
shell: bash
run: |
cp target/${{ matrix.target }}/release/codex-linux-sandbox "$dest/codex-linux-sandbox-${{ matrix.target }}"

- name: Compress artifacts
shell: bash
run: |
zstd -T0 -19 --rm "$dest"/*

- uses: actions/upload-artifact@v4
Expand Down
5 changes: 4 additions & 1 deletion codex-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ members = [
version = "0.1.0"

[profile.release]
lto = "fat"
lto = "fat"
# Because we bundle some of these executables with the TypeScript CLI, we
# remove everything to make the binary as small as possible.
strip = "symbols"
8 changes: 8 additions & 0 deletions codex-rs/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ edition = "2021"
name = "codex"
path = "src/main.rs"

[[bin]]
name = "codex-linux-sandbox"
path = "src/linux-sandbox/main.rs"

[lib]
name = "codex_cli"
path = "src/lib.rs"

[dependencies]
anyhow = "1"
clap = { version = "4", features = ["derive"] }
Expand Down
5 changes: 1 addition & 4 deletions codex-rs/cli/src/landlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use std::process::ExitStatus;

/// Execute `command` in a Linux sandbox (Landlock + seccomp) the way Codex
/// would.
pub(crate) fn run_landlock(
command: Vec<String>,
sandbox_policy: SandboxPolicy,
) -> anyhow::Result<()> {
pub fn run_landlock(command: Vec<String>, sandbox_policy: SandboxPolicy) -> anyhow::Result<()> {
if command.is_empty() {
anyhow::bail!("command args are empty");
}
Expand Down
47 changes: 47 additions & 0 deletions codex-rs/cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#[cfg(target_os = "linux")]
pub mod landlock;
pub mod proto;
pub mod seatbelt;

use clap::Parser;
use codex_core::protocol::SandboxPolicy;
use codex_core::SandboxPermissionOption;

#[derive(Debug, Parser)]
pub struct SeatbeltCommand {
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
#[arg(long = "full-auto", default_value_t = false)]
pub full_auto: bool,

#[clap(flatten)]
pub sandbox: SandboxPermissionOption,

/// Full command args to run under seatbelt.
#[arg(trailing_var_arg = true)]
pub command: Vec<String>,
}

#[derive(Debug, Parser)]
pub struct LandlockCommand {
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
#[arg(long = "full-auto", default_value_t = false)]
pub full_auto: bool,

#[clap(flatten)]
pub sandbox: SandboxPermissionOption,

/// Full command args to run under landlock.
#[arg(trailing_var_arg = true)]
pub command: Vec<String>,
}

pub fn create_sandbox_policy(full_auto: bool, sandbox: SandboxPermissionOption) -> SandboxPolicy {
if full_auto {
SandboxPolicy::new_full_auto_policy()
} else {
match sandbox.permissions.map(Into::into) {
Some(sandbox_policy) => sandbox_policy,
None => SandboxPolicy::new_read_only_policy(),
}
}
}
22 changes: 22 additions & 0 deletions codex-rs/cli/src/linux-sandbox/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#[cfg(not(target_os = "linux"))]
fn main() -> anyhow::Result<()> {
eprintln!("codex-linux-sandbox is not supported on this platform.");
std::process::exit(1);
}

#[cfg(target_os = "linux")]
fn main() -> anyhow::Result<()> {
use clap::Parser;
use codex_cli::create_sandbox_policy;
use codex_cli::landlock;
use codex_cli::LandlockCommand;

let LandlockCommand {
full_auto,
sandbox,
command,
} = LandlockCommand::parse();
let sandbox_policy = create_sandbox_policy(full_auto, sandbox);
landlock::run_landlock(command, sandbox_policy)?;
Ok(())
}
53 changes: 6 additions & 47 deletions codex-rs/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
#[cfg(target_os = "linux")]
mod landlock;
mod proto;
mod seatbelt;

use clap::Parser;
use codex_core::protocol::SandboxPolicy;
use codex_core::SandboxPermissionOption;
use codex_cli::create_sandbox_policy;
use codex_cli::proto;
use codex_cli::seatbelt;
use codex_cli::LandlockCommand;
use codex_cli::SeatbeltCommand;
use codex_exec::Cli as ExecCli;
use codex_repl::Cli as ReplCli;
use codex_tui::Cli as TuiCli;
Expand Down Expand Up @@ -63,34 +61,6 @@ enum DebugCommand {
Landlock(LandlockCommand),
}

#[derive(Debug, Parser)]
struct SeatbeltCommand {
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
#[arg(long = "full-auto", default_value_t = false)]
full_auto: bool,

#[clap(flatten)]
pub sandbox: SandboxPermissionOption,

/// Full command args to run under seatbelt.
#[arg(trailing_var_arg = true)]
command: Vec<String>,
}

#[derive(Debug, Parser)]
struct LandlockCommand {
/// Convenience alias for low-friction sandboxed automatic execution (network-disabled sandbox that can write to cwd and TMPDIR)
#[arg(long = "full-auto", default_value_t = false)]
full_auto: bool,

#[clap(flatten)]
sandbox: SandboxPermissionOption,

/// Full command args to run under landlock.
#[arg(trailing_var_arg = true)]
command: Vec<String>,
}

#[derive(Debug, Parser)]
struct ReplProto {}

Expand Down Expand Up @@ -127,7 +97,7 @@ async fn main() -> anyhow::Result<()> {
full_auto,
}) => {
let sandbox_policy = create_sandbox_policy(full_auto, sandbox);
landlock::run_landlock(command, sandbox_policy)?;
codex_cli::landlock::run_landlock(command, sandbox_policy)?;
}
#[cfg(not(target_os = "linux"))]
DebugCommand::Landlock(_) => {
Expand All @@ -138,14 +108,3 @@ async fn main() -> anyhow::Result<()> {

Ok(())
}

fn create_sandbox_policy(full_auto: bool, sandbox: SandboxPermissionOption) -> SandboxPolicy {
if full_auto {
SandboxPolicy::new_full_auto_policy()
} else {
match sandbox.permissions.map(Into::into) {
Some(sandbox_policy) => sandbox_policy,
None => SandboxPolicy::new_read_only_policy(),
}
}
}
2 changes: 1 addition & 1 deletion codex-rs/cli/src/seatbelt.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use codex_core::exec::create_seatbelt_command;
use codex_core::protocol::SandboxPolicy;

pub(crate) async fn run_seatbelt(
pub async fn run_seatbelt(
command: Vec<String>,
sandbox_policy: SandboxPolicy,
) -> anyhow::Result<()> {
Expand Down