102 lines
6.2 KiB
Bash
Executable File
102 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Offline fixture assets only. Separate bounded manager admission is required.
|
|
set -euo pipefail
|
|
[[ $# == 3 ]] || { echo 'usage: build-browser-runtime-offline.sh EMPTY_OUTPUT PINNED_BROWSER_IMAGE LOCKED_FRONTEND_DIRECTORY' >&2; exit 2; }
|
|
out=$(realpath -e "$1"); image=$2; deps=$(realpath -e "$3")
|
|
[[ "$image" =~ ^sha256:[0-9a-f]{64}$ && -d "$deps/node_modules" ]] || exit 2
|
|
[[ -d "$out" && -z $(find "$out" -mindepth 1 -maxdepth 1 -print -quit) ]] || exit 2
|
|
root=$(cd "$(dirname "$0")/../.." && pwd)
|
|
PYTHONOPTIMIZE=0 python3 - <<'PY'
|
|
from pathlib import Path
|
|
group = next(line.split(':', 2)[2] for line in Path('/proc/self/cgroup').read_text().splitlines() if line.startswith('0::'))
|
|
root = Path('/sys/fs/cgroup') / group.lstrip('/')
|
|
assert 0 < int((root / 'memory.max').read_text()) <= 1073741824
|
|
assert int((root / 'memory.swap.max').read_text()) == 0
|
|
assert 0 < int((root / 'pids.max').read_text()) <= 256
|
|
quota, period = (root / 'cpu.max').read_text().split()
|
|
assert 0 < int(quota) <= int(period)
|
|
PY
|
|
cmp "$root/neode-ui/package.json" "$deps/package.json"
|
|
cmp "$root/neode-ui/package-lock.json" "$deps/package-lock.json"
|
|
inputs=(neode-ui tests/cloud/browser/index.html tests/cloud/browser/main.js tests/cloud/browser/vite.config.mjs
|
|
tests/cloud/browser/drive.cjs tests/cloud/browser/pagination.cjs tests/cloud/browser/pagination-seed.test.cjs
|
|
tests/cloud/build-browser-runtime-offline.sh core/archipelago/src/api/handler/cloud_browser_tests.rs)
|
|
git -C "$root" diff --exit-code HEAD -- "${inputs[@]}" >/dev/null
|
|
[[ -z $(git -C "$root" ls-files --others --exclude-standard -- "${inputs[@]}") ]] || exit 2
|
|
commit=$(git -C "$root" rev-parse HEAD)
|
|
printf '%s\n' "$commit" > "$out/source.commit"
|
|
printf '%s\n' "$image" > "$out/base-image"
|
|
podman ps -aq --no-trunc | sort > "$out/containers.before"
|
|
cleanup() {
|
|
local status=$? file cid exists
|
|
# A parent stop may arrive during cleanup; finish only these bounded removals.
|
|
trap '' INT TERM
|
|
trap - EXIT
|
|
set +e
|
|
for file in "$out/ui.cid" "$out/image.cid"; do
|
|
[[ -s "$file" ]] || continue
|
|
cid=$(<"$file")
|
|
if [[ "$cid" =~ ^[a-f0-9]{64}$ ]]; then
|
|
timeout --kill-after=1s 6s podman rm -f "$cid" >> "$out/cleanup.log" 2>&1 || status=1
|
|
timeout 2s podman container exists "$cid"; exists=$?
|
|
[[ "$exists" == 1 ]] || status=1
|
|
else status=1; fi
|
|
done
|
|
timeout 3s podman ps -aq --no-trunc | sort > "$out/containers.after" || status=1
|
|
cmp "$out/containers.before" "$out/containers.after" || status=1
|
|
printf '%s\n' "$status" > "$out/outer.exit"
|
|
exit "$status"
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 143' TERM
|
|
trap 'exit 130' INT
|
|
mkdir -p "$out/source" "$out/input/fixture" "$out/ui-output"
|
|
# Export tracked bytes from the pinned commit, never copy a dirty source tree.
|
|
git -C "$root" archive "$commit" neode-ui/src \
|
|
neode-ui/{tailwind.config.js,postcss.config.js,package.json,package-lock.json} \
|
|
neode-ui/public/assets/fonts/Montserrat/{Montserrat-Bold,Montserrat-ExtraBold}.ttf \
|
|
neode-ui/public/assets/img/bg.jpg tests/cloud/browser/{index.html,main.js,vite.config.mjs,drive.cjs,pagination.cjs} \
|
|
| tar --no-same-owner --no-same-permissions -xf - -C "$out/source"
|
|
[[ -z $(find "$out/source" ! -type d ! -type f -print -quit) ]] || exit 2
|
|
snapshot="$out/source"
|
|
cp -R "$snapshot/neode-ui/src" "$out/input/"
|
|
cp "$snapshot/neode-ui/"{tailwind.config.js,postcss.config.js,package.json,package-lock.json} "$out/input/"
|
|
cp "$snapshot/tests/cloud/browser/"{index.html,main.js,vite.config.mjs} "$out/input/fixture/"
|
|
mkdir -p "$out/input/fixture/public/assets/fonts/Montserrat" "$out/input/fixture/public/assets/img"
|
|
cp "$snapshot/neode-ui/public/assets/fonts/Montserrat/"{Montserrat-Bold,Montserrat-ExtraBold}.ttf "$out/input/fixture/public/assets/fonts/Montserrat/"
|
|
cp "$snapshot/neode-ui/public/assets/img/bg.jpg" "$out/input/fixture/public/assets/img/"
|
|
(cd "$out/input" && find . -type f -print0 | sort -z | xargs -0 sha256sum) > "$out/input.sha256"
|
|
nonce="$(date +%s)-$$"
|
|
podman create --cidfile "$out/ui.cid" --name "archy-cloud-assets-$nonce" --pull=never \
|
|
--network=none --pid=private --ipc=private --http-proxy=false --no-hosts \
|
|
--read-only --cap-drop=all --security-opt=no-new-privileges --memory=1g --memory-swap=1g \
|
|
--cpus=1 --pids-limit=256 --timeout=90 --log-driver=none \
|
|
--tmpfs /tmp:rw,size=256m --tmpfs /work:rw,size=128m \
|
|
--env HOME=/tmp --env XDG_CONFIG_HOME=/tmp/config --env NODE_PATH=/browser/node_modules \
|
|
--volume "$out/input:/input:ro" --volume "$out/ui-output:/out:rw" --volume "$deps/node_modules:/deps/node_modules:ro" \
|
|
--workdir /work --entrypoint /bin/sh "$image" -ec '
|
|
cp -R /input/. /work/
|
|
mkdir node_modules
|
|
for dep in /deps/node_modules/*; do ln -s "$dep" node_modules/; done
|
|
node /deps/node_modules/vite/bin/vite.js build --config fixture/vite.config.mjs
|
|
cp -R dist /out/
|
|
' > "$out/ui-create.log" 2>&1
|
|
timeout --kill-after=10s 100s podman start --attach "$(<"$out/ui.cid")" > "$out/ui-build.log" 2>&1
|
|
[[ -f "$out/ui-output/dist/index.html" && -z $(find "$out/ui-output" ! -type d ! -type f -print -quit) ]] || exit 2
|
|
# Never start the image-assembly container or mutate the retained base image.
|
|
# Only its new private layer is writable for the host control-plane copy/commit.
|
|
podman create --cidfile "$out/image.cid" --name "archy-cloud-image-$nonce" --pull=never \
|
|
--network=none --pid=private --ipc=private --http-proxy=false --no-hosts \
|
|
--cap-drop=all --security-opt=no-new-privileges --memory=1g --memory-swap=1g \
|
|
--cpus=1 --pids-limit=64 --timeout=10 --entrypoint /bin/false "$image" > "$out/image-create.log" 2>&1
|
|
cid=$(<"$out/image.cid")
|
|
timeout --kill-after=2s 15s podman cp "$out/ui-output" "$cid:/cloud-pagination"
|
|
timeout --kill-after=2s 15s podman cp "$cid:/cloud-pagination/dist" "$out/copied-dist"
|
|
(cd "$out/ui-output/dist" && find . -type f -print0 | sort -z | xargs -0 sha256sum) > "$out/assets.sha256"
|
|
(cd "$out/copied-dist" && find . -type f -print0 | sort -z | xargs -0 sha256sum) > "$out/copied-assets.sha256"
|
|
cmp "$out/assets.sha256" "$out/copied-assets.sha256"
|
|
timeout --kill-after=10s 60s podman commit --pause=false \
|
|
--change 'ENTRYPOINT ["/bin/false"]' --change 'CMD []' \
|
|
--change 'LABEL archy.fixture=cloud-pagination-only' "$cid" > "$out/runtime-image"
|
|
sha256sum "$snapshot/tests/cloud/browser/"{drive.cjs,pagination.cjs} > "$out/drivers.sha256"
|