// SPDX-License-Identifier: GPL-2.0-or-later // Copyright (C) 2026 Bryan Joshua Pedini /** * Prerequisite checks shared by the setup projects. Every failure is a HarnessError('prerequisite') * with an actionable message, so a broken environment fails fast and is never mistaken for an * application failure. */ import fs from 'node:fs'; import { spawnSync } from 'node:child_process'; import { ALPINE_IMAGE } from '../harness/env'; import { HarnessError } from '../harness/errors'; export function sh(cmd: string, args: string[], timeoutMs = 60_000): { code: number | null; out: string; err: string } { const r = spawnSync(cmd, args, { encoding: 'utf8', timeout: timeoutMs }); if (r.error) return { code: null, out: '', err: r.error.message }; return { code: r.status, out: r.stdout ?? '', err: r.stderr ?? '' }; } export function requireTool(name: string, args: string[], hint: string): void { const r = sh(name, args, 20_000); if (r.code !== 0) throw new HarnessError('prerequisite', `${name} is required (${hint}): \`${name} ${args.join(' ')}\` failed: ${r.err.trim() || r.out.trim()}`); } export function requireDocker(): void { requireTool('docker', ['version', '--format', '{{.Server.Version}}'], 'Docker Engine reachable by the current user'); const r = sh('docker', ['image', 'inspect', '--format', '{{.Id}}', ALPINE_IMAGE]); if (r.code !== 0) throw new HarnessError('prerequisite', `test image ${ALPINE_IMAGE} is not present locally (docker pull ${ALPINE_IMAGE}): ${r.err.trim()}`); } export function requireCurl(): void { requireTool('curl', ['--version'], 'real curl client for the HTTP tests'); } /** Unprivileged user+mount namespaces with a bind mount over /var/run/docker.sock (fake/inaccessible Docker sockets). */ export function requireUnshare(): void { if (!fs.existsSync('/var/run/docker.sock')) throw new HarnessError('prerequisite', '/var/run/docker.sock must exist (bind-mount target for the fake Docker socket)'); const r = sh('unshare', ['-Urm', 'sh', '-c', 'mount --bind /etc/hostname /var/run/docker.sock && test -f /var/run/docker.sock && mount -t tmpfs none /run && test ! -e /var/run/docker.sock']); if (r.code !== 0) throw new HarnessError('prerequisite', `unprivileged user/mount namespaces are required (unshare -Urm + bind mount + tmpfs): ${r.err.trim()}`); }