#!/usr/bin/env bash set -euo pipefail readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ $# -ne 3 ]]; then echo "usage: $0 SOURCE_GIT_DIR NEW_WORK_DIR NODE_IMAGE_AT_SHA256" >&2 exit 2 fi source_git=$(cd "$1" && pwd) work_parent=$(cd "$(dirname "$2")" && pwd) work_dir="$work_parent/$(basename "$2")" node_image=$3 [[ "$node_image" == *@sha256:* ]] || { echo "NODE_IMAGE_AT_SHA256 must be an immutable digest reference" >&2 exit 2 } [[ ! -e "$work_dir" ]] || { echo "refusing to overwrite existing work directory: $work_dir" >&2 exit 2 } command -v podman >/dev/null || { echo "podman is required" >&2 exit 127 } mkdir -p "$work_dir" "$SCRIPT_DIR/prepare-source.sh" "$source_git" "$work_dir/source" common=( --rm --pull=never --cpus=2 --memory=2g --memory-swap=2g --pids-limit=512 --cap-drop=all --security-opt=no-new-privileges --read-only --tmpfs=/tmp:rw,nosuid,nodev,size=256m --tmpfs=/run:rw,nosuid,nodev,size=16m --env=HOME=/tmp/npm-home --env=npm_config_cache=/tmp/npm-cache --env=npm_config_audit=false --env=npm_config_fund=false --volume="$work_dir/source:/src:rw,Z" --workdir=/src/server ) # Dependency installation may execute package lifecycle scripts, so it occurs # only inside this disposable, secret-free container. No home, credentials, # engine socket, service bus, wallet, app data, or host network is mounted. timeout --signal=TERM --kill-after=15s 10m \ podman run "${common[@]}" \ --network=slirp4netns:allow_host_loopback=false \ "$node_image" npm ci # The source gate itself has no network. The work directory is intentionally # retained so the parent can preserve exact logs and inspect package-lock state. timeout --signal=TERM --kill-after=15s 10m \ podman run "${common[@]}" \ --network=none \ "$node_image" sh -c 'npm run build && npm test' printf 'Podsteadr source gate passed for tree %s with image %s\n' \ "$(sed -n '1p' "$work_dir/source/.archipelago-patched-tree")" "$node_image"