Harden FreeBSD guest /etc and activation diagnostics
This commit is contained in:
@@ -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
|
||||
|
||||
210
docs/reports/phase12-runtime-diagnostics-freebsd.md
Normal file
210
docs/reports/phase12-runtime-diagnostics-freebsd.md
Normal file
@@ -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`
|
||||
Reference in New Issue
Block a user