summaryrefslogtreecommitdiff
path: root/infra/guix/test-bootstrap.sh
diff options
context:
space:
mode:
authorDoan Luu Duc Tai <doan@luuduct.ai>2026-11-01 07:13:45 -0600
committerDoan Luu Duc Tai <doan@luuduct.ai>2026-11-01 07:13:45 -0600
commit9349a2de648e241da8e00ba7ae25cb2a877ff3e9 (patch)
tree2fea913ee0aaff4370877f4a91c911db2fe37592 /infra/guix/test-bootstrap.sh
parent5b89c370d5974f057306a52089f14c337565fd1d (diff)
feat(guix): carry prebuilt runtime and recover preserved state
Diffstat (limited to 'infra/guix/test-bootstrap.sh')
-rw-r--r--infra/guix/test-bootstrap.sh118
1 files changed, 118 insertions, 0 deletions
diff --git a/infra/guix/test-bootstrap.sh b/infra/guix/test-bootstrap.sh
new file mode 100644
index 0000000..470ebeb
--- /dev/null
+++ b/infra/guix/test-bootstrap.sh
@@ -0,0 +1,118 @@
+#!/bin/sh
+# Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -eu
+umask 077
+ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/../.." && pwd)
+command -v bwrap >/dev/null || { echo 'Bootstrap tests require bubblewrap.' >&2; exit 1; }
+STAGE=$(mktemp -d)
+trap 'chmod -R u+w "$STAGE"; rm -rf -- "$STAGE"' EXIT HUP INT TERM
+mkdir -p "$STAGE/capsule" "$STAGE/pack/gnu/store/00000000000000000000000000000000-tool/bin" \
+ "$STAGE/pack/gnu/store/11111111111111111111111111111111-profile/bin" "$STAGE/pack/etc"
+cp "$ROOT/infra/guix/bootstrap.sh" "$STAGE/capsule/bootstrap"
+printf '%s\n' '#!/bin/sh' 'printf "%s\n" canonical-tool' > "$STAGE/pack/gnu/store/00000000000000000000000000000000-tool/bin/tool"
+chmod 755 "$STAGE/pack/gnu/store/00000000000000000000000000000000-tool/bin/tool"
+ln -s /gnu/store/00000000000000000000000000000000-tool/bin/tool "$STAGE/pack/gnu/store/11111111111111111111111111111111-profile/bin/tool"
+ln -s /gnu/store/11111111111111111111111111111111-profile/bin "$STAGE/pack/bin"
+printf '%s\n' 'Must stay inside pack.' > "$STAGE/pack/etc/pack-sentinel"
+tar -czf "$STAGE/capsule/runtime.tar.gz" -C "$STAGE/pack" .
+(cd "$STAGE/capsule" && sha256sum bootstrap runtime.tar.gz > SHA256SUMS)
+cp -a "$STAGE/capsule" "$STAGE/tampered"
+printf '%s\n' 'tamper' >> "$STAGE/tampered/runtime.tar.gz"
+cp -a "$STAGE/capsule" "$STAGE/next"
+mkdir "$STAGE/pack/gnu/store/22222222222222222222222222222222-next"
+printf '%s\n' 'Second closure.' > "$STAGE/pack/gnu/store/22222222222222222222222222222222-next/value"
+tar -czf "$STAGE/next/runtime.tar.gz" -C "$STAGE/pack" .
+(cd "$STAGE/next" && sha256sum bootstrap runtime.tar.gz > SHA256SUMS)
+bwrap --unshare-user --uid 0 --gid 0 --unshare-pid --cap-add CAP_DAC_OVERRIDE \
+ --tmpfs / --ro-bind /usr /usr \
+ --symlink usr/bin /bin --symlink usr/lib /lib --symlink usr/lib /lib64 \
+ --ro-bind "$STAGE/capsule" /capsule --ro-bind "$STAGE/next" /next \
+ --ro-bind "$STAGE/tampered" /tampered --proc /proc --dev /dev --tmpfs /tmp \
+ --chdir / /bin/sh -eu <<'TEST'
+fail() { printf '%s\n' "$1" >&2; exit 1; }
+reject() { if sh "$1/bootstrap"; then fail "$2"; fi; }
+TOOL=/gnu/store/00000000000000000000000000000000-tool/bin/tool
+PROFILE=/gnu/store/11111111111111111111111111111111-profile
+mkdir /etc
+printf '%s\n' 'Host configuration.' > /etc/host-sentinel
+[ ! -e /gnu ] && [ ! -e /var/guix ]
+if sh /capsule/bootstrap extra; then fail 'Accepted bootstrap arguments.'; fi
+reject /tampered 'Accepted altered runtime.'
+[ ! -e /gnu ]
+sh /capsule/bootstrap > /tmp/bootstrap-first.log &
+FIRST=$!
+sh /capsule/bootstrap
+wait "$FIRST"
+DIGEST=$(sha256sum /capsule/runtime.tar.gz)
+DIGEST=${DIGEST%% *}
+[ "$(cat "/gnu/.stack-runtimes/$DIGEST")" = "$DIGEST" ]
+[ -z "$(find /gnu/store -mindepth 1 ! -user 0 -print -quit)" ]
+[ -z "$(find /gnu/store -mindepth 1 ! -type l -perm /222 -print -quit)" ]
+[ "$("$PROFILE/bin/tool")" = canonical-tool ]
+[ "$(readlink "$PROFILE/bin/tool")" = "$TOOL" ]
+[ "$(readlink /bin)" = usr/bin ]
+[ "$(cat /etc/host-sentinel)" = 'Host configuration.' ]
+[ ! -e /etc/pack-sentinel ]
+INODE=$(stat -c %i "/gnu/.stack-runtimes/$DIGEST")
+sh /capsule/bootstrap
+[ "$(stat -c %i "/gnu/.stack-runtimes/$DIGEST")" = "$INODE" ]
+rm "/gnu/.stack-runtimes/$DIGEST"
+chmod -R u+w "$PROFILE"
+rm -rf "$PROFILE"
+sh /capsule/bootstrap
+[ "$("$PROFILE/bin/tool")" = canonical-tool ]
+[ -f "/gnu/.stack-runtimes/$DIGEST" ]
+[ -z "$(find /gnu -maxdepth 1 -name '.stack-stage.*' -print -quit)" ]
+sh /next/bootstrap
+[ "$("$PROFILE/bin/tool")" = canonical-tool ]
+[ "$(cat /gnu/store/22222222222222222222222222222222-next/value)" = 'Second closure.' ]
+[ -f "/gnu/.stack-runtimes/$DIGEST" ]
+rm "/gnu/.stack-runtimes/$DIGEST"
+chmod u+w "$TOOL"
+printf '%s\n' 'conflicting content' >> "$TOOL"
+chmod a-w "$TOOL"
+reject /capsule 'Overwrote conflicting store entry.'
+[ ! -e "/gnu/.stack-runtimes/$DIGEST" ]
+[ -z "$(find /gnu -maxdepth 1 -name '.stack-stage.*' -print -quit)" ]
+tail -n 1 "$TOOL" | grep -Fx 'conflicting content'
+chmod -R u+w /gnu
+rm -rf /gnu
+mkdir -p /var/guix
+reject /capsule 'Accepted managed Guix installation.'
+[ ! -e /gnu ]
+rm -rf /var/guix
+mkdir -p /gnu/store
+printf '%s\n' 'Foreign store.' > /gnu/store/sentinel
+reject /capsule 'Accepted foreign store.'
+[ "$(cat /gnu/store/sentinel)" = 'Foreign store.' ]
+rm -rf /gnu
+mkdir /outside
+ln -s /outside /gnu
+reject /capsule 'Accepted symlink /gnu.'
+[ -z "$(find /outside -mindepth 1 -print -quit)" ]
+rm /gnu
+mkdir -p /gnu/.stack-runtimes
+chmod 755 /gnu /gnu/.stack-runtimes
+ln -s /outside /gnu/store
+reject /capsule 'Accepted symlink store.'
+[ -z "$(find /outside -mindepth 1 -print -quit)" ]
+rm /gnu/store
+chmod 777 /gnu/.stack-runtimes
+reject /capsule 'Accepted writable ownership metadata.'
+[ ! -e /gnu/store ]
+printf '%s\n' 'Canonical bootstrap, retry, idempotency, preservation and refusal checks passed.'
+TEST