diff --git a/keys/private.key b/keys/private.key new file mode 100644 index 0000000..c8365c5 --- /dev/null +++ b/keys/private.key @@ -0,0 +1,11 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lFgEaqdVLxYJKwYBBAHaRw8BAQdAMqdhLopNz2sQyweu8/Q69g4JaDyV9OId7Vwl +yUruXrsAAQCVpYkfluugz8zo1sRyG90sKUKNQSJYTL4insHZRt3fnhFutCdndWl4 +LWlzbyBkZWJ1ZyA8ZGVidWdAZ3VpeC1pc28uaW52YWxpZD6IrwQTFgoAVxYhBOF9 +hn03wGAxQ+/pQ37/dJ7F1gGMBQJqp1UvGxSAAAAAAAQADm1hbnUyLDIuNSsxLjEy +LDAsMwIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRB+/3SexdYBjAfh +AP9MgJ/wH3UGOb2Nb6divGwf0wYckQYMdhl24WN9yCQm7gD/bik7WTBEj7odelZR +/jf8DaiM/6nqp1YqXxHUEKhi7wc= +=EPPE +-----END PGP PRIVATE KEY BLOCK----- diff --git a/keys/public.key b/keys/public.key new file mode 100644 index 0000000..8d8dcd7 --- /dev/null +++ b/keys/public.key @@ -0,0 +1,10 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEaqdVLxYJKwYBBAHaRw8BAQdAMqdhLopNz2sQyweu8/Q69g4JaDyV9OId7Vwl +yUruXru0J2d1aXgtaXNvIGRlYnVnIDxkZWJ1Z0BndWl4LWlzby5pbnZhbGlkPoiv +BBMWCgBXFiEE4X2GfTfAYDFD7+lDfv90nsXWAYwFAmqnVS8bFIAAAAAABAAObWFu +dTIsMi41KzEuMTIsMCwzAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJ +EH7/dJ7F1gGMB+EA/0yAn/AfdQY5vY1vp2K8bB/TBhyRBgx2GXbhY33IJCbuAP9u +KTtZMESPuh16VlH+N/wNqIz/qeqnVipfEdQQqGLvBw== +=6csO +-----END PGP PUBLIC KEY BLOCK----- diff --git a/main.go b/main.go index 57b77c4..a44abfa 100644 --- a/main.go +++ b/main.go @@ -55,7 +55,7 @@ func setup(arch string) *dagger.Container { WithEnvVariable("DEBIAN_FRONTEND", "noninteractive"). WithExec([]string{"apt-get", "update"}). WithExec([]string{"apt-get", "install", "-y", "--no-install-recommends", - "curl", "ca-certificates", "xz-utils", "gnupg", "passwd", "netbase"}). + "curl", "ca-certificates", "xz-utils", "gnupg", "passwd", "netbase", "git", "python3"}). WithExec([]string{"curl", "-fsSL", "-o", "/tmp/" + tarball, "https://ftp.gnu.org/gnu/guix/" + tarball}). WithExec([]string{"tar", "-C", "/", "--warning=no-timestamp", "-xf", "/tmp/" + tarball}). diff --git a/patch.sh b/patch.sh new file mode 100644 index 0000000..8de6f8c --- /dev/null +++ b/patch.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Clone the pinned Guix commit, verify its authenticity, apply local debugging +# patches, sign the result with our own key, and write a channels file that +# Guix will accept (the channel is named 'guix' with a valid introduction). +# Called from pull.sh before 'guix pull'. + +SRC=/tmp/guix-src +CHANNELS=/workspace/channels.scm +FINGERPRINT="E17D867D37C0603143EFE9437EFF749EC5D6018C" +FINGERPRINT_SPACED="E17D 867D 37C0 6031 43EF E943 7EFF 749E C5D6 018C" + +# Pinned Guix commit from channels.scm. +COMMIT="$(grep -oE '\(commit "[0-9a-f]{40}"\)' "$CHANNELS" | grep -oE '[0-9a-f]{40}')" +[ -n "$COMMIT" ] || { echo "error: no pinned commit in channels.scm" >&2; exit 1; } +echo "pinned Guix commit: $COMMIT" + +# Shallow-clone the pinned commit, plus the keyring branch used for +# authentication. Land on a branch so the patched commit is reachable by ref. +rm -rf "$SRC" +git init -q "$SRC" +git -C "$SRC" remote add origin https://codeberg.org/guix/guix.git +git -C "$SRC" fetch -q --depth 1 origin "$COMMIT" +git -C "$SRC" fetch -q origin keyring +git -C "$SRC" checkout -q -b patched FETCH_HEAD + +# Import the official signing keys and verify the pinned commit's signature, +# so we patch a known-authentic base. +export GNUPGHOME=/tmp/gnupg +rm -rf "$GNUPGHOME" +mkdir -p "$GNUPGHOME" +chmod 700 "$GNUPGHOME" +echo "trust-model always" > "$GNUPGHOME/gpg.conf" +mkdir -p /tmp/keyring +git -C "$SRC" archive origin/keyring | tar -x -C /tmp/keyring +for k in /tmp/keyring/*.key; do + gpg --batch --import "$k" >/dev/null 2>&1 || true +done +git -C "$SRC" verify-commit "$COMMIT" || { + echo "error: pinned commit $COMMIT failed signature verification" >&2 + exit 1 +} +echo "verified pinned commit signature" + +# Route shepherd's log to the console, so boot failures are visible on screen +# instead of only in /var/log/messages. +python3 - "$SRC" <<'PY' +import sys +from pathlib import Path +p = Path(sys.argv[1]) / "gnu/services/shepherd.scm" +s = p.read_text() +old = ''' ;; Start shepherd. + (execl #$(file-append shepherd "/bin/shepherd") + "shepherd" "--config" + #$(shepherd-configuration-file services shepherd)))))''' +new = ''' ;; Start shepherd. Log to the console so boot failures are visible. + (execl #$(file-append shepherd "/bin/shepherd") + "shepherd" "--config" + #$(shepherd-configuration-file services shepherd) + "--logfile" "/dev/console"))))''' +assert old in s, "shepherd-boot-gexp execl not found" +p.write_text(s.replace(old, new, 1)) +print("patched shepherd-boot-gexp") +PY + +# Make the kernel verbose by default (drop 'quiet'). +python3 - "$SRC" <<'PY' +import sys +from pathlib import Path +p = Path(sys.argv[1]) / "gnu/system.scm" +s = p.read_text() +old = ''' "quiet"))''' +new = ''' "verbose"))''' +assert s.count(old) == 1, f"expected one 'quiet' kernel arg, found {s.count(old)}" +p.write_text(s.replace(old, new, 1)) +print("patched %default-kernel-arguments") +PY + +# Sign the patched commit with our key. +gpg --batch --import /workspace/keys/private.key >/dev/null 2>&1 +git -C "$SRC" add -A +git -C "$SRC" \ + -c user.email=debug@guix-iso.invalid \ + -c user.name="guix-iso debug" \ + -c user.signingkey="$FINGERPRINT" \ + commit -q -S -m "debug: console shepherd log + verbose kernel" +NEW_COMMIT="$(git -C "$SRC" rev-parse HEAD)" +echo "patched commit: $NEW_COMMIT" + +cat > /tmp/channels-local.scm <&2; exit 1; } - if guix pull --verbosity=3 --fallback --channels=/workspace/channels.scm; then + if guix pull --verbosity=3 --fallback --channels=/tmp/channels-local.scm; then PULL_OK=1 break fi