Skip to content

Commit bd0da35

Browse files
authored
Add apl-feed config sync subcommand and metadata-LWW apply gate (#83)
* feat(apply): gate writes with metadata last-write-wins Skip per-key writes whose incoming edited_at is not strictly newer than the on-disk feed.meta.json entry, with a bogus-future heal exception. Symmetric with the server-side LWW in /api/feeders/config/sync. * feat(apl-feed): add config sync subcommand and systemd timer Periodic ~60s poll of POST /api/feeders/config/sync that pushes the local snapshot and applies the server's merged response. Authenticates with the existing Bearer alv1 token. Hardening: tight ReadWritePaths, jitter, on-disk metadata round-trip with rejected_fields healing. * fix(config-sync): four review-driven correctness fixes LWW bogus-future check now uses APL_APPLY_INCOMING_SERVER_TIME from the response so a fast local clock cannot self-mask future-stamped on-disk metadata. Atomic position-group LWW pre-check in config.sh stops a partial server response from mixing local and server axes. _config_sync_load_meta validates RFC 3339 and edited_by enum per entry. read_secret_file failure is captured cleanly so a corrupt secret exits 64 instead of 1.
1 parent 56d6787 commit bd0da35

11 files changed

Lines changed: 1707 additions & 7 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[Unit]
2+
Description=airplanes.live feeder remote-config sync
3+
Wants=network-online.target
4+
After=network-online.target airplanes-feed.service
5+
ConditionPathExists=/etc/airplanes/feeder-claim-secret
6+
7+
[Service]
8+
Type=oneshot
9+
ExecStart=/usr/local/bin/apl-feed config sync
10+
TimeoutStartSec=60s
11+
SyslogIdentifier=airplanes-config-sync
12+
NoNewPrivileges=yes
13+
ProtectSystem=strict
14+
ProtectHome=yes
15+
PrivateTmp=yes
16+
ReadWritePaths=/var/lib/airplanes /etc/airplanes /run
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[Unit]
2+
Description=Sync feeder remote configuration with airplanes.live every 60 seconds
3+
4+
[Timer]
5+
OnBootSec=45s
6+
OnUnitActiveSec=60s
7+
RandomizedDelaySec=30s
8+
Unit=airplanes-config-sync.service
9+
Persistent=true
10+
11+
[Install]
12+
WantedBy=timers.target

scripts/apl-feed.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ source "$APL_FEED_LIB_DIR/apply.sh"
111111
source "$APL_FEED_LIB_DIR/schema.sh"
112112
# shellcheck source=scripts/apl-feed/import.sh
113113
source "$APL_FEED_LIB_DIR/import.sh"
114+
# shellcheck source=scripts/apl-feed/config.sh
115+
source "$APL_FEED_LIB_DIR/config.sh"
114116

115117
main() {
116118
local cmd="${1:-}"
@@ -159,6 +161,10 @@ main() {
159161
shift
160162
dispatch_import "$@"
161163
;;
164+
config)
165+
shift
166+
dispatch_config "$@"
167+
;;
162168
-h|--help|'')
163169
usage
164170
;;

scripts/apl-feed/common.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Usage:
5151
apl-feed diagnostics disable
5252
apl-feed apply [--no-restart] [--lock-timeout SECS]
5353
apl-feed schema
54+
apl-feed config sync [--dry-run] [--no-restart]
5455
apl-feed import legacy-config [--no-restart] <path>
5556
apl-feed backup <file>
5657
apl-feed restore <file>

0 commit comments

Comments
 (0)