carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1# Root apply of a platform self-update (spec §6): re-verify the pointer,
2# copy the candidate into a root-owned dir, journal, swap the binary and
3# units, restart the edge, gate it, roll back to carlos.prev on failure.
4#
5# ExecStart goes through one line of shell so that when a journal is open
6# (a previous apply was cut off) and carlos.prev exists, the RECOVERY runs
7# from carlos.prev rather than from the candidate that did not work.
8#
9# The moves protocol floor (moves spec §11) narrows that choice: once a
10# floor is armed (/data/.moves/floor.min-release is there and not empty),
11# carlos.prev runs only when its verdict file (/opt/carlos/carlos.prev.allowed,
12# written by root after comparing versions in Go) names that same floor,
13# byte for byte. A floor path that is a symlink or anything but a regular
14# file (a dangling link, a FIFO, a directory) never reads as "no floor":
15# the current binary runs (#267). carlos.prev's own floor gate (carlos
16# system floor-allows-prev) makes the comparison: it opens each file once,
17# without following a symlink or waiting on a FIFO, refuses anything but a
18# small single-link regular file with the expected owner, and exits 0 only
19# for a match. Not cmp: the agent owns /data and could swap the floor file
20# between the shell's tests and cmp's open.
21# Otherwise the current binary runs, and its own check refuses to restore a
22# carlos.prev below the floor. No floor file: the choice is exactly as
23# before. The line carries no percent sign and no dollar sign, both of which
24# systemd expands before the shell sees them.
25#
26# The seeds floor (seeded-instances spec §3.3) adds the same test for its
27# own files: once /data/.moves/seeds-floor.min-release is there and not
28# empty, carlos.prev runs only when /opt/carlos/carlos.prev.seeds-allowed
29# names that same floor, byte for byte.
30#
31# Deliberately no filesystem-sandboxing directive and no dedicated run
32# account: it must write /opt/carlos and /etc/systemd/system, which only
33# root can do. StartLimitIntervalSec=0 because the path unit can fire in
34# bursts. TimeoutStartSec bounds a hung apply; OnFailure= makes a killed or
35# timed-out apply recover without waiting for a touch.
36[Unit]
37Description=carlos platform self-update (root apply)
38After=network-online.target
39Wants=network-online.target
40StartLimitIntervalSec=0
41OnFailure=carlos-system-recover.service
42
43[Service]
44Type=oneshot
45TimeoutStartSec=15min
46EnvironmentFile=-/etc/carlos/host.env
47ExecStart=/bin/sh -c 'if [ -x /opt/carlos/system/guard/carlos ] && { [ -e /var/lib/carlos-claims/authority/exec/census.json ] || [ -L /var/lib/carlos-claims/authority/exec/census.json ] || [ -e /opt/carlos/system/guard/moves ] || [ -L /opt/carlos/system/guard/moves ]; }; then exec /opt/carlos/system/guard/carlos system guard-exec apply; fi; if [ -f /opt/carlos/system/router/journal.json ] && [ -x /opt/carlos/carlos.prev ] && [ ! -L /data/.moves/floor.min-release ] && { [ ! -e /data/.moves/floor.min-release ] || [ -f /data/.moves/floor.min-release ]; } && { ! [ -s /data/.moves/floor.min-release ] || /opt/carlos/carlos.prev system floor-allows-prev /data/.moves/floor.min-release /opt/carlos/carlos.prev.allowed; } && [ ! -L /data/.moves/seeds-floor.min-release ] && { [ ! -e /data/.moves/seeds-floor.min-release ] || [ -f /data/.moves/seeds-floor.min-release ]; } && { ! [ -s /data/.moves/seeds-floor.min-release ] || /opt/carlos/carlos.prev system floor-allows-prev /data/.moves/seeds-floor.min-release /opt/carlos/carlos.prev.seeds-allowed; }; then exec /opt/carlos/carlos.prev system apply; fi; exec /opt/carlos/carlos system apply'
48
49# --- hardening (the carlos-stage.service set) ---
50ProtectHome=yes
51PrivateTmp=yes
52PrivateDevices=yes
53ProtectClock=yes
54ProtectHostname=yes
55ProtectKernelTunables=yes
56ProtectKernelModules=yes
57ProtectKernelLogs=yes
58RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
59RestrictNamespaces=yes
60RestrictRealtime=yes
61LockPersonality=yes
62MemoryDenyWriteExecute=yes
63MemoryMax=256M
64TasksMax=64
65