From 6a295013718af2f1535dfd063822bc09302f531e Mon Sep 17 00:00:00 2001 From: CMGS Date: Wed, 4 Nov 2026 22:27:02 +0800 Subject: [PATCH] fix(os-image): image checks fail when they should, picoclaw is pinned set -e ignores a negated command, so every '! cmd' in verify-vm-inner.sh passed whatever it found, including an unresolved scrcpy-rfb library or an X server left in the image. They now fail the build. Drop the check that named an internal DNS prefix. Pin picoclaw to v0.3.1 with a sha256 like every other downloaded binary, and stop printing the first twelve characters of the API key. Remove two validate-image assertions that compared a value to itself, and number start.sh's steps correctly. --- os-image/debian/validate-image.sh | 2 -- os-image/start.sh | 8 +++---- .../prepare-gapps16-inner.sh | 4 ++-- .../verify-vm-inner.sh | 22 ++++++++++++------- os-image/ubuntu/24.04-picoclaw/Dockerfile | 9 +++++--- os-image/ubuntu/24.04-picoclaw/picoclaw-init | 4 ++-- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/os-image/debian/validate-image.sh b/os-image/debian/validate-image.sh index 851be8af5..1b68aace7 100755 --- a/os-image/debian/validate-image.sh +++ b/os-image/debian/validate-image.sh @@ -250,8 +250,6 @@ validate_image_metadata() { user_metadata=$(inspect_image '{{.Config.User}}') select_architecture_contract "$operating_system" "$architecture" - assert_equal "OCI architecture" "$IMAGE_ARCHITECTURE" "$architecture" - assert_equal "OCI operating system" "linux" "$operating_system" assert_equal "OCI command" '["/sbin/init"]' "$command_metadata" assert_equal "OCI entrypoint" "null" "$entrypoint_metadata" case "$user_metadata" in diff --git a/os-image/start.sh b/os-image/start.sh index 98ceead2a..c3fe2cc0c 100644 --- a/os-image/start.sh +++ b/os-image/start.sh @@ -29,7 +29,7 @@ command -v mkfs.erofs >/dev/null 2>&1 || _MISSING="$_MISSING erofs-utils" command -v mkfs.ext4 >/dev/null 2>&1 || _MISSING="$_MISSING e2fsprogs" command -v wget >/dev/null 2>&1 || _MISSING="$_MISSING wget" if [ -n "$_MISSING" ]; then - echo "[1/7] Installing missing dependencies:$_MISSING" + echo "[1/4] Installing missing dependencies:$_MISSING" sudo apt-get install -y -qq $_MISSING fi @@ -45,7 +45,7 @@ sudo setcap cap_net_admin+ep "$CH_BIN" # 4. Extract Layers via Crane if [ -n "$IMAGE_NAME" ]; then - echo "[4/7] Extracting layers for '$IMAGE_NAME'..." + echo "[2/4] Extracting layers for '$IMAGE_NAME'..." rm -f layer*.erofs boot/vmlinuz* boot/initrd.img* # Download Crane @@ -81,7 +81,7 @@ fi # 5. Prepare COW (Optimized for performance and sparse efficiency) # lazy_itable_init=1 speeds up formatting on large sparse files -echo "[5/7] Preparing optimized sparse COW disk..." +echo "[3/4] Preparing optimized sparse COW disk..." truncate -s 10G cow.raw mkfs.ext4 -F -m 0 -q -E lazy_itable_init=1,lazy_journal_init=1,discard cow.raw @@ -107,7 +107,7 @@ done DISK_CONFIGS+=("path=cow.raw,readonly=off,direct=on,sparse=on,image_type=raw,num_queues=2,queue_size=256,serial=cocoon-cow") # 7. Ignite -echo "[7/7] Igniting Cloud Hypervisor..." +echo "[4/4] Igniting Cloud Hypervisor..." "$CH_BIN" --kernel "$KERNEL" --initramfs "$INITRD" \ --disk "${DISK_CONFIGS[@]}" \ --cmdline "console=ttyS0 loglevel=3 boot=cocoon-overlay cocoon.layers=${COCOON_LAYERS} cocoon.cow=cocoon-cow clocksource=kvm-clock rw" \ diff --git a/os-image/ubuntu/22.04-redroid-16.0-gms-h264/prepare-gapps16-inner.sh b/os-image/ubuntu/22.04-redroid-16.0-gms-h264/prepare-gapps16-inner.sh index c13f1c587..151bf448a 100644 --- a/os-image/ubuntu/22.04-redroid-16.0-gms-h264/prepare-gapps16-inner.sh +++ b/os-image/ubuntu/22.04-redroid-16.0-gms-h264/prepare-gapps16-inner.sh @@ -22,7 +22,7 @@ install_tree() { find "$dst" -type d -name oat -prune -exec rm -rf {} + } -# API-36 x86_64 GMS core from Google's Play Store emulator image. Avoid emulator +# API-36 GMS core from Google's Play Store emulator image. Avoid emulator # Settings/SystemUI/HAL packages; ReDroid keeps its own framework and hardware UI. install_tree /tmp/google-product/priv-app/PrebuiltGmsCore \ /tmp/gapps-out/system/product/priv-app/PrebuiltGmsCore @@ -38,7 +38,7 @@ install_tree /tmp/google-system-ext/priv-app/GoogleFeedback \ /tmp/gapps-out/system/system_ext/priv-app/GoogleFeedback # Chrome uses TrichromeLibrary. The emulator stores the full APKs gzip-compressed -# next to tiny stubs; install the full x86_64 APKs directly for offline first boot. +# next to tiny stubs; install the full APKs directly for offline first boot. mkdir -p /tmp/gapps-out/system/product/app/Chrome gzip -dc /tmp/google-product/app/Chrome/Chrome.apk.gz \ > /tmp/gapps-out/system/product/app/Chrome/Chrome.apk diff --git a/os-image/ubuntu/22.04-redroid-16.0-gms-h264/verify-vm-inner.sh b/os-image/ubuntu/22.04-redroid-16.0-gms-h264/verify-vm-inner.sh index 3b93aecab..176de5b3f 100644 --- a/os-image/ubuntu/22.04-redroid-16.0-gms-h264/verify-vm-inner.sh +++ b/os-image/ubuntu/22.04-redroid-16.0-gms-h264/verify-vm-inner.sh @@ -2,6 +2,13 @@ # Static checks for the built Ubuntu VM image. Run inside its root filesystem. set -euo pipefail +refute() { + if "$@"; then + echo "unexpected: $*" >&2 + exit 1 + fi +} + test -e /boot/vmlinuz test -e /boot/initrd.img test -d /var/lib/redroid-data @@ -14,14 +21,14 @@ grep -Fq 'VIDEO_BIT_RATE="${VIDEO_BIT_RATE:-8000000}"' /usr/local/bin/remoteview grep -Fq -- '-rfbport "$RFB_PORT"' /usr/local/bin/remoteview-run.sh grep -Fq 'video_codec=h264' /usr/local/bin/remoteview-run.sh command -v scrcpy-rfb >/dev/null -! command -v fuse-overlayfs >/dev/null +refute command -v fuse-overlayfs test -f /usr/local/share/scrcpy/scrcpy-server.jar -! ldd /usr/local/bin/scrcpy-rfb | grep -q 'not found' -! command -v Xvfb >/dev/null -! command -v x11vnc >/dev/null -! command -v Xtigervnc >/dev/null -! command -v openbox >/dev/null -! command -v scrcpy >/dev/null +refute grep -q 'not found' <(ldd /usr/local/bin/scrcpy-rfb) +refute command -v Xvfb +refute command -v x11vnc +refute command -v Xtigervnc +refute command -v openbox +refute command -v scrcpy # No first-boot launcher: the container is baked already-created with a restart # policy, so dockerd replays it on boot instead of a service running docker create. @@ -63,7 +70,6 @@ grep -Fq 'local/redroid' /var/lib/docker/image/vfs/repositories.json grep -Fq 'androidboot.redroid_net_ndns=2' "$cfg" grep -Fq 'androidboot.redroid_net_dns1=' "$cfg" grep -Fq 'androidboot.redroid_net_dns2=' "$cfg" -! grep -Eq 'androidboot\.redroid_net_dns[12]=10\.104\.' "$cfg" for value in \ androidboot.use_memfd=0 \ diff --git a/os-image/ubuntu/24.04-picoclaw/Dockerfile b/os-image/ubuntu/24.04-picoclaw/Dockerfile index 0071d091f..79a276a8d 100644 --- a/os-image/ubuntu/24.04-picoclaw/Dockerfile +++ b/os-image/ubuntu/24.04-picoclaw/Dockerfile @@ -47,11 +47,14 @@ RUN --mount=type=secret,id=cocoon_overlay \ # PicoClaw: install pre-built binary ARCH=${TARGETARCH:-$(dpkg --print-architecture)}; \ case "$ARCH" in \ - amd64) PC_ARCH="x86_64" ;; \ - arm64) PC_ARCH="arm64" ;; \ + amd64) PC_ARCH="x86_64"; PC_SHA256="86f0fe84aa55279352edbe13adfca484a03bcf189e2030b25e34628089069c3f" ;; \ + arm64) PC_ARCH="arm64"; PC_SHA256="e78ab0de05d000698ff8b32458e71cb3134e52e9eaf540e3323a72e9914de060" ;; \ *) echo "unsupported arch: $ARCH" && exit 1 ;; \ esac && \ - curl -fsSL "https://github.com/sipeed/picoclaw/releases/latest/download/picoclaw_Linux_${PC_ARCH}.tar.gz" | tar xz -C /usr/local/bin/ picoclaw && \ + curl -fsSLo /tmp/picoclaw.tar.gz "https://github.com/sipeed/picoclaw/releases/download/v0.3.1/picoclaw_Linux_${PC_ARCH}.tar.gz" && \ + echo "$PC_SHA256 /tmp/picoclaw.tar.gz" | sha256sum -c - && \ + tar xzf /tmp/picoclaw.tar.gz -C /usr/local/bin/ picoclaw && \ + rm -f /tmp/picoclaw.tar.gz && \ chmod 0755 /usr/local/bin/picoclaw && \ # Cocoon initramfs overlay + network cp /run/secrets/cocoon_overlay /etc/initramfs-tools/scripts/cocoon-overlay && \ diff --git a/os-image/ubuntu/24.04-picoclaw/picoclaw-init b/os-image/ubuntu/24.04-picoclaw/picoclaw-init index 2b45e2746..8352a08da 100644 --- a/os-image/ubuntu/24.04-picoclaw/picoclaw-init +++ b/os-image/ubuntu/24.04-picoclaw/picoclaw-init @@ -175,8 +175,8 @@ def main() -> None: print(f"Configured: model={model_field}") if args.api_base or provider_prefix in PROVIDER_API_BASE: print(f" api_base={entry.get('api_base', '')}") - print(f" api_key={key[:12]}...{key[-4:]}") - print(f" telegram=enabled") + print(f" api_key=...{key[-4:]}") + print(" telegram=enabled") # Enable and (re)start picoclaw. systemctl("daemon-reload")