#![forbid(unsafe_code)]
#[cfg(unix)]
use harness_codex::{
CodexAppServerClient, OwnedAppServerConfig, S08OwnedChildTurnReceipt, run_s08_owned_child_turn,
};
use std::env;
use std::path::{Component, PathBuf};
use std::process::ExitCode;
use std::time::Duration;
#[derive(Clone, Copy)]
enum Seam {
Cli,
Desktop,
}
struct Arguments {
app_server: PathBuf,
app_server_sha256: String,
correlation: String,
seam: Seam,
}
fn main() -> ExitCode {
#[cfg(unix)]
{
match run() {
Ok(()) => ExitCode::SUCCESS,
Err(()) => {
eprintln!("s08-owned-child-turn: refused");
ExitCode::from(2)
}
}
}
#[cfg(not(unix))]
{
eprintln!("s08-owned-child-turn: requires macOS or Linux");
ExitCode::from(2)
}
}
#[cfg(unix)]
fn run() -> Result<(), ()> {
let arguments = parse_arguments()?;
let configuration = match arguments.seam {
Seam::Cli => OwnedAppServerConfig::codex_pinned(
arguments.app_server,
&arguments.app_server_sha256,
Duration::from_secs(30),
Duration::from_secs(10),
),
Seam::Desktop => OwnedAppServerConfig::codex_desktop_pinned(
arguments.app_server,
&arguments.app_server_sha256,
Duration::from_secs(30),
Duration::from_secs(10),
),
}
.map_err(|_| ())?;
let mut client = CodexAppServerClient::spawn(&configuration).map_err(|_| ())?;
let receipt = run_s08_owned_child_turn(&mut client, &arguments.correlation).map_err(|_| ())?;
print_receipt(&receipt)
}
#[cfg(unix)]
fn print_receipt(receipt: &S08OwnedChildTurnReceipt) -> Result<(), ()> {
let output = serde_json::to_string(receipt).map_err(|_| ())?;
if output.len() > 4096 {
return Err(());
}
println!("{output}");
Ok(())
}
fn parse_arguments() -> Result<Arguments, ()> {
let mut app_server = None;
let mut app_server_sha256 = None;
let mut correlation = None;
let mut seam = None;
let mut arguments = env::args().skip(1);
while let Some(argument) = arguments.next() {
match argument.as_str() {
"--app-server" => app_server = Some(PathBuf::from(arguments.next().ok_or(())?)),
"--app-server-sha256" => app_server_sha256 = Some(arguments.next().ok_or(())?),
"--correlation" => correlation = Some(arguments.next().ok_or(())?),
"--seam" => {
seam = Some(match arguments.next().as_deref() {
Some("cli") => Seam::Cli,
Some("desktop") => Seam::Desktop,
_ => return Err(()),
});
}
_ => return Err(()),
}
}
let app_server = app_server.ok_or(())?;
if !app_server.is_absolute()
|| app_server
.components()
.any(|component| component == Component::ParentDir)
{
return Err(());
}
let app_server_sha256 = app_server_sha256.ok_or(())?;
if !valid_sha256(&app_server_sha256) {
return Err(());
}
Ok(Arguments {
app_server,
app_server_sha256,
correlation: correlation.ok_or(())?,
seam: seam.ok_or(())?,
})
}
fn valid_sha256(value: &str) -> bool {
value.len() == 64
&& value
.bytes()
.all(|byte| byte.is_ascii_digit() || matches!(byte, b'a'..=b'f'))
}