1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Error types for the Forge sandbox.
use thiserror::Error;
/// Errors that can occur during sandbox execution.
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum SandboxError {
/// Code failed validation checks.
#[error("code validation failed: {reason}")]
ValidationFailed {
/// What went wrong.
reason: String,
},
/// Code exceeds the configured maximum size.
#[error("code exceeds maximum size of {max} bytes (got {actual})")]
CodeTooLarge {
/// Maximum allowed size.
max: usize,
/// Actual size.
actual: usize,
},
/// Execution result exceeds the configured maximum size.
#[error("output exceeds maximum size of {max} bytes")]
OutputTooLarge {
/// Maximum allowed size.
max: usize,
},
/// Execution timed out (async event loop or CPU-bound watchdog).
#[error("execution timed out after {timeout_ms}ms")]
Timeout {
/// Configured timeout in milliseconds.
timeout_ms: u64,
},
/// A banned code pattern was detected during validation.
#[error("banned pattern detected: `{pattern}` — the sandbox has no filesystem, network, or module access. Use forge.callTool() or forge.server() to interact with external services.")]
BannedPattern {
/// The pattern that was matched.
pattern: String,
},
/// Generic execution failure.
#[error("sandbox execution failed: {0}")]
Execution(#[from] anyhow::Error),
/// A JavaScript error was thrown during execution.
#[error("javascript error: {message}")]
JsError {
/// The error message from JavaScript.
message: String,
},
/// Result serialization failed.
#[error("result serialization failed: {0}")]
Serialization(#[from] serde_json::Error),
/// Too many concurrent sandbox executions.
#[error("concurrency limit reached (max {max} concurrent executions)")]
ConcurrencyLimit {
/// Maximum allowed concurrent executions.
max: usize,
},
/// Too many tool calls in a single execution.
#[error("tool call limit exceeded (max {max} calls per execution)")]
ToolCallLimit {
/// Maximum allowed tool calls.
max: usize,
},
/// Tool call arguments exceed the configured maximum size.
#[error("tool call arguments too large (max {max} bytes, got {actual})")]
ToolCallArgsTooLarge {
/// Maximum allowed argument size.
max: usize,
/// Actual argument size.
actual: usize,
},
/// V8 heap memory limit was exceeded.
#[error("V8 heap limit exceeded")]
HeapLimitExceeded,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::executor::ExecutionMode;
use crate::ipc::ErrorKind;
/// Compile-time guard: all sandbox public enums are #[non_exhaustive].
/// The wildcard arm documents that downstream crates must handle future variants.
#[test]
#[allow(unreachable_patterns)]
fn ne_sandbox_enums_are_non_exhaustive() {
let err = SandboxError::HeapLimitExceeded;
match err {
SandboxError::HeapLimitExceeded
| SandboxError::Timeout { .. }
| SandboxError::ValidationFailed { .. } => {}
_ => {}
}
let mode = ExecutionMode::InProcess;
match mode {
ExecutionMode::InProcess | ExecutionMode::ChildProcess => {}
_ => {}
}
let kind = ErrorKind::Timeout;
match kind {
ErrorKind::Timeout | ErrorKind::HeapLimit | ErrorKind::JsError => {}
_ => {}
}
}
}