Repository navigation
Bootstrap repairs for Ubuntu 26.04: sudo, PHP packages, PHP-FPM, DNS and CA trust - #153
Merged
Merged
Conversation
A run of 2.1.1 on Ubuntu 26.04 fixed nothing, because each repair was guarded by a check that the broken state itself defeated. Sudoers: bootstrap skipped the whole step whenever the file existed, so machines carrying wildcard rules from an older release kept them. The step now always runs and the installer decides whether to rewrite. apt: InstallPrerequisites ran apt update first and returned on error. A PPA with nothing for this release makes apt exit 100, so bootstrap gave up before reaching the code that repairs that very repository. Both update calls are warnings now, as is add-apt-repository's exit code. nginx: one vhost naming a certificate that is not on disk stops nginx from starting, taking every project offline. Bootstrap now checks the certificates vhosts reference, regenerates the ones MageBox manages, and names the file to remove for any it does not. Docker: a permission error on the socket was reported as a stopped daemon, sending the user to restart something already running. The two are now told apart, with the docker group command printed for the first. dnsmasq: Ubuntu's dnsmasq-base ships the binary without a service unit, so MageBox considered dnsmasq installed, skipped the install and then failed to start it. Installation now also requires the unit. And when dnsmasq cannot be started, the systemd-resolved drop-in is removed instead of being left pointing at a resolver that is not there, which made .test names fail rather than fall through to /etc/hosts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-FPM A bootstrap run on Ubuntu 26.04 got further but still failed, in three new places. PHP packages: pinning Ondrej's PPA to its newest suite made apt work but produced packages that cannot be installed, because they depend on libxml2, libicu74 and libzip4t64 versions 26.04 no longer ships. The PPA itself says packages.sury.org is now canonical for this release, and sury does publish for it. Bootstrap now picks the repository covering the running release, and warns plainly when none does. Root: run under sudo, bootstrap built the environment under /root and added an nginx include pointing into a directory nginx cannot read, so nginx would not start. It now refuses to run as root. php-fpm.conf: every run appended another pools include. Duplicates define the same pool twice and an include from a run as another user matches nothing, so PHP-FPM refused to start — and a PHP-FPM that cannot start makes every later dpkg operation on the package fail, which is what broke the Blackfire and dnsmasq installs. The file is now rewritten to hold exactly one include. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
systemd-resolved never read MageBox's drop-in. Config is written through a temp file, which os.CreateTemp creates mode 0600, and cp preserves it; systemd-resolved parses its configuration after dropping privileges, so every restart logged "Failed to open /etc/systemd/resolved.conf.d/ magebox.conf: Permission denied" and ignored it. Files written this way are now 0644, and callers needing something stricter still set it. The DNS check hid this. It queried dnsmasq directly, which proves only that dnsmasq works, so bootstrap printed "resolves to 127.0.0.1" while browsers and curl could not resolve anything. It now asks the system resolver as well and names which one answered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bootstrap reported "Local CA already installed" whenever rootCA.pem existed, which says nothing about trust. On a machine carried over from another install, the browser store still trusted the previous authority, so every local HTTPS site warned while bootstrap looked clean. The CA's serial is now compared against the browser trust store, and mkcert -install runs when they differ. The check answers "trusted" when it cannot tell, so a machine without certutil never reinstalls pointlessly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MageBox filters out packages apt-cache does not know about, but apt gives the same empty answer whether a package is genuinely missing or a sources file could not be read. The PHP repository file MageBox wrote was root-only, so apt-cache run as the user reported every php8.1 … php8.4 package as unavailable, and bootstrap skipped all of them while printing success. The machine kept only the PHP version Ubuntu ships. A permission warning now means "cannot tell" rather than "not available", and apt decides: the install either works or fails with a real message. The file mode itself is fixed in an earlier commit; this stops a comparable mistake elsewhere from silently emptying the package list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Installing PHP still did nothing on Ubuntu 26.04, through a cascade this commit breaks in two places. php8.5-fpm was left half-configured by an earlier failure, and one such package makes every apt install exit 100 regardless of what it is asked to install. InstallPrerequisites returned on that error, so it never reached the repository configuration below it — and without the repository, every php8.1 … php8.4 package looked unavailable and was skipped. Bootstrap now runs dpkg --configure -a when dpkg reports broken packages, and treats a failure to install its base tools as a warning. The repository file is also chmod'ed explicitly after writing, so an install carrying a root-only file from an older MageBox is repaired even if nothing rewrites the file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The guide still described pinning the PPA to an older suite, which was the first attempt and does not work: those packages depend on library versions a newer Ubuntu no longer ships. It now documents choosing the repository that covers the release, and records why pinning a suite is the wrong fix so it is not tried again. Also documents the two repairs added since: the apt source file is made readable, and half-configured packages are finished before installing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nine bugs found by running
magebox bootstrapon a fresh Ubuntu 26.04 LTS machine. The 2.1.1 fixes were correct but never took effect, because each repair was guarded by a check that the broken state itself defeated. Four commits; the version stays 2.1.1 and the entries are folded into that release's changelog section.Four of these are the same mistake: checking that a file exists instead of checking that the thing works.
Bootstrap could not repair anything
/etc/sudoers.d/mageboxexisted, so every machine upgrading from an older release kept the wildcard rules sudo-rs rejects. It now always runs; the installer decides whether a rewrite is needed.InstallPrerequisitesranapt updatefirst and returned on error. A PPA with nothing for the running release makes apt exit 100, so bootstrap gave up before reaching the code that repairs that repository. Update failures are warnings now.PHP could not be installed
dpkgoperation fail, which is what broke the Blackfire and dnsmasq installs mid-run. The file is now rewritten to hold exactly one include.Running as root broke the machine
Under
sudo, bootstrap built the whole environment in/root: config, certificate authority, pools and an nginx include pointing into a directory nginx cannot read, which stopped nginx entirely. Bootstrap now refuses to run as root.nginx, DNS and certificates
Failed to open /etc/systemd/resolved.conf.d/magebox.conf: Permission denied. Config files are written 0644 now; callers needing stricter modes still set their own..testbroken. The resolver override is written before dnsmasq is known to work; left behind it points every.testlookup at a resolver that is not running, so names failed instead of falling through to/etc/hosts. The fallback removes it.dnsmasq-basewas. That package ships the binary without a service unit, so MageBox skipped the install and then failed to start the service.rootCA.pem. On a machine restored from another install the browser still trusted the previous authority and every local HTTPS site warned. The serial is now compared against the browser trust store.Docker
A permission error on the socket was reported as a stopped daemon, sending users to restart something already running. The two are told apart, and the permission case prints the command that adds the user to the docker group.
Verification
go test ./...go vet,gofmt.testresolves, mailpit returns 200 over HTTPSNew tests cover the pure decisions: repository choice, the root guard, include normalization, Docker failure classification, certificate scanning, the systemd unit check, resolver cleanup and browser trust detection.
🤖 Generated with Claude Code