use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::path::PathBuf;
use std::time::Duration;
const ONE_MB: usize = 1_048_576;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ExecutionLanguage {
Rust,
JavaScript,
Wasm,
Python,
Command,
}
impl std::fmt::Display for ExecutionLanguage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Rust => write!(f, "Rust"),
Self::JavaScript => write!(f, "JavaScript"),
Self::Wasm => write!(f, "Wasm"),
Self::Python => write!(f, "Python"),
Self::Command => write!(f, "Command"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GuestModuleFormat {
Wasm,
}
#[derive(Debug, Clone)]
pub enum ExecutionPayload {
Source {
code: String,
},
GuestModule {
format: GuestModuleFormat,
bytes: Vec<u8>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ExecutionIsolation {
InProcess,
HostLocal,
ContainerEphemeral,
ContainerPersistent,
ProviderHosted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NetworkPolicy {
Disabled,
Enabled,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum FilesystemPolicy {
None,
WorkspaceReadOnly {
root: PathBuf,
},
WorkspaceReadWrite {
root: PathBuf,
},
Paths {
read_only: Vec<PathBuf>,
read_write: Vec<PathBuf>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EnvironmentPolicy {
None,
AllowList(Vec<String>),
}
#[derive(Debug, Clone)]
pub struct SandboxPolicy {
pub network: NetworkPolicy,
pub filesystem: FilesystemPolicy,
pub environment: EnvironmentPolicy,
pub timeout: Duration,
pub max_stdout_bytes: usize,
pub max_stderr_bytes: usize,
pub working_directory: Option<PathBuf>,
}
impl SandboxPolicy {
pub fn strict_rust() -> Self {
Self {
network: NetworkPolicy::Disabled,
filesystem: FilesystemPolicy::None,
environment: EnvironmentPolicy::None,
timeout: Duration::from_secs(30),
max_stdout_bytes: ONE_MB,
max_stderr_bytes: ONE_MB,
working_directory: None,
}
}
pub fn host_local() -> Self {
Self {
network: NetworkPolicy::Enabled,
filesystem: FilesystemPolicy::None,
environment: EnvironmentPolicy::None,
timeout: Duration::from_secs(30),
max_stdout_bytes: ONE_MB,
max_stderr_bytes: ONE_MB,
working_directory: None,
}
}
pub fn strict_js() -> Self {
Self {
network: NetworkPolicy::Disabled,
filesystem: FilesystemPolicy::None,
environment: EnvironmentPolicy::None,
timeout: Duration::from_secs(5),
max_stdout_bytes: ONE_MB,
max_stderr_bytes: ONE_MB,
working_directory: None,
}
}
}
impl Default for SandboxPolicy {
fn default() -> Self {
Self::strict_rust()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BackendCapabilities {
pub isolation: ExecutionIsolation,
pub enforce_network_policy: bool,
pub enforce_filesystem_policy: bool,
pub enforce_environment_policy: bool,
pub enforce_timeout: bool,
pub supports_structured_output: bool,
pub supports_process_execution: bool,
pub supports_persistent_workspace: bool,
pub supports_interactive_sessions: bool,
}
#[derive(Debug, Clone)]
pub struct ExecutionRequest {
pub language: ExecutionLanguage,
pub payload: ExecutionPayload,
pub argv: Vec<String>,
pub stdin: Option<Vec<u8>>,
pub input: Option<Value>,
pub sandbox: SandboxPolicy,
pub identity: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ExecutionStatus {
Success,
Timeout,
CompileFailed,
Failed,
Rejected,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExecutionMetadata {
pub backend_name: String,
pub language: ExecutionLanguage,
pub isolation: ExecutionIsolation,
pub status: ExecutionStatus,
pub duration_ms: u64,
pub identity: Option<String>,
pub artifact_refs: Vec<ArtifactRef>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ArtifactRef {
pub key: String,
pub size_bytes: u64,
pub content_type: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExecutionResult {
pub status: ExecutionStatus,
pub stdout: String,
pub stderr: String,
pub output: Option<Value>,
pub exit_code: Option<i32>,
pub stdout_truncated: bool,
pub stderr_truncated: bool,
pub duration_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<ExecutionMetadata>,
}