From 901d0a84483fad3fd9c7a7fbebc555d6b840f262 Mon Sep 17 00:00:00 2001 From: Steffen Beyer Date: Thu, 2 Apr 2026 22:45:34 +0200 Subject: [PATCH] Harden FreeBSD guest /etc and activation diagnostics --- docs/PROGRESS.md | 99 +++++++++ .../phase12-runtime-diagnostics-freebsd.md | 210 ++++++++++++++++++ modules/fruix/system/freebsd.scm | 39 +++- .../system/run-phase11-shepherd-pid1-qemu.sh | 15 ++ .../system/run-phase11-shepherd-pid1-xcpng.sh | 15 ++ tests/system/run-phase8-system-image.sh | 6 + tests/system/run-phase9-xcpng-boot.sh | 15 ++ 7 files changed, 392 insertions(+), 7 deletions(-) create mode 100644 docs/reports/phase12-runtime-diagnostics-freebsd.md diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 0e95bb6..0ef0635 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -2711,3 +2711,102 @@ Next recommended step: 1. continue with Phase 12.2 and tighten the guest-side runtime/operator diagnostics 2. remove or reduce the most distracting remaining boot/runtime rough edges where the fixes are small and local 3. keep the deployment path stable so Phase 13 can start from a sharper baseline + +## 2026-04-02 — Phase 12.2: guest runtime diagnostics tightened and `/etc` handling improved + +Completed work: + +- wrote the Phase 12.2 report: + - `docs/reports/phase12-runtime-diagnostics-freebsd.md` +- updated `modules/fruix/system/freebsd.scm` so selected database-backed `/etc` files are now materialized as regular files in the guest rootfs instead of symlinks: + - `/etc/passwd` + - `/etc/master.passwd` + - `/etc/group` + - `/etc/login.conf` +- the generated activation script now refreshes those files from `/run/current-system/etc` before rebuilding FreeBSD databases +- activation now writes a guest-visible log: + - `/var/log/fruix-activate.log` + - with markers including: + - `fruix-activate:start` + - `fruix-activate:cap_mkdb=ok` + - `fruix-activate:pwd_mkdb=ok` + - `fruix-activate:done` + - exit status marker via shell trap +- tightened closure permissions slightly by making: + - `etc/master.passwd` + mode `0600` +- upgraded validation harnesses so they now assert the improved runtime behavior directly: + - `tests/system/run-phase8-system-image.sh` + - now checks that image `/etc/login.conf` is a regular file + - now checks that image `/etc/master.passwd` is a regular file + - `tests/system/run-phase9-xcpng-boot.sh` + - `tests/system/run-phase11-shepherd-pid1-xcpng.sh` + - `tests/system/run-phase11-shepherd-pid1-qemu.sh` + - now check for: + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - activation log completion marker +- fixed a small follow-up bug in the activation log path: + - initial implementation used `touch`, which is not staged in the minimal guest + - switched to shell redirection instead: + - `: >> "$logfile"` + +Validation: + +- `tests/system/run-phase8-system-image.sh` passes locally with the new image-layout checks: + - workdir: `/tmp/phase12-2-image-1775159011` + - confirmed: + - `login_conf_kind=regular` + - `master_passwd_kind=regular` +- `tests/system/run-phase11-shepherd-pid1-qemu.sh` passes locally again with the new activation/runtime checks: + - workdir: `/tmp/phase12-2b-qemu-1775161367` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `shepherd_pid=1` + - `sshd_status=running` +- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with the new checks: + - workdir: `/tmp/phase12-2b-phase9-1775161731` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `shepherd_status=running` + - `sshd_status=running` +- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with the new checks: + - workdir: `/tmp/phase12-2b-phase11-1775162210` + - confirmed: + - `activate_log=fruix-activate:start ... fruix-activate:done ...` + - `login_conf_kind=regular` + - `login_conf_db=present` + - `pwd_dbs=present` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `shepherd_pid=1` + - `sshd_status=running` + +Important findings: + +- the old symlink-based handling for login/password database inputs was a real mismatch with FreeBSD expectations; making those files regular in the guest was a better fit than leaving them store-backed symlinks +- adding a direct activation log materially improves post-boot diagnosis and avoids guessing whether activation actually completed +- the first attempt exposed a missing-userland dependency (`touch`) quickly; because the new diagnostics were explicit, the follow-up fix was immediate and local +- both validated boot paths still hold after this change: + - `freebsd-init+rc.d-shepherd` + - `shepherd-pid1` + +Current assessment: + +- the current Fruix guest remains intentionally minimal, but its runtime behavior is now less prototype-noisy and easier to inspect as a basic FreeBSD-like system +- this is exactly the kind of targeted hardening that makes the existing system a better launch point for native FreeBSD base-build work + +Next recommended step: + +1. complete Phase 12.3 by making the host-staged FreeBSD base boundary explicit in the package/model layer and docs +2. document the first intended replacement order for native world/kernel work +3. then begin Phase 13 with a clearer transitional boundary diff --git a/docs/reports/phase12-runtime-diagnostics-freebsd.md b/docs/reports/phase12-runtime-diagnostics-freebsd.md new file mode 100644 index 0000000..553e9b7 --- /dev/null +++ b/docs/reports/phase12-runtime-diagnostics-freebsd.md @@ -0,0 +1,210 @@ +# Phase 12.2: tightened guest runtime diagnostics and reduced early-boot rough edges + +Date: 2026-04-02 + +## Goal + +The current Fruix FreeBSD guest already booted, reached the network, and ran Shepherd. The next hardening step was to make the guest easier to diagnose and to remove a few distracting runtime rough edges that were still coming from the prototype-style `/etc` handling. + +The main targets were: + +- reduce early-boot/login-class noise around `/etc/login.conf` +- ensure the FreeBSD password/login databases are created in writable guest state, not implicitly in store-backed paths +- add a clear activation log inside the guest +- teach the validation harnesses to assert the new behavior directly + +## Root cause addressed + +The old rootfs layout symlinked several generated `/etc` files directly to `/run/current-system/etc/...`, including: + +- `/etc/login.conf` +- `/etc/master.passwd` +- `/etc/passwd` +- `/etc/group` + +That worked for static lookup, but it was a poor fit for FreeBSD tools such as: + +- `cap_mkdb` +- `pwd_mkdb` +- early login-class lookups + +because those tools expect to work with regular files and adjacent generated database files such as: + +- `/etc/login.conf.db` +- `/etc/pwd.db` +- `/etc/spwd.db` + +With symlink-backed inputs, the system could still limp along, but it produced avoidable warnings and less clear runtime behavior. + +## Implementation + +### 1. Selected `/etc` files now become regular files in the guest rootfs + +`modules/fruix/system/freebsd.scm` now materializes these files as regular files in the rootfs instead of symlinks: + +- `/etc/passwd` +- `/etc/master.passwd` +- `/etc/group` +- `/etc/login.conf` + +Other generated configuration files that do not need this treatment remain symlinked to `/run/current-system/...`. + +This gives FreeBSD's database tools writable, regular inputs in the guest filesystem while keeping the current system closure as the source of truth. + +### 2. Activation now refreshes those files from `/run/current-system/etc` + +The generated activation script now refreshes the regular guest copies from the currently selected system closure before rebuilding databases. + +That means rebuild/redeploy still works coherently even though these specific files are no longer left as symlinks in the booted guest. + +### 3. Activation now records a guest-visible log + +Activation now writes: + +- `/var/log/fruix-activate.log` + +with explicit markers such as: + +- `fruix-activate:start` +- `fruix-activate:cap_mkdb=ok` +- `fruix-activate:pwd_mkdb=ok` +- `fruix-activate:done` +- exit status marker from the shell trap + +This gives a direct guest-side indicator of whether activation actually completed. + +### 4. Closure permissions were tightened slightly + +The generated closure now explicitly sets: + +- `etc/master.passwd` => `0600` + +before the rootfs/image path copies it into the guest. + +### 5. Validation harnesses were upgraded + +#### Local image validation + +`tests/system/run-phase8-system-image.sh` now asserts that the mounted image contains: + +- `/etc/login.conf` as a regular file +- `/etc/master.passwd` as a regular file + +#### VM validation + +These harnesses now check for the new runtime behavior: + +- `tests/system/run-phase9-xcpng-boot.sh` +- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` +- `tests/system/run-phase11-shepherd-pid1-qemu.sh` + +New checks include: + +- `login_conf_kind=regular` +- `login_conf_db=present` +- `pwd_dbs=present` +- activation log contains `fruix-activate:done` + +They also capture the activation log into metadata. + +### 6. Small follow-up fix + +The first activation-log implementation briefly used `touch`, which is not staged in the minimal guest userland. This was corrected by switching to shell redirection: + +- `: >> "$logfile"` + +so the activation path no longer depends on an extra utility for log-file creation. + +## Validation + +### Local image structure + +Passing run: + +- `PASS phase8-system-image` +- workdir: `/tmp/phase12-2-image-1775159011` + +Key metadata: + +```text +login_conf_kind=regular +master_passwd_kind=regular +``` + +### Local QEMU Shepherd PID 1 + +Passing run: + +- `PASS phase11-shepherd-pid1-qemu` +- workdir: `/tmp/phase12-2b-qemu-1775161367` + +Key metadata: + +```text +activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0 +login_conf_kind=regular +login_conf_db=present +pwd_dbs=present +shepherd_pid=1 +sshd_status=running +``` + +### Real VM, `freebsd-init+rc.d-shepherd` + +Passing run: + +- `PASS phase9-xcpng-boot` +- workdir: `/tmp/phase12-2b-phase9-1775161731` + +Key metadata: + +```text +activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0 +login_conf_kind=regular +login_conf_db=present +pwd_dbs=present +compat_prefix_shims=absent +guile_module_smoke=ok +shepherd_status=running +sshd_status=running +``` + +### Real VM, `shepherd-pid1` + +Passing run: + +- `PASS phase11-shepherd-pid1-xcpng` +- workdir: `/tmp/phase12-2b-phase11-1775162210` + +Key metadata: + +```text +activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0 +login_conf_kind=regular +login_conf_db=present +pwd_dbs=present +shepherd_pid=1 +compat_prefix_shims=absent +guile_module_smoke=ok +sshd_status=running +``` + +## Assessment + +This was a small but high-value hardening step. + +The guest now behaves more like a real FreeBSD system in one of the places where a store-backed prototype can otherwise feel awkward: password/login database management and early `/etc` expectations. + +The important result is not cosmetic; it is operational: + +- activation success is now visible inside the guest +- the login/password database inputs live as regular guest files where FreeBSD expects them +- both validated boot modes still work locally and on the real XCP-ng VM + +## Next recommended step + +Proceed to Phase 12.3: + +- make the host-staged FreeBSD base boundary explicit in the code/documentation model +- group the transitional host-copy base packages more clearly +- document the first intended replacement order for native world/kernel artifacts in `/frx/store` diff --git a/modules/fruix/system/freebsd.scm b/modules/fruix/system/freebsd.scm index 4a581b3..d65f3f6 100644 --- a/modules/fruix/system/freebsd.scm +++ b/modules/fruix/system/freebsd.scm @@ -657,7 +657,18 @@ uid gid home))))) users) "")) - (compat-prefixes "") + (refresh-db-input-files + (string-join + (map (lambda (entry) + (match entry + ((name mode) + (string-append + "if [ -f /run/current-system/etc/" name " ]; then rm -f /etc/" name "; cp /run/current-system/etc/" name " /etc/" name "; chmod " mode " /etc/" name "; fi\n")))) + '(("passwd" "0644") + ("master.passwd" "0600") + ("group" "0644") + ("login.conf" "0644"))) + "")) (ssh-section (string-append "mkdir -p /var/empty /etc/ssh /root/.ssh\n" @@ -671,13 +682,22 @@ (string-append "#!/bin/sh\n" "set -eu\n" + "logfile=/var/log/fruix-activate.log\n" "mkdir -p /var/cron /var/db /var/lib/fruix /var/log /var/run /root /home /tmp\n" + ": >> \"$logfile\"\n" + "trap 'status=$?; echo \"fruix-activate:exit status=$status\" >> \"$logfile\"' EXIT\n" + "echo \"fruix-activate:start\" >> \"$logfile\"\n" "chmod 1777 /tmp\n" - "if [ -x /usr/bin/cap_mkdb ] && [ -f /etc/login.conf ]; then /usr/bin/cap_mkdb /etc/login.conf || true; fi\n" - "if [ -x /usr/sbin/pwd_mkdb ] && [ -f /etc/master.passwd ]; then /usr/sbin/pwd_mkdb -p /etc/master.passwd || true; fi\n" + refresh-db-input-files + "if [ -x /usr/bin/cap_mkdb ] && [ -f /etc/login.conf ]; then\n" + " if /usr/bin/cap_mkdb /etc/login.conf; then echo \"fruix-activate:cap_mkdb=ok\" >> \"$logfile\"; else echo \"fruix-activate:cap_mkdb=failed\" >> \"$logfile\"; fi\n" + "fi\n" + "if [ -x /usr/sbin/pwd_mkdb ] && [ -f /etc/master.passwd ]; then\n" + " if /usr/sbin/pwd_mkdb -p /etc/master.passwd; then echo \"fruix-activate:pwd_mkdb=ok\" >> \"$logfile\"; else echo \"fruix-activate:pwd_mkdb=failed\" >> \"$logfile\"; fi\n" + "fi\n" home-setup - compat-prefixes - ssh-section))) + ssh-section + "echo \"fruix-activate:done\" >> \"$logfile\"\n"))) (define (pid1-mount-commands os) (string-join @@ -1131,6 +1151,8 @@ (write-file (string-append closure-path "/" (car entry)) (cdr entry))) generated-files) (chmod (string-append closure-path "/activate") #o555) + (when (file-exists? (string-append closure-path "/etc/master.passwd")) + (chmod (string-append closure-path "/etc/master.passwd") #o600)) (chmod (string-append closure-path "/usr/local/etc/rc.d/fruix-activate") #o555) (chmod (string-append closure-path "/usr/local/etc/rc.d/fruix-shepherd") #o555) (when (file-exists? (string-append closure-path "/boot/fruix-pid1")) @@ -1202,8 +1224,11 @@ (for-each (lambda (path) (symlink-force (string-append "/run/current-system/etc/" path) (string-append rootfs "/etc/" path))) - '("rc.conf" "fstab" "hosts" "passwd" "master.passwd" "group" - "login.conf" "shells" "motd" "ttys")) + '("rc.conf" "fstab" "hosts" "shells" "motd" "ttys")) + (for-each (lambda (path) + (copy-regular-file (string-append closure-path "/etc/" path) + (string-append rootfs "/etc/" path))) + '("passwd" "master.passwd" "group" "login.conf")) (when (file-exists? (string-append closure-path "/etc/ssh/sshd_config")) (symlink-force "/run/current-system/etc/ssh/sshd_config" (string-append rootfs "/etc/ssh/sshd_config"))) diff --git a/tests/system/run-phase11-shepherd-pid1-qemu.sh b/tests/system/run-phase11-shepherd-pid1-qemu.sh index f87353f..1d45868 100755 --- a/tests/system/run-phase11-shepherd-pid1-qemu.sh +++ b/tests/system/run-phase11-shepherd-pid1-qemu.sh @@ -113,6 +113,10 @@ logger_log=$(ssh_guest 'cat /var/log/fruix-shepherd.log' | tr '\n' ' ') shepherd_bootstrap_tail=$(ssh_guest "awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }' /var/log/shepherd-bootstrap.out 2>/dev/null || true" | tr '\n' ' ') shepherd_log_tail=$(ssh_guest "awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }' /var/log/shepherd.log 2>/dev/null || true" | tr '\n' ' ') guest_dmesg_tail=$(ssh_guest "dmesg | awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }'" | tr '\n' ' ') +activate_log=$(ssh_guest 'cat /var/log/fruix-activate.log 2>/dev/null || true' | tr '\n' ' ') +login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi') +login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing') +pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi') uname_output=$(ssh_guest 'uname -sr') operator_home_listing=$(ssh_guest 'ls -d /home/operator') @@ -128,6 +132,13 @@ operator_home_listing=$(ssh_guest 'ls -d /home/operator') [ "$shepherd_socket" = present ] || { echo "shepherd socket is missing" >&2; exit 1; } [ "$shepherd_status" = running ] || { echo "shepherd is not running" >&2; exit 1; } [ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; } +[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; } +[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; } +[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; } +case "$activate_log" in + *fruix-activate:done*) : ;; + *) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;; +esac [ "$operator_home_listing" = /home/operator ] || { echo "operator home missing" >&2; exit 1; } cat >"$metadata_file" </dev/null || true' | tr '\n' ' ') +login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi') +login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing') +pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi') [ "$ready_marker" = ready ] || { echo "unexpected ready marker contents: $ready_marker" >&2; exit 1; } [ "$shepherd_pid" = 1 ] || { echo "shepherd is not PID 1: pid=$shepherd_pid command=$pid1_command" >&2; exit 1; } @@ -166,6 +170,13 @@ activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n' [ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; } [ "$compat_prefix_shims" = absent ] || { echo "compatibility prefix shims are still present in /tmp" >&2; exit 1; } [ "$guile_module_smoke" = ok ] || { echo "guest Guile module smoke failed: $guile_module_smoke" >&2; exit 1; } +[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; } +[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; } +[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; } +case "$activate_log" in + *fruix-activate:done*) : ;; + *) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;; +esac [ "$run_current_system_target" = "/frx/store/$closure_base" ] || { echo "unexpected /run/current-system target in guest: $run_current_system_target" >&2 exit 1 @@ -210,6 +221,10 @@ operator_home_listing=$operator_home_listing compat_prefix_shims=$compat_prefix_shims guile_module_smoke=$guile_module_smoke activate_preview=$activate_preview +activate_log=$activate_log +login_conf_kind=$login_conf_kind +login_conf_db=$login_conf_db +pwd_dbs=$pwd_dbs boot_backend=xcp-ng-xo-cli init_mode=shepherd-pid1 operator_access=ssh-root-key diff --git a/tests/system/run-phase8-system-image.sh b/tests/system/run-phase8-system-image.sh index df14e14..1792d41 100755 --- a/tests/system/run-phase8-system-image.sh +++ b/tests/system/run-phase8-system-image.sh @@ -114,11 +114,15 @@ boot_loader_target=$(readlink "$mnt_root/boot/loader") boot_loader_conf_target=$(readlink "$mnt_root/boot/loader.conf") rc_conf_target=$(readlink "$mnt_root/etc/rc.conf") rc_script_target=$(readlink "$mnt_root/usr/local/etc/rc.d/fruix-shepherd") +if [ -L "$mnt_root/etc/login.conf" ]; then login_conf_kind=symlink; elif [ -f "$mnt_root/etc/login.conf" ]; then login_conf_kind=regular; else login_conf_kind=missing; fi +if [ -L "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=symlink; elif [ -f "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=regular; else master_passwd_kind=missing; fi [ "$run_current_system_target" = "/frx/store/$closure_base" ] || { echo "unexpected /run/current-system target: $run_current_system_target" >&2; exit 1; } [ "$boot_loader_target" = /run/current-system/boot/loader ] || { echo "unexpected /boot/loader target: $boot_loader_target" >&2; exit 1; } [ "$boot_loader_conf_target" = /run/current-system/boot/loader.conf ] || { echo "unexpected /boot/loader.conf target: $boot_loader_conf_target" >&2; exit 1; } [ "$rc_conf_target" = /run/current-system/etc/rc.conf ] || { echo "unexpected /etc/rc.conf target: $rc_conf_target" >&2; exit 1; } [ "$rc_script_target" = /run/current-system/usr/local/etc/rc.d/fruix-shepherd ] || { echo "unexpected fruix_shepherd rc target: $rc_script_target" >&2; exit 1; } +[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in the image" >&2; exit 1; } +[ "$master_passwd_kind" = regular ] || { echo "/etc/master.passwd is not a regular file in the image" >&2; exit 1; } loader_conf_image=$mnt_root/frx/store/$closure_base/boot/loader.conf rc_conf_image=$mnt_root/frx/store/$closure_base/etc/rc.conf grep -F 'comconsole' "$loader_conf_image" >/dev/null || { echo "loader.conf is missing serial console config" >&2; exit 1; } @@ -159,6 +163,8 @@ boot_loader_target=$boot_loader_target boot_loader_conf_target=$boot_loader_conf_target rc_conf_target=$rc_conf_target rc_script_target=$rc_script_target +login_conf_kind=$login_conf_kind +master_passwd_kind=$master_passwd_kind image_generation_mode=declarative-system-layer frontend_invocation=$fruix_cmd system image EOF diff --git a/tests/system/run-phase9-xcpng-boot.sh b/tests/system/run-phase9-xcpng-boot.sh index c968f59..5f6bb0e 100755 --- a/tests/system/run-phase9-xcpng-boot.sh +++ b/tests/system/run-phase9-xcpng-boot.sh @@ -157,12 +157,23 @@ operator_home_listing=$(ssh_guest 'ls -d /home/operator') compat_prefix_shims=$(ssh_guest 'for p in /tmp/guile-freebsd-validate-install /tmp/guile-gnutls-freebsd-validate-install /tmp/shepherd-freebsd-validate-install; do if [ -e "$p" ] || [ -L "$p" ]; then echo present; exit 0; fi; done; echo absent') guile_module_smoke=$(ssh_guest "env LANG='C.UTF-8' LC_ALL='C.UTF-8' LD_LIBRARY_PATH='$guile_extra_store/lib:$guile_store/lib:/usr/local/lib' GUILE_SYSTEM_PATH='$guile_store/share/guile/3.0:$guile_store/share/guile/site/3.0:$guile_store/share/guile/site:$guile_store/share/guile' GUILE_LOAD_PATH='$shepherd_store/share/guile/site/3.0:$guile_extra_store/share/guile/site/3.0' GUILE_SYSTEM_COMPILED_PATH='$guile_store/lib/guile/3.0/ccache:$guile_store/lib/guile/3.0/site-ccache' GUILE_LOAD_COMPILED_PATH='$shepherd_store/lib/guile/3.0/site-ccache:$guile_extra_store/lib/guile/3.0/site-ccache' GUILE_SYSTEM_EXTENSIONS_PATH='$guile_store/lib/guile/3.0/extensions' GUILE_EXTENSIONS_PATH='$guile_extra_store/lib/guile/3.0/extensions' '$guile_store/bin/guile' --no-auto-compile -c '(use-modules (fibers config) (gnutls) (shepherd config)) (display \"ok\") (newline)'") activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n' ' ') +activate_log=$(ssh_guest 'cat /var/log/fruix-activate.log 2>/dev/null || true' | tr '\n' ' ') +login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi') +login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing') +pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi') [ "$ready_marker" = ready ] || { echo "unexpected ready marker contents: $ready_marker" >&2; exit 1; } [ "$shepherd_status" = running ] || { echo "fruix_shepherd is not running" >&2; exit 1; } [ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; } [ "$compat_prefix_shims" = absent ] || { echo "compatibility prefix shims are still present in /tmp" >&2; exit 1; } [ "$guile_module_smoke" = ok ] || { echo "guest Guile module smoke failed: $guile_module_smoke" >&2; exit 1; } +[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; } +[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; } +[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; } +case "$activate_log" in + *fruix-activate:done*) : ;; + *) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;; +esac [ "$run_current_system_target" = "/frx/store/$closure_base" ] || { echo "unexpected /run/current-system target in guest: $run_current_system_target" >&2 exit 1 @@ -205,6 +216,10 @@ operator_home_listing=$operator_home_listing compat_prefix_shims=$compat_prefix_shims guile_module_smoke=$guile_module_smoke activate_preview=$activate_preview +activate_log=$activate_log +login_conf_kind=$login_conf_kind +login_conf_db=$login_conf_db +pwd_dbs=$pwd_dbs boot_backend=xcp-ng-xo-cli operator_access=ssh-root-key root_authorized_key_file=$root_authorized_key_file