cageforge_backend_api/
execution.rs1use std::{
6 error::Error,
7 io::{Read, Write},
8 process::ExitStatus,
9};
10
11use cageforge_policy::PathResolutionContext;
12
13use crate::{BackendRequest, PreparedBackendRequest, SandboxBackend};
14
15pub trait DynSandbox: SandboxBackend + Send + Sync {
26 fn launch(
31 &self,
32 request: BackendRequest<'_>,
33 context: &PathResolutionContext,
34 ) -> Result<Box<dyn SandboxChild<Error = SandboxExecutionError> + Send>, SandboxExecutionError>;
35}
36
37#[derive(Debug, thiserror::Error)]
43#[non_exhaustive]
44pub enum SandboxExecutionError {
45 #[error("sandbox preparation failed: {source}")]
47 Prepare {
48 source: Box<dyn Error + Send + Sync>,
50 },
51 #[error("sandbox launch failed: {source}")]
53 Spawn {
54 source: Box<dyn Error + Send + Sync>,
56 },
57 #[error("sandbox status check failed: {source}")]
59 TryWait {
60 source: Box<dyn Error + Send + Sync>,
62 },
63 #[error("sandbox wait failed: {source}")]
65 Wait {
66 source: Box<dyn Error + Send + Sync>,
68 },
69 #[error("sandbox termination failed: {source}")]
71 Kill {
72 source: Box<dyn Error + Send + Sync>,
74 },
75}
76
77struct ErasedChild<C> {
78 child: C,
79}
80
81pub trait Sandbox: SandboxBackend {
84 type Child: SandboxChild<Error = Self::Error>;
86
87 type Error: std::error::Error + 'static;
89
90 fn prepare<'a>(
92 &self,
93 request: BackendRequest<'a>,
94 context: &PathResolutionContext,
95 ) -> Result<PreparedBackendRequest<'a, Self>, Self::Error>
96 where
97 Self: Sized;
98
99 fn spawn<'a>(
101 &self,
102 prepared: PreparedBackendRequest<'a, Self>,
103 ) -> Result<Self::Child, Self::Error>
104 where
105 Self: Sized;
106}
107
108pub trait SandboxChild {
110 fn id(&self) -> u32;
112
113 fn stdin(&mut self) -> Option<&mut dyn Write>;
115
116 fn stdout(&mut self) -> Option<&mut dyn Read>;
118
119 fn stderr(&mut self) -> Option<&mut dyn Read>;
121
122 fn take_stdin(&mut self) -> Option<Box<dyn Write + Send>> {
129 None
130 }
131
132 fn take_stdout(&mut self) -> Option<Box<dyn Read + Send>> {
134 None
135 }
136
137 fn take_stderr(&mut self) -> Option<Box<dyn Read + Send>> {
139 None
140 }
141
142 type Error: std::error::Error + 'static;
144
145 fn try_wait(&mut self) -> Result<Option<ExitStatus>, Self::Error>;
147
148 fn wait(&mut self) -> Result<ExitStatus, Self::Error>;
150
151 fn kill(&mut self) -> Result<(), Self::Error>;
153}
154
155impl<B> DynSandbox for B
156where
157 B: Sandbox + Send + Sync,
158 B::Child: Send + 'static,
159 B::Error: Send + Sync,
160{
161 fn launch(
162 &self,
163 request: BackendRequest<'_>,
164 context: &PathResolutionContext,
165 ) -> Result<Box<dyn SandboxChild<Error = SandboxExecutionError> + Send>, SandboxExecutionError>
166 {
167 let prepared =
168 self.prepare(request, context)
169 .map_err(|source| SandboxExecutionError::Prepare {
170 source: Box::new(source),
171 })?;
172 let child = self
173 .spawn(prepared)
174 .map_err(|source| SandboxExecutionError::Spawn {
175 source: Box::new(source),
176 })?;
177 Ok(Box::new(ErasedChild { child }))
178 }
179}
180
181impl<C> SandboxChild for ErasedChild<C>
182where
183 C: SandboxChild,
184 C::Error: Send + Sync,
185{
186 type Error = SandboxExecutionError;
187
188 fn id(&self) -> u32 {
189 self.child.id()
190 }
191
192 fn stdin(&mut self) -> Option<&mut dyn Write> {
193 self.child.stdin()
194 }
195
196 fn stdout(&mut self) -> Option<&mut dyn Read> {
197 self.child.stdout()
198 }
199
200 fn stderr(&mut self) -> Option<&mut dyn Read> {
201 self.child.stderr()
202 }
203
204 fn take_stdin(&mut self) -> Option<Box<dyn Write + Send>> {
205 self.child.take_stdin()
206 }
207
208 fn take_stdout(&mut self) -> Option<Box<dyn Read + Send>> {
209 self.child.take_stdout()
210 }
211
212 fn take_stderr(&mut self) -> Option<Box<dyn Read + Send>> {
213 self.child.take_stderr()
214 }
215
216 fn try_wait(&mut self) -> Result<Option<ExitStatus>, Self::Error> {
217 self.child
218 .try_wait()
219 .map_err(|source| SandboxExecutionError::TryWait {
220 source: Box::new(source),
221 })
222 }
223
224 fn wait(&mut self) -> Result<ExitStatus, Self::Error> {
225 self.child
226 .wait()
227 .map_err(|source| SandboxExecutionError::Wait {
228 source: Box::new(source),
229 })
230 }
231
232 fn kill(&mut self) -> Result<(), Self::Error> {
233 self.child
234 .kill()
235 .map_err(|source| SandboxExecutionError::Kill {
236 source: Box::new(source),
237 })
238 }
239}