# One unit-backed CONFIG sync pass (appconfig.Sync + restart the routes whose # env file actually changed) — and nothing else. Started only by # carlos-adopt.path, which fires when the agent touches # /data/config-sync-requested; it has no [Install] section because nothing # else should ever want it. Deliberately NOT carlos-adopt.service: that unit # also runs release.Pass and the canary-TTL nag, so pointing a per-config-write # trigger at it would let one app's `carlos env set` cut over another app's # pending release within seconds, and would nag on every write instead of # hourly. Same root + hardening shape as carlos-adopt.service, which is what # writing /etc/carlos/apps and restarting carlos-app@ units requires. [Unit] Description=carlos config sync (unit-backed routes, on agent request) After=network-online.target Wants=network-online.target # A path unit re-triggers as often as config is written; the default start # rate limit would latch this unit into start-limit-hit after a burst and then # ignore every later trigger until an operator reset it. ([Unit], not # [Service] — systemd moved these two keys in v230.) StartLimitIntervalSec=0 [Service] Type=oneshot # CARLOS_DEPLOYMENT_BUCKET/_DIR + CARLOS_SECRETS_KEY live here. EnvironmentFile=-/etc/carlos/host.env ExecStart=/opt/carlos/carlos adopt --config-only # --- hardening --- # Runs as ROOT deliberately, exactly like carlos-adopt.service: this pass # writes /etc/carlos/apps and restarts instance units via systemctl. # NoNewPrivileges and the syscall filter are omitted for the systemctl child; # the rest applies. ProtectHome=yes PrivateTmp=yes PrivateDevices=yes ProtectClock=yes ProtectHostname=yes ProtectKernelTunables=yes ProtectKernelModules=yes ProtectKernelLogs=yes RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX RestrictNamespaces=yes RestrictRealtime=yes LockPersonality=yes MemoryDenyWriteExecute=yes MemoryMax=256M TasksMax=64