fa44ffbb24
1. The state directory was created too late and never verified. ensure_state_dir only ran when the ownership record was written, well after assert_swap_path_is_safe had already required every parent of swap.path to exist. On a clean host that meant a perfectly legal /var/lib/awg2-harness/swapfile was rejected because the directory this package is supposed to create did not exist yet. Worse, when the directory did exist the check only confirmed it was a directory. A pre-existing /var/lib/awg2-harness that was group- or world-writable defeated the whole point of restricting swap.path to root-owned roots: another user could still swap the swapfile out from under a root-owned fallocate or mkswap. ensure_state_dir now runs first in ensure_swap and asserts what the restriction actually depends on: the parent is a real directory and not a symlink, the state directory itself is not a symlink, it is owned by uid 0, and it is not writable by group or others. A mode that is merely narrower than 0700 is tightened rather than rejected; anything group- or world-writable is a hard error, because the safety argument for the whole allow-list rests on it. The units also declare StateDirectory=awg2-harness with mode 0700 and RuntimeDirectory=awg2-harness, so in the common case systemd creates and owns both and the binary only has to verify. The runtime checks stay regardless: the CLI subcommands run outside the service lifecycle. 2. The fstab copies could be more permissive than the file they mirror. The backup and pristine copies were written at a hardcoded 0644 with a comment claiming they must not be wider than the original. On a host where /etc/fstab is 0600 they were, and the rollback then handed that wider mode to the live file too. FstabTransaction now captures the live mode when it opens and uses it for the backup, the pristine copy, the candidate and the rollback. One test added, unix-only since it asserts a mode: a 0600 fstab produces 0600 copies and stays 0600 after the commit. cargo test --workspace: 180 + 4 passed. clippy -D warnings clean. Unit files not verified here - no systemd on this host; tools/build.sh runs systemd-analyze verify on the build machine.
41 lines
1.7 KiB
Desktop File
41 lines
1.7 KiB
Desktop File
[Unit]
|
|
Description=AWG2 Harness multi-orchestrator
|
|
After=network-online.target docker.service
|
|
Wants=network-online.target
|
|
Requires=docker.service
|
|
# Restart backoff below can span ~5 minutes, so the failure window has to be wider than
|
|
# the old 60s or the limit would trip during a single legitimate backoff sequence.
|
|
StartLimitIntervalSec=15min
|
|
StartLimitBurst=10
|
|
|
|
[Service]
|
|
# Type=exec, not simple: startup is only considered successful once the binary has been
|
|
# executed, so a missing or non-executable /usr/sbin/awg2-harness fails the unit instead
|
|
# of being reported as started.
|
|
Type=exec
|
|
User=root
|
|
# ensure-swap is not run here. The daemon performs it as the first step of its own startup
|
|
# sequence, where it shares one error contract, one lock and one log stream. Running it
|
|
# twice per start only duplicated the work and split the failure path across two units.
|
|
ExecStart=/usr/sbin/awg2-harness --config /etc/awg2-harness/config.toml daemon
|
|
# systemd creates and owns these, so the common case needs no directory handling in the
|
|
# binary. The runtime checks stay regardless: the CLI subcommands run outside this unit.
|
|
RuntimeDirectory=awg2-harness
|
|
RuntimeDirectoryMode=0755
|
|
RuntimeDirectoryPreserve=yes
|
|
StateDirectory=awg2-harness
|
|
StateDirectoryMode=0700
|
|
# on-failure, not always: a clean exit is deliberate and must not be restarted.
|
|
Restart=on-failure
|
|
# Stepped backoff 10 -> 20 -> 40 -> 80 -> 160s. A tight restart loop against a dependency
|
|
# that is still coming up (Docker, the container, the network) only burns the start limit
|
|
# before the dependency has a chance to recover.
|
|
RestartSec=10s
|
|
RestartSteps=4
|
|
RestartMaxDelaySec=160s
|
|
StandardOutput=journal
|
|
StandardError=journal
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|