feat: build system hardening — collision detection, validation gates, init path enforcement
5-phase hardening to prevent silent file-layer collisions (the D-Bus regression class): Phase 1: lint-config-paths.sh + make lint-config in depends.mk Phase 2: CollisionTracker in installer (content-hash comparison) Phase 3: installs manifests in recipe.toml + validate-file-ownership.sh Phase 4: validate-init-services.sh + make validate in disk.mk Phase 5: documentation (AGENTS.md, BUILD-SYSTEM-HARDENING-PLAN.md) Both redbear-mini and redbear-full build and validate clean. 66 declared install paths in base, zero conflicts.
This commit is contained in:
@@ -382,3 +382,55 @@ Based on these invariants, the first practical implementation slice should do al
|
||||
4. ensure release-mode source trees before deep build execution
|
||||
|
||||
If those four changes land cleanly, the build system will already move from reactive deep-build debugging toward proactive build-state validation.
|
||||
|
||||
---
|
||||
|
||||
## 6. Installer file-layer separation
|
||||
|
||||
### Layer ordering
|
||||
|
||||
The installer (`install_dir()`) processes files in this order:
|
||||
|
||||
1. Config pre-install `[[files]]` (`postinstall = false`)
|
||||
2. Package staging (`install_packages()`)
|
||||
3. Config post-install `[[files]]` (`postinstall = true`)
|
||||
4. User/group creation (`passwd`, `shadow`, `group`)
|
||||
|
||||
Layer 2 silently overwrites Layer 1 files at the same path. Layer 3 overwrites
|
||||
Layer 2. There is no collision detection or warning.
|
||||
|
||||
### Invariant I1: Init service path separation
|
||||
|
||||
Config `[[files]]` entries that create or override init service files MUST use
|
||||
`/etc/init.d/` paths. Package-owned service files go in `/usr/lib/init.d/`.
|
||||
|
||||
The init system's `config_for_dirs(["/usr/lib/init.d", "/etc/init.d"])` uses a
|
||||
BTreeMap keyed by filename. For the same filename, the `/etc/init.d/` entry
|
||||
overwrites the `/usr/lib/init.d/` entry, so config overrides take effect.
|
||||
|
||||
Config entries using `/usr/lib/init.d/` paths will be silently overwritten by
|
||||
package staging. The `scripts/lint-config-paths.sh` tool detects violations.
|
||||
|
||||
### Invariant I2: Config override survival
|
||||
|
||||
Any file created by config `[[files]]` that must survive package installation
|
||||
MUST use a path that packages do not install to.
|
||||
|
||||
For init services, `/etc/init.d/` provides this via the `config_for_dirs()`
|
||||
BTreeMap mechanism. For other file types, either use `/etc/` paths or mark the
|
||||
file as `postinstall = true`.
|
||||
|
||||
### Invariant I3: Post-install as explicit override
|
||||
|
||||
`[[files]]` entries with `postinstall = true` run after package installation and
|
||||
are guaranteed to overwrite any package-provided file at the same path.
|
||||
|
||||
Prefer `/etc/` directory overrides over `postinstall` for init services, because
|
||||
`postinstall` requires every override to be explicitly marked and is easy to
|
||||
miss. The `/etc/init.d/` path convention is self-enforcing via `config_for_dirs()`.
|
||||
|
||||
### Enforcement
|
||||
|
||||
- `scripts/lint-config-paths.sh` — detects `/usr/lib/init.d/` paths in config files
|
||||
- `make lint-config` — runs the lint as a build step
|
||||
- Full plan: `local/docs/BUILD-SYSTEM-HARDENING-PLAN.md`
|
||||
|
||||
Reference in New Issue
Block a user