rohitg00--ai-engineering-from-scratch
79 行
4.2 KiB
JSON
79 行
4.2 KiB
JSON
{
|
|
"lesson": "phase-19/26-sandbox-runner-denylist",
|
|
"title": "Sandbox Runner with Denylist and Path Jail",
|
|
"questions": [
|
|
{
|
|
"stage": "pre",
|
|
"question": "Before reading the lesson: what is the strongest reason a sandbox checks argv shapes for interpreter invocations like python3 -c?",
|
|
"options": [
|
|
"Interpreters are slow and waste agent budget.",
|
|
"An interpreter with -c is a shell call by another name and bypasses the executable denylist.",
|
|
"Interpreters cannot be safely sandboxed at all.",
|
|
"The model writes better code without them."
|
|
],
|
|
"correct": 1,
|
|
"explanation": "python3 -c, bash -c, node -e, and friends are functionally identical to giving the model a shell. Blocking the executable name is not enough."
|
|
},
|
|
{
|
|
"stage": "check",
|
|
"question": "The sandbox is configured with project_root=/work. A path argument arrives as ./src/main.py. How is the jail check performed?",
|
|
"options": [
|
|
"Literal string prefix match against /work.",
|
|
"os.path.realpath of the joined absolute path is checked for a /work prefix.",
|
|
"The sandbox refuses every relative path.",
|
|
"The sandbox spawns the subprocess and checks the working directory after the fact."
|
|
],
|
|
"correct": 1,
|
|
"explanation": "realpath resolves symlinks. A literal prefix check is bypassed by a symlink inside the project root pointing outside. realpath plus prefix-or-equal is the safe check."
|
|
},
|
|
{
|
|
"stage": "check",
|
|
"question": "A SandboxResult comes back with denied=True, timed_out=False, exit_code=-100. What is the canonical interpretation?",
|
|
"options": [
|
|
"The subprocess started and was killed by SIGKILL.",
|
|
"The sandbox never spawned the subprocess; the call was refused before exec.",
|
|
"The subprocess returned -100 explicitly.",
|
|
"The wall-clock timeout fired."
|
|
],
|
|
"correct": 1,
|
|
"explanation": "The sentinel exit_code -100 paired with denied=True means the sandbox short-circuited before subprocess.run was called."
|
|
},
|
|
{
|
|
"stage": "check",
|
|
"question": "Why does the sandbox prefer shell=False by default and refuse shell metacharacters?",
|
|
"options": [
|
|
"shell=True is slower in CPython.",
|
|
"Shell parsing exposes the entire shell DSL to the model, which is the surface the sandbox is trying to shrink.",
|
|
"subprocess does not accept shell=True on macOS.",
|
|
"It makes the test suite simpler."
|
|
],
|
|
"correct": 1,
|
|
"explanation": "shell=True turns argv into a shell-interpreted string. Pipes, redirects, command substitution, and globbing all become available. The sandbox cannot meaningfully refuse a payload once shell parsing runs."
|
|
},
|
|
{
|
|
"stage": "post",
|
|
"question": "You want to add a per-process memory limit to the sandbox. The lesson's sandbox does not implement this. What is the correct next step?",
|
|
"options": [
|
|
"Use os.setrlimit(RLIMIT_AS) in a preexec_fn passed to subprocess.run.",
|
|
"Add the limit to the denylist as a string.",
|
|
"Increase the wall-clock timeout to compensate.",
|
|
"Skip it: a denylist is sufficient for memory bombs."
|
|
],
|
|
"correct": 0,
|
|
"explanation": "subprocess.run accepts preexec_fn (POSIX) or a similar mechanism. setrlimit(RLIMIT_AS) caps the address space of the child. The sandbox in this lesson does not ship this; lesson 29's end-to-end demo discusses how to layer container-level limits on top."
|
|
},
|
|
{
|
|
"stage": "post",
|
|
"question": "The model invokes the sandbox with argv=['cat', 'src/../src/main.py']. The file exists under project_root. Should the call pass the path jail?",
|
|
"options": [
|
|
"No, any .. in a path is an automatic refusal.",
|
|
"Yes: realpath collapses src/../src to src and the resolved path is inside project_root.",
|
|
"No: argv is rejected by the regex gate before the sandbox sees it.",
|
|
"It depends on whether the user is root."
|
|
],
|
|
"correct": 1,
|
|
"explanation": "realpath normalises the path. The sandbox does not blanket-refuse .. tokens; it checks the resolved target. This is intentional: legitimate paths sometimes go through .. legitimately."
|
|
}
|
|
]
|
|
}
|