docs: first container test pass, and what it found

Ubuntu 24.04, Debian 12, Arch and Fedora 41. OS and package-manager detection
correct on all four; --help works unprivileged; and the install report is written
end to end in a container that had never seen this code — task 1's mechanism
confirmed off the machine it was written on.

Three real findings.

--only does not isolate a step. Running --only "Core utils" still created a user
account, because ask_username and the account creation sit in the preamble above
the step framework, so everything before the first `step` runs every time. It is
defensible and it is not what the flag appears to promise.

.setup-answers travels with a copy of the tree. Correctly gitignored and 0600,
but it lives inside the repository directory, so `cp -r` carries it — a container
that had never run setup came up already knowing the username and created that
account. Nothing secret in it; it is a surprise, which in an installer is the
expensive kind.

adduser leaks its own interactive prompt ("Try again? [y/N]") on the
account-creation path. Harmless here because the run had already stopped, but a
hang on a real unattended install.

Also records what containers cannot reach: no init means systemd, netplan, ufw
and the sshd drop-ins are only verifiable as "wrote the right file"; Docker and
Postgres are untested; macOS is unreachable entirely and everything about it is
reasoned rather than executed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-13 04:00:31 +00:00
co-authored by Claude Opus 5
parent d7d64cd6d6
commit 236a3a5481
+74
View File
@@ -0,0 +1,74 @@
# Testing the installer in containers
**2026-08-13.** First pass. Ubuntu 24.04, Debian 12, Arch, Fedora 41.
## What passed
**OS and package-manager detection is correct on all four.**
| image | `OS` | `PM` |
| --- | --- | --- |
| ubuntu:24.04 | `ubuntu` | `apt` |
| debian:12 | `debian` | `apt` |
| archlinux | `arch` | `pacman` |
| fedora:41 | `fedora` | `dnf` |
**`--help` and argument handling work unprivileged** in a clean container, before any escalation.
**The install report is written**, end to end, in a container that had never seen this code. That is
task 1's mechanism confirmed outside the machine it was written on.
**Refusing beats hanging.** With no answer available the run stopped with
`FAIL: No answer. Set ASSUME_YES=1 to run without prompts.` rather than blocking forever on a prompt
nobody could see. That is the behaviour an unattended run needs, and it already exists.
---
## What it found
### 1. `--only` does not isolate a step
Running `--only "Core utils"` still **created a user account**, because `ask_username` and the
account creation happen in the preamble, above the step framework. Everything before the first
`step` call runs on every invocation.
Defensible — every step needs to know who it is installing for — but it means `--only` is not the
surgical tool it appears to be, and a first-time reader will assume it is. Either the preamble
becomes lazy, or `--only` says plainly what it will still do.
### 2. `.setup-answers` travels with a copy of the tree
It lives at `scripts/setup/machine-setup/.setup-answers`, is correctly gitignored, and is `0600`
root-owned. But it is **inside the repository directory**, so `cp -r` or a tarball of the tree
carries it — which is exactly what happened here: a container that had never run setup came up
already knowing the username `pastilhas` and created that account.
Not a leak (username and install path, nothing secret). It is a surprise, and surprises in an
installer are the expensive kind. Worth moving outside the repo, next to the progress file.
### 3. `adduser` leaks its own prompts
```
Use of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 848.
Try again? [y/N]
```
The account-creation path reaches an interactive `adduser` question the script does not answer.
Harmless here because the run stopped anyway, but on a real unattended install this is a hang.
---
## Coverage this cannot reach
Containers have no init by default, so **`systemctl`, netplan, ufw and the sshd drop-ins were not
exercised**. Those sections can only be verified as "wrote the right file", not "the service came
up". Running privileged containers with systemd would close most of that gap and is the obvious next
step.
**Docker-in-Docker** was not attempted, so the Docker section and Postgres provisioning are
untested. Mounting the host socket would test the section's logic while telling us nothing about the
install path.
**macOS is untestable here entirely.** The 17 skipped sections, the Homebrew paths, the Xcode
command line tools step and the refusal-to-run-as-root are all reasoned from documentation and
unverified by execution.