Skip to content

Build installable Andromeda Developer Preview - #5

Merged
oratis merged 31 commits into
mainfrom
codex/installable-preview
Aug 1, 2026
Merged

Build installable Andromeda Developer Preview#5
oratis merged 31 commits into
mainfrom
codex/installable-preview

Conversation

@oratis

@oratis oratis commented Jul 26, 2026

Copy link
Copy Markdown
Owner

What changed

  • builds an x86-64 Fedora bootc 44 payload with KDE Plasma and the Andromeda Rust control plane
  • builds an image-builder bootc-generic-iso with an embedded offline payload
  • provides a safe graphical Anaconda default and a clearly labeled destructive CI-only boot entry
  • installs to a blank UEFI/QEMU disk and verifies EFI fallback, NVRAM, SELinux enforcing, SDDM, taskd, and the hardware report
  • stages and boots revision 2, then rolls back and boots revision 1
  • preserves installer-generated root/boot kernel arguments while removing the live environment's selinux=0
  • uploads the ISO, SHA-256, disk diagnostics, installer logs, and lifecycle serial evidence
  • documents the tested support boundary and verified build evidence

Why

This is the first installable Developer Preview vertical slice. The acceptance boundary is deliberately x86-64 UEFI with QEMU/KVM, OVMF, VirtIO, 8 GiB RAM, and a new 32 GiB disk. It does not claim that a physical PC or Mac is Supported or Certified.

Verified end-to-end

Final head b52314125237815ef5c34764a23cb5df40239b0a:

The serial evidence contains, in order:

ANDROMEDA_FIRST_BOOT_OK revision=1
ANDROMEDA_UPDATE_STAGED_OK revision=2
ANDROMEDA_UPDATE_BOOT_OK revision=2
ANDROMEDA_ROLLBACK_STAGED_OK revision=1
ANDROMEDA_ROLLBACK_BOOT_OK revision=1
ANDROMEDA_E2E_OK

All three disk boots use root=UUID, boot=UUID, selinux=1, and enforcing=1; the evidence contains neither selinux=0 nor ANDROMEDA_E2E_FAILED.

Other validation

  • bash -n os/scripts/*.sh os/installer/*.sh os/files/usr/libexec/*
  • shellcheck os/scripts/*.sh os/installer/*.sh os/files/usr/libexec/*
  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --locked -- -D warnings
  • cargo test --workspace --locked (19 tests)

oratis added 30 commits July 26, 2026 15:56
@oratis
oratis marked this pull request as ready for review July 28, 2026 09:42
@oratis

oratis commented Aug 1, 2026

Copy link
Copy Markdown
Owner Author

PR #5 代码评审:Build installable Andromeda Developer Preview

总体评价

这是一个完成度很高的垂直切片:从 Containerfile、image-builder ISO、Kickstart、UEFI fallback 到 QEMU 全生命周期验收(安装 → 首启 → 更新 → 回滚)形成了闭环,脚本普遍有 set -euo pipefail、trap 清理和 shellcheck 门禁,文档对支持边界的描述也很克制诚实。但存在一个严重的安全性与文档一致性问题:build-iso.sh 硬编码 INSTALLER_DEFAULT=1,导致所有构建出的 ISO(包括 CI 上传的开发者预览产物)都以"10 秒后自动清盘安装"作为 GRUB 默认启动项,与文档宣称的"正常默认项是图形化安装器"直接矛盾。该问题必须在合并前修复。

优点

  • 验收脚本设计扎实:os/scripts/test-install.sh 按 GPT 分区类型 GUID 和 andromeda-root 文件系统标签发现分区(第 128–139 行),不依赖 p1/p2 顺序;mount -o ro,noload 只读挂载、qemu-nbd --read-only、EXIT trap 逐项清理(第 23–52 行),都是正确做法。
  • CI 验证器状态机清晰:os/files/usr/libexec/andromeda-ci-verify/var/lib/andromeda-ci/state(跨 deployment 共享的 /var)驱动 first-boot → updating → rolling-back → complete,配合 set -Eeuo pipefail + trap on_error ERR 输出 ANDROMEDA_E2E_FAILED 标记,证据链可审计。
  • 危险入口有内核参数门控:andromeda-ci-verify.serviceConditionKernelCommandLine=andromeda.ci=1 限定只在 CI 启动项下运行,破坏性 Kickstart(zerombr + clearpart --all)只挂在该入口上。
  • systemd 加固到位:andromeda-taskd.service 使用 DynamicUserProtectSystem=strictNoNewPrivilegesRestrictAddressFamilies 等,且只监听 127.0.0.1:7777
  • 内核参数安全校验:os/installer/install-uefi-fallback.sh 第 83–99 行通过 OSTree API 重建 kargs 后,显式拒绝残留 selinux=0 的 BLS 条目,并断言 root=/boot= 仍在——这是对"live 环境 selinux=0 泄漏进目标系统"这一真实风险的正确防御。
  • 供应链意识:image-builder-cli@sha256: digest 固定(build-iso.sh 第 7 行),free-disk-space action 按 commit SHA 固定;Anaconda 版本契约有显式断言(os/Containerfile 第 134 行 test "${anaconda_version%%.*}" -ge 44)。
  • 文档(docs/development/installable-preview.md)明确列出未验收范围、artifact digest 和"证据不等于真机支持"的边界声明。

问题与建议

  • 【严重】构建出的 ISO 默认启动项是破坏性自动清盘安装,与文档矛盾。 os/scripts/build-iso.sh 第 51 行硬编码 --build-arg INSTALLER_DEFAULT=1,经 os/Containerfile 第 131–132 行的 sed -i "s/^ default: 0$/ default: ${INSTALLER_DEFAULT}/" 写入 os/installer/iso.yaml,使 GRUB default 指向第 2 个条目——"Automated destructive install (CI only)"(iso.yaml 第 9–11 行),且 timeout: 10。这意味着:开发者按 docs/development/installable-preview.md 第 33 行"安装器的正常默认项是 Install Andromeda Developer Preview"和 os/README.md 第 8–10 行的说明构建或下载 CI artifact 的 ISO,在真机上启动 10 秒后就会自动清空第一块磁盘。而 .github/workflows/os-e2e.yml 第 81–92 行把这个 ISO 直接作为 Andromeda-Developer-Preview-x86_64-* 产物上传。建议:build-iso.sh 默认 INSTALLER_DEFAULT=0,仅由 test-install.sh/CI 显式传 1 并构建单独命名的 CI ISO(如 *-ci.iso),或至少不要把 default=1 的 ISO 当作 "Developer Preview" 产物发布。
  • 【中等】更新 payload 无完整性校验。 andromeda-ci-verify 第 7 行 UPDATE_URL=http://10.0.2.2:8080/andromeda-v2.tar,第 46–50 行以 root 身份通过明文 HTTP 下载后直接 skopeo copy + bootc switch。虽有 andromeda.ci=1 门控,但任何能在宿主 8080 端口提供服务的进程都能让被测系统安装任意镜像。建议在 kernel cmdline 或镜像内嵌入期望的 sha256,下载后校验再导入。
  • 【中等】宿主 HTTP 服务绑定 0.0.0.0。 os/scripts/test-install.sh 第 194–197 行 python3 -m http.server 8080 --bind 0.0.0.0 --directory "${OUTPUT_DIR}" 会把整个 output 目录(含磁盘镜像、NVRAM、日志)暴露给宿主所在网络。QEMU user-mode 网络中 guest 访问 10.0.2.2 由 slirp 转发到宿主回环,绑定 127.0.0.1 即可。在开发者本机运行时这是不必要的暴露面。
  • 【中等】安装失败时的错误路径会被前置断言掩盖。 test-install.sh 故意在第 94–96 行捕获 install_status 延迟退出以便收集诊断,但第 166–174 行的 grep --text ... "${INSTALL_LOG}" | teegrep -q 'ANDROMEDA_INSTALLER_KARGS_OK mode=ci' 和 ESP 文件 test -f 都在第 189 行的 install_status 检查之前执行——安装失败时脚本会死在一条令人困惑的 grep/test 失败上,而不是打印 Installer exited with status N。建议把 status 检查移到诊断收集(第 146–149 行)之后、严格断言之前。
  • 【中等】test-install.sh 缺少前置环境检查。 脚本需要 root(modprobeqemu-nbdmount)却不在开头校验 EUID,非 root 运行会在 45 分钟安装跑完后才失败;OVMF 默认路径 /usr/share/OVMF/OVMF_CODE_4M.fd(第 12–13 行)是 Debian/Ubuntu 专有布局,Fedora 主机需要 OVMF_CODE/OVMF_VARS_TEMPLATE 环境变量覆盖,但两份文档都没提。建议加 root 检查并在文档写明覆盖变量。
  • 【中等】curl 重试不覆盖 connection refused。 andromeda-ci-verify 第 21–23 行对 taskd /healthz--retry 30,第 46 行下载用 --retry 60,但 curl 的 --retry 默认不重试 ECONNREFUSED;systemctl is-active(Type=simple)也不保证 taskd 已在监听。首启竞态下健康检查可能一次拒绝就失败。建议追加 --retry-connrefused--retry-all-errors
  • 【中等】payload 默认启用 sshd。 os/Containerfile 第 96 行 systemctl enable ... sshd.service,配合 firewalld 默认放行 ssh,意味着交互安装出的桌面预览系统默认对外开放密码认证 SSH。对 Developer Preview 建议默认关闭,或至少在文档的安全边界一节说明。
  • 【轻微】sed 替换 GRUB default 无命中校验。 os/Containerfile 第 131–132 行的 sed -i "s/^ default: 0$/..."iso.yaml 缩进或格式漂移时会静默不生效;INSTALLER_DEFAULT 也未校验只能是 0/1。建议替换后 grep -q "default: ${INSTALLER_DEFAULT}" 断言。
  • 【轻微】efibootmgr --create 不去重。 install-uefi-fallback.sh 第 64–69 行每次安装都会新建 Andromeda NVRAM 条目,重装会累积重复项。建议先 efibootmgr | grep Andromeda 删旧再建。
  • 【轻微】默认远程更新引用指向不存在且未签名的 ghcr.io/oratis/andromeda:edge(os/installer/andromeda-ci.ks 第 17 行、interactive-defaults.ks 第 1 行)。文档已在"当前限制"中声明,可接受,但注意用户在装好的系统上跑 bootc upgrade 会直接失败或拉到未签名镜像。
  • 【轻微】固定资源导致并发冲突:8080 端口、/dev/nbd* 扫描、固定 DISK_PATH 使同一宿主无法并行跑两个 test-install.sh;CI 无碍,本地需注意。
  • 【轻微】exec > >(tee -a /dev/ttyS0)(install-uefi-fallback.sh 第 26–28 行)在脚本退出时存在进程替换 flush 竞态,串口日志末尾几行可能丢失;诊断脚本已用直接重定向,此处可统一。
  • 【轻微】杂项:os/Containerfile 把软件包拆成 10 个 RUN dnf install 层,体积和可读性都不占优;andromeda-ci-verify 用完不删 /var/tmp/andromeda-v2.tar(数 GB);os-e2e.ymlcheckout@v4/upload-artifact@v4 用 tag 而 free-disk-space 用 SHA,固定策略不一致;installable-preview.md "构建产物"一节漏列了 CI 会上传的 andromeda-v1-history.json

结论

Request changes —— 工程质量整体优秀,但 build-iso.sh 硬编码 INSTALLER_DEFAULT=1 使发布产物默认 10 秒自动清盘、且与两处文档的安全承诺直接矛盾,属于必须先修复的安全问题;其余中等项(HTTP 无校验更新、0.0.0.0 绑定、失败路径掩盖)建议一并处理。


Review by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant