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:
2026-05-03 22:25:22 +01:00
parent 907d447369
commit 2e764746e7
21 changed files with 1503 additions and 69 deletions
+81
View File
@@ -0,0 +1,81 @@
#!/bin/bash
# lint-config-paths.sh — Detect init service file path violations in config files
#
# Init service files in config [[files]] entries MUST use /etc/init.d/ paths,
# NOT /usr/lib/init.d/. The base package installs to /usr/lib/init.d/ and
# silently overwrites any config files placed there during install_dir().
#
# The init system's config_for_dirs() gives /etc/init.d/ priority over
# /usr/lib/init.d/ for the same filename, so config overrides must use /etc/.
#
# Usage:
# scripts/lint-config-paths.sh # Check all redbear configs
# scripts/lint-config-paths.sh config/*.toml # Check specific files
#
# Exit codes:
# 0 — No violations found
# 1 — Violations found (printed to stderr)
set -euo pipefail
# Default to all redbear configs if no arguments
if [ $# -eq 0 ]; then
set -- config/redbear-*.toml
fi
violations=0
for config_file in "$@"; do
if [ ! -f "$config_file" ]; then
echo "WARN: $config_file not found, skipping" >&2
continue
fi
# Find [[files]] entries with /usr/lib/init.d/ paths
# We look for path = "/usr/lib/init.d/..." lines
line_num=0
in_files_section=false
while IFS= read -r line; do
line_num=$((line_num + 1))
# Track TOML structure to only check [[files]] sections
if [[ "$line" =~ ^\[\[files\]\] ]]; then
in_files_section=true
continue
elif [[ "$line" =~ ^\[ ]]; then
in_files_section=false
continue
fi
if $in_files_section; then
# Check for /usr/lib/init.d/ paths
if [[ "$line" =~ path[[:space:]]*=[[:space:]]*\"/usr/lib/init\.d/ ]]; then
echo "VIOLATION: $config_file:$line_num" >&2
echo " Line: $line" >&2
echo " Fix: Change /usr/lib/init.d/ to /etc/init.d/" >&2
echo "" >&2
violations=$((violations + 1))
fi
# Also check for /usr/lib/environment.d/ (similar override pattern)
if [[ "$line" =~ path[[:space:]]*=[[:space:]]*\"/usr/lib/environment\.d/ ]]; then
echo "VIOLATION: $config_file:$line_num" >&2
echo " Line: $line" >&2
echo " Fix: Change /usr/lib/environment.d/ to /etc/environment.d/" >&2
echo "" >&2
violations=$((violations + 1))
fi
fi
done < "$config_file"
done
if [ $violations -gt 0 ]; then
echo "FAILED: $violations init service path violation(s) found." >&2
echo "Config [[files]] entries must use /etc/init.d/ not /usr/lib/init.d/" >&2
echo "See: local/docs/BUILD-SYSTEM-HARDENING-PLAN.md Phase 1" >&2
exit 1
else
echo "OK: No init service path violations in config files."
exit 0
fi