Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 14x 3x 3x 3x 3x | import { realpathSync } from "node:fs";
/**
* Docker Command Builder
*
* Handles the construction of secure Docker run commands with all necessary
* security constraints and resource limits for Arduino sketch execution.
*/
interface DockerRunOptions {
sketchDir: string;
memoryMB: number;
cpuLimit: string;
pidsLimit: number;
imageName: string;
command: string[];
containerName?: string;
/** Host path for the Arduino compiler cache. When set, the directory is
* bind-mounted into the container at the same path and ARDUINO_CACHE_DIR
* is forwarded as an environment variable so the compiler inside the
* container writes artefacts to the persisted host location. */
arduinoCacheDir?: string;
}
export class DockerCommandBuilder {
/**
* Builds a secure Docker run command with all security constraints
*
* @param options - Docker run configuration
* @returns Array of command arguments for spawn
*/
static buildSecureRunCommand(options: DockerRunOptions): string[] {
// Resolve symlinks so Docker Desktop on macOS gets the real path (e.g. /private/tmp not /tmp)
let realSketchDir = options.sketchDir;
try { realSketchDir = realpathSync(options.sketchDir); } catch { /* keep original */ }
return [
"run",
"--rm", // Remove container after exit
...(options.containerName ? ["--name", options.containerName] : []),
"-i", // Interactive mode for stdin
"--network",
"none", // No network access
"--memory",
`${options.memoryMB}m`, // Memory limit
"--memory-swap",
`${options.memoryMB}m`, // Disable swap
"--cpus",
options.cpuLimit, // CPU limit (e.g., "0.5" for 50%)
"--pids-limit",
String(options.pidsLimit), // Limit number of processes
"--security-opt",
"no-new-privileges", // Prevent privilege escalation
"--cap-drop",
"ALL", // Drop all Linux capabilities
"-v",
`${realSketchDir}:/sandbox:rw`, // Mount sketch directory (realpath resolves macOS /tmp symlink)
// Cache volume: only added when a host cache dir is configured
...(options.arduinoCacheDir
? [
"-v",
`${options.arduinoCacheDir}:${options.arduinoCacheDir}`,
"-e",
`ARDUINO_CACHE_DIR=${options.arduinoCacheDir}`,
]
: []),
options.imageName,
...options.command, // Execution command
];
}
/**
* Builds the compile and run command for Docker
*/
static buildCompileAndRunCommand(): string[] {
return [
"sh",
"-c",
// The echo marker ensures that a successful silent compilation (no
// warnings, no output) still triggers an onStdout event so that
// isCompilePhase is reset before the sketch starts writing to stderr.
// Without this, isCompilePhase would stay true and all runtime stderr
// (SERIAL_EVENT, IO_REGISTRY, …) would accumulate in compileErrorBuffer,
// causing a spurious 'compilation_error' message on process exit.
"g++ /sandbox/sketch.cpp -o /tmp/sketch -pthread 2>&1 && echo '[[RUNTIME_START]]' && /tmp/sketch",
];
}
}
|