D39 = B: 09 §3 decision 255 (the security-fix step) + a dated note on decision 13; capability B23; R-1239 closed, R-1240 opened, R-1238 updated (register 186 -> 186); STATUS/CONTEXT; nodes.md (9202 password, Tester 1 DHCP); evidence security-lane-2026-10-23 (controller 0.341.0, global floor 11:24 UTC)
gates / gates (push) Successful in 13m49s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-10-23 13:35:38 +02:00
1 parent 4b9b0af3cb
commit 87dc50743c
37 files changed
+1104 -8

No files matched your search

@@ -0,0 +1,19 @@
{
"app": "plex",
"walk": "security",
"box_walk_version": 1,
"verdict": "inconclusive",
"venue": "box 9202 (drill catalog), the guarded Update",
"from": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"to": {
"plex": "busybox:1.36.1"
},
"why": "the install at FROM did not complete — nothing was tested",
"log": [
"12:26:15 [1] made the drive paths this app requires: ['/mnt/felhom-drives/scratch_hdd/userdata/plex']",
"12:26:15 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['PLEX_CLAIM', 'HDD_PATH']",
"12:26:15 [1] deploy -> 409 {'ok': False, 'error': 'Az alkalmazás adatainak helye egy meghajtó lehet, nem egy mappa a meghajtón belül. Válaszd ezt: "
]
}
@@ -0,0 +1,5 @@
12:26:15 [1] made the drive paths this app requires: ['/mnt/felhom-drives/scratch_hdd/userdata/plex']
12:26:15 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['PLEX_CLAIM', 'HDD_PATH']
12:26:15 [1] deploy -> 409 {'ok': False, 'error': 'Az alkalmazás adatainak helye egy meghajtó lehet, nem egy mappa a meghajtón belül. Válaszd ezt:
12:26:15 [9] verdict inconclusive -> /mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/P2-negative/verdict.json
12:26:15 RESULT inconclusive — the install at FROM did not complete — nothing was tested
@@ -0,0 +1,188 @@
{
"app": "plex",
"walk": "security",
"box_walk_version": 1,
"verdict": "failed",
"venue": "box 9202 (drill catalog), the guarded Update",
"from": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"to": {
"plex": "busybox:1.36.1"
},
"observables_before": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"catalog_images": null,
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"
]
},
"setup_gate_before": {
"browser": {
"status": "302",
"redirect": "https://felhom.enkisfelhom.hu/__gate/start?…"
},
"script": {
"status": "401",
"redirect": null
}
},
"seed": "none",
"seed_why": "the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"drill_commit": "577947198bff",
"sync_waited_s": 4.5,
"badge_before": {
"hu": [
{
"title": "Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.",
"text": "Frissítés elérhető — ma"
}
],
"en": [
{
"title": "A newer version of this app is available. Select the Update button to start it.",
"text": "Update available — today"
}
]
},
"measured_at": "2026-10-23T10:27:24Z",
"update": {
"accepted": true,
"http": "202",
"phases": [
{
"t": 0.0,
"phase": "backing-up",
"label": "Biztonsági mentés készül a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 11.3,
"phase": "safety-dump",
"label": "Adatbázis pillanatkép…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 12.3,
"phase": "pulling",
"label": "Új verzió letöltése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 14.4,
"phase": "copying",
"label": "Az adatok másolása a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 24.7,
"phase": "starting",
"label": "Indítás az új verzióval…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 25.7,
"phase": "verifying",
"label": "Működés ellenőrzése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 327.2,
"phase": "undoing",
"label": "Visszaállítás az előző változatra…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 335.4,
"phase": "undone",
"label": "Visszaállítva az előző változatra",
"updating": false,
"error": null,
"hold": null
}
],
"duration_s": 335.4,
"final_phase": "undone",
"update_error": null,
"hold_reason": null,
"state": "running"
},
"observables_after": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"catalog_images": {
"plex": "busybox:1.36.1"
},
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"
]
},
"badge_after": {
"hu": [
{
"title": "Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.",
"text": "Frissítés elérhető — ma"
}
],
"en": [
{
"title": "A newer version of this app is available. Select the Update button to start it.",
"text": "Update available — today"
}
]
},
"state_after": "running",
"hold_after": null,
"to_digests": {
"plex": "sha256:e0ab27395614a8e1a4fdf84c6bc60ac664915cfdde70c52d030c7728a1c48e14"
},
"why": "the update ended 'undone' (error None, hold None)",
"log": [
"12:26:46 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']",
"12:26:46 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}",
"12:27:06 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}",
"12:27:06 gate: plex is gated — passed as the household (cookie set)",
"12:27:10 [2] setup gate as installed: {'browser': {'status': '302', 'redirect': 'https://felhom.enkisfelhom.hu/__gate/start?…'}, 'script': {'status': '401', 'redirect': None}}",
"12:27:10 [3] seed: none — the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"12:27:11 [5] drill commit 577947198bff: plex plexinc/pms-docker:1.43.4.10903-e5521bd8c -> busybox:1.36.1 (push rc=0)",
"12:27:19 [5] the box's drill mirror now at 57794719",
"12:27:24 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}",
"12:27:24 + 0.0s phase=backing-up label=Biztonsági mentés készül a frissítés előtt… err=None hold=None",
"12:27:35 + 11.3s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None",
"12:27:37 + 12.3s phase=pulling label=Új verzió letöltése… err=None hold=None",
"12:27:39 + 14.4s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None",
"12:27:49 + 24.7s phase=starting label=Indítás az új verzióval… err=None hold=None",
"12:27:50 + 25.7s phase=verifying label=Működés ellenőrzése… err=None hold=None",
"12:32:51 + 327.2s phase=undoing label=Visszaállítás az előző változatra… err=None hold=None",
"12:33:00 + 335.4s phase=undone label=Visszaállítva az előző változatra err=None hold=None"
]
}
@@ -0,0 +1,22 @@
12:26:46 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']
12:26:46 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
12:27:06 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}
12:27:06 gate: plex is gated — passed as the household (cookie set)
12:27:10 [2] setup gate as installed: {'browser': {'status': '302', 'redirect': 'https://felhom.enkisfelhom.hu/__gate/start?…'}, 'script': {'status': '401', 'redirect': None}}
12:27:10 [3] seed: none — the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue
12:27:11 [5] drill commit 577947198bff: plex plexinc/pms-docker:1.43.4.10903-e5521bd8c -> busybox:1.36.1 (push rc=0)
12:27:19 [5] the box's drill mirror now at 57794719
12:27:24 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}
12:27:24 + 0.0s phase=backing-up label=Biztonsági mentés készül a frissítés előtt… err=None hold=None
12:27:35 + 11.3s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None
12:27:37 + 12.3s phase=pulling label=Új verzió letöltése… err=None hold=None
12:27:39 + 14.4s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None
12:27:49 + 24.7s phase=starting label=Indítás az új verzióval… err=None hold=None
12:27:50 + 25.7s phase=verifying label=Működés ellenőrzése… err=None hold=None
12:32:51 + 327.2s phase=undoing label=Visszaállítás az előző változatra… err=None hold=None
12:33:00 + 335.4s phase=undone label=Visszaállítva az előző változatra err=None hold=None
12:33:18 [9] verdict failed -> /mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/P2-negative/verdict.json
12:33:18 RESULT failed — the update ended 'undone' (error None, hold None)
12:33:27 [X] stop -> 200 {'ok': True, 'message': 'Stack plex stop completed'}
12:33:59 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'plex', 'volumes_removed': ['plex_plex_config', 'plex_plex_transcode'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'us
12:34:08 [X] after remove: deployed=False leftovers='/opt/docker/stacks/plex'
@@ -0,0 +1 @@
REFUSED plex: the box walk is 'security' with verdict 'failed' — only a PROVEN `box_walk.py --security` walk is written as a security-fix step
@@ -0,0 +1,9 @@
12:57:50 [5] drill commit f8b700e1d889: plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0 -> plexinc/pms-docker:1.43.4.10903-e5521bd8c (push rc=0)
12:57:58 [5] the box's drill mirror now at f8b700e1
f8b700e1d889
13:00:27 [sync] the badge NEVER caught up to plexinc/pms-docker:1.43.4.10903-e5521bd8c in 148.8s — catalog_images = None
13:00:27 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']
13:00:27 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
13:00:47 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}
13:00:47 gate: plex is gated — passed as the household (cookie set)
deployed True {"pinned_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "catalog_images": null, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"], "docker_inspect": ["plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"]}
@@ -0,0 +1,15 @@
13:01:23 [5] the box's drill mirror now at f46e1bc6
before: {"pinned_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"], "docker_inspect": ["plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"]}
badge before: {'hu': [{'title': 'Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.', 'text': 'Frissítés elérhető — ma'}], 'en': [{'title': 'A newer version of this app is available. Select the Update button to start it.', 'text': 'Update available — today'}]}
night chain -> 202 {'data': {'legs': ['db-dump', 'tier2', 'update-leg']}, 'message': 'started', 'ok': True}
the leg's own lines:
2026/10/23 11:01:34 night_chain.go:108: [INFO] [night-chain] manual run started from 172.18.0.6:46254: [db-dump tier2 update-leg]
2026/10/23 11:02:40 night_chain.go:77: [INFO] [night-chain] update-leg: started
2026/10/23 11:02:40 unattended.go:270: [INFO] [update-leg] started (manual-chain): window 02:30, no step starts at or after 16:17
2026/10/23 11:02:41 unattended.go:316: [INFO] [update-leg] plex: skipped — not_proven
2026/10/23 11:02:41 unattended.go:316: [INFO] [update-leg] privatebin: skipped — stopped_by_household
2026/10/23 11:02:41 unattended.go:248: [INFO] [update-leg] update leg (manual-chain): done=0 undone=0 held=0 failed=0 skipped=2 in 0s [skipped: plex=not_proven, privatebin=stopped_by_household]
2026/10/23 11:02:41 night_chain.go:82: [INFO] [night-chain] update-leg: done in 0s
after: {"pinned_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"], "docker_inspect": ["plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"]}
state running hold None phase None
@@ -0,0 +1,11 @@
13:03:07 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}
13:03:07 + 0.0s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None
13:03:08 + 1.0s phase=pulling label=Új verzió letöltése… err=None hold=None
13:03:16 + 9.2s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None
13:03:26 + 19.5s phase=starting label=Indítás az új verzióval… err=None hold=None
13:03:27 + 20.5s phase=verifying label=Működés ellenőrzése… err=None hold=None
13:03:32 + 25.6s phase=done label=Frissítve err=None hold=None
{"accepted": true, "final_phase": "done", "update_error": null, "hold_reason": null, "state": "running", "duration_s": 25.7}
after: {"pinned_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.5.11029-6bf8af3f0@sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f"], "docker_inspect": ["plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0@sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f running=true restarts=0"]}
13:03:51 gate: plex is gated — passed as the household (cookie set)
identity 200 {"MediaContainer":{"size":0,"apiVersion":"1.2.3","claimed":false,"machineIdentifier":"f34aaee0f637bb3bf168e5b4e5ce2223c7c40c5f","version":"1.43.5.11029-6bf8af3f0"}}
@@ -0,0 +1,227 @@
{
"app": "plex",
"walk": "security",
"box_walk_version": 1,
"verdict": "proven",
"venue": "box 9202 (drill catalog), the guarded Update",
"from": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"to": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"observables_before": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"
},
"catalog_images": null,
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"
]
},
"setup_gate_before": {
"browser": {
"status": "302",
"redirect": "https://felhom.enkisfelhom.hu/__gate/start?…"
},
"script": {
"status": "401",
"redirect": null
}
},
"seed": "none",
"seed_why": "the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"drill_commit": "b5e2406d3b49",
"sync_waited_s": 4.5,
"badge_before": {
"hu": [
{
"title": "Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.",
"text": "Frissítés elérhető — ma"
}
],
"en": [
{
"title": "A newer version of this app is available. Select the Update button to start it.",
"text": "Update available — today"
}
]
},
"measured_at": "2026-10-23T10:36:22Z",
"update": {
"accepted": true,
"http": "202",
"phases": [
{
"t": 0.0,
"phase": "backing-up",
"label": "Biztonsági mentés készül a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 11.3,
"phase": "safety-dump",
"label": "Adatbázis pillanatkép…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 12.3,
"phase": "pulling",
"label": "Új verzió letöltése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 20.5,
"phase": "copying",
"label": "Az adatok másolása a frissítés előtt…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 30.8,
"phase": "starting",
"label": "Indítás az új verzióval…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 31.8,
"phase": "verifying",
"label": "Működés ellenőrzése…",
"updating": true,
"error": null,
"hold": null
},
{
"t": 36.9,
"phase": "done",
"label": "Frissítve",
"updating": false,
"error": null,
"hold": null
}
],
"duration_s": 36.9,
"final_phase": "done",
"update_error": null,
"hold_reason": null,
"state": "running"
},
"observables_after": {
"pinned_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"installed_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"catalog_images": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"live_compose_image_lines": [
"image: plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
],
"docker_inspect": [
"plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0 running=true restarts=0"
]
},
"badge_after": {
"hu": [
{
"title": "Ez az alkalmazás a legfrissebb elérhető változatot futtatja.",
"text": "Naprakész"
}
],
"en": [
{
"title": "This app is running the newest version available.",
"text": "Up to date"
}
]
},
"state_after": "running",
"hold_after": null,
"to_digests": {
"plex": "sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f"
},
"four_observables": {
"pinned": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"installed": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"catalog": {
"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
},
"live_compose": [
"plexinc/pms-docker:1.43.5.11029-6bf8af3f0"
]
},
"setup_gate_after": {
"browser": {
"status": "302",
"redirect": "https://felhom.enkisfelhom.hu/__gate/start?…"
},
"script": {
"status": "401",
"redirect": null
}
},
"memory": {
"soak_s": 600,
"interval_s": 10,
"samples": 60,
"containers": {
"plex": {
"samples": 60,
"anon_peak_bytes": 229015552,
"limit_bytes": 2147483648,
"anon_peak_pct": 10.7,
"cgroup_peak_pct": 11.5,
"oom_kill_delta": 0,
"oom_killed_flag": false,
"restarts_delta": 0,
"running_all_samples": true,
"cgroup": "/sys/fs/cgroup/system.slice/docker-f699bdec12560064fa6bd64884d941915072974ca27d389bcb3e3b917861ac88.scope"
}
},
"oom_kills": 0,
"restarts": 0,
"peak_pct": 10.7
},
"why": "the security-fix step ran on the box through the guarded Update; healthy, TO on all four observables, no undo, no hold, a clean soak",
"log": [
"12:35:39 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']",
"12:35:40 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}",
"12:36:05 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}",
"12:36:05 gate: plex is gated — passed as the household (cookie set)",
"12:36:08 [2] setup gate as installed: {'browser': {'status': '302', 'redirect': 'https://felhom.enkisfelhom.hu/__gate/start?…'}, 'script': {'status': '401', 'redirect': None}}",
"12:36:08 [3] seed: none — the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue",
"12:36:09 [5] drill commit b5e2406d3b49: plex plexinc/pms-docker:1.43.4.10903-e5521bd8c -> plexinc/pms-docker:1.43.5.11029-6bf8af3f0 (push rc=0)",
"12:36:18 [5] the box's drill mirror now at b5e2406d",
"12:36:23 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}",
"12:36:23 + 0.0s phase=backing-up label=Biztonsági mentés készül a frissítés előtt… err=None hold=None",
"12:36:34 + 11.3s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None",
"12:36:35 + 12.3s phase=pulling label=Új verzió letöltése… err=None hold=None",
"12:36:43 + 20.5s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None",
"12:36:53 + 30.8s phase=starting label=Indítás az új verzióval… err=None hold=None",
"12:36:54 + 31.8s phase=verifying label=Működés ellenőrzése… err=None hold=None",
"12:36:59 + 36.9s phase=done label=Frissítve err=None hold=None",
"12:37:18 [7] memory soak 600 s …",
"12:47:24 [7] soak: peak 10.7% of the limit (anon), kills 0, restarts 0"
]
}
@@ -0,0 +1,23 @@
12:35:39 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']
12:35:40 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
12:36:05 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}
12:36:05 gate: plex is gated — passed as the household (cookie set)
12:36:08 [2] setup gate as installed: {'browser': {'status': '302', 'redirect': 'https://felhom.enkisfelhom.hu/__gate/start?…'}, 'script': {'status': '401', 'redirect': None}}
12:36:08 [3] seed: none — the first-run claim needs a token minted at plex.tv by a real Plex account; no account exists for this venue
12:36:09 [5] drill commit b5e2406d3b49: plex plexinc/pms-docker:1.43.4.10903-e5521bd8c -> plexinc/pms-docker:1.43.5.11029-6bf8af3f0 (push rc=0)
12:36:18 [5] the box's drill mirror now at b5e2406d
12:36:23 [6] Update -> 202 {'ok': True, 'data': {'accepted': True, 'completed': False}, 'message': 'Frissítés elindult – az állapot a kártyán követhető'}
12:36:23 + 0.0s phase=backing-up label=Biztonsági mentés készül a frissítés előtt… err=None hold=None
12:36:34 + 11.3s phase=safety-dump label=Adatbázis pillanatkép… err=None hold=None
12:36:35 + 12.3s phase=pulling label=Új verzió letöltése… err=None hold=None
12:36:43 + 20.5s phase=copying label=Az adatok másolása a frissítés előtt… err=None hold=None
12:36:53 + 30.8s phase=starting label=Indítás az új verzióval… err=None hold=None
12:36:54 + 31.8s phase=verifying label=Működés ellenőrzése… err=None hold=None
12:36:59 + 36.9s phase=done label=Frissítve err=None hold=None
12:37:18 [7] memory soak 600 s …
12:47:24 [7] soak: peak 10.7% of the limit (anon), kills 0, restarts 0
12:47:24 [9] verdict proven -> /mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/P2-walk/verdict.json
12:47:24 RESULT proven — the security-fix step ran on the box through the guarded Update; healthy, TO on all four observables, no undo, no hold, a clean soak
12:47:33 [X] stop -> 200 {'ok': True, 'message': 'Stack plex stop completed'}
12:48:05 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'plex', 'volumes_removed': ['plex_plex_config', 'plex_plex_transcode'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'us
12:48:13 [X] after remove: deployed=False leftovers='/opt/docker/stacks/plex'
@@ -0,0 +1 @@
WROTE plex: {'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'} -> {'plex': 'plexinc/pms-docker:1.43.5.11029-6bf8af3f0'} peak 10.7% marks {'files_may_change': False, 'needs_person': None, 'memory_tight': False}
@@ -0,0 +1,21 @@
13:04:15 [X] stop -> 200 {'ok': True, 'message': 'Stack plex stop completed'}
13:04:47 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'plex', 'volumes_removed': ['plex_plex_config', 'plex_plex_transcode'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'us
13:04:56 [X] after remove: deployed=False leftovers='/opt/docker/stacks/plex'
remote: . Processing 1 references
remote: Processed 1 references in total
13:05:05 [5] the box's drill mirror now at 42945c94
13:07:34 [sync] the badge NEVER caught up to plexinc/pms-docker:1.43.4.10903-e5521bd8c in 149.0s — catalog_images = None
13:07:34 [1] required fields filled beyond DOMAIN/SUBDOMAIN: ['HDD_PATH', 'PLEX_CLAIM']
13:07:34 [1] deploy -> 202 {'ok': True, 'message': 'Telepítés elindítva – az állapot a kártyán követhető'}
13:07:54 [1] deployed, controller state=running, pinned={'plex': 'plexinc/pms-docker:1.43.4.10903-e5521bd8c'}
deploy True
13:07:55 gate: plex is gated — passed as the household (cookie set)
remote: . Processing 1 references
remote: Processed 1 references in total
17e0da0 Revert "DRILL plex: compose image line back to 1.43.4 ONLY (the ladder untouched) — a fresh install at FROM for the Part 3 proof; reverted right after"
42945c9 DRILL plex: compose image line back to 1.43.4 ONLY (the ladder untouched) — a fresh install at FROM for the Part 3 proof; reverted right after
f46e1bc DRILL plex: security_fix step 1.43.4 -> 1.43.5 written by upgrade-test.py --write-ladder --security (D39 = B proof)
13:08:04 [5] the box's drill mirror now at 17e0da02
obs {"pinned_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"], "docker_inspect": ["plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"]}
badge {'hu': [{'title': 'Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.', 'text': 'Frissítés elérhető — ma'}], 'en': [{'title': 'A newer version of this app is available. Select the Update button to start it.', 'text': 'Update available — today'}]}
@@ -0,0 +1,17 @@
13:12:03 [5] the box's drill mirror now at 17e0da02
before: {"pinned_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.4.10903-e5521bd8c"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.4.10903-e5521bd8c"], "docker_inspect": ["plex plexinc/pms-docker:1.43.4.10903-e5521bd8c running=true restarts=0"]}
badge before: {'hu': [{'title': 'Újabb változat érhető el ehhez az alkalmazáshoz. A frissítés indításához nyomd meg a Frissítés gombot.', 'text': 'Frissítés elérhető — ma'}], 'en': [{'title': 'A newer version of this app is available. Select the Update button to start it.', 'text': 'Update available — today'}]}
night chain -> 202 {'data': {'legs': ['db-dump', 'tier2', 'update-leg']}, 'message': 'started', 'ok': True}
the leg's own lines:
2026/10/23 11:12:13 night_chain.go:108: [INFO] [night-chain] manual run started from 172.18.0.6:38520: [db-dump tier2 update-leg]
2026/10/23 11:13:15 night_chain.go:77: [INFO] [night-chain] update-leg: started
2026/10/23 11:13:15 unattended.go:279: [INFO] [update-leg] started (manual-chain): window 02:30, no step starts at or after 16:28
2026/10/23 11:13:15 unattended.go:345: [INFO] [update-leg] plex: step pressed plex=plexinc/pms-docker:1.43.4.10903-e5521bd8c → plex=plexinc/pms-docker:1.43.5.11029-6bf8af3f0
2026/10/23 11:13:15 unattended.go:351: [INFO] [update-leg] plex: security fix CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 taken (plex=plexinc/pms-docker:1.43.4.10903-e5521bd8c → plex=plexinc/pms-docker:1.43.5.11029-6bf8af3f0)
2026/10/23 11:13:45 unattended.go:359: [INFO] [update-leg] plex: step ended done after 30.1 s
2026/10/23 11:13:45 unattended.go:325: [INFO] [update-leg] privatebin: skipped — stopped_by_household
2026/10/23 11:13:45 unattended.go:257: [INFO] [update-leg] update leg (manual-chain): done=1 undone=0 held=0 failed=0 skipped=1 in 30s [skipped: privatebin=stopped_by_household] [security fix plex: CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 done]
2026/10/23 11:13:45 night_chain.go:82: [INFO] [night-chain] update-leg: done in 30s
after: {"pinned_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "installed_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "catalog_images": {"plex": "plexinc/pms-docker:1.43.5.11029-6bf8af3f0"}, "live_compose_image_lines": ["image: plexinc/pms-docker:1.43.5.11029-6bf8af3f0@sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f"], "docker_inspect": ["plex plexinc/pms-docker:1.43.5.11029-6bf8af3f0@sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f running=true restarts=0"]}
state running hold None phase done
@@ -0,0 +1,28 @@
2026/10/23 11:13:15 tier2.go:507: [INFO] [backup] Tier 2 copied plex → /mnt/sizing-bench/backups/secondary/plex (2.3 MB, 0 leg(s), 0s)
2026/10/23 11:13:15 update.go:537: [INFO] [stacks] update plex: accepted — guarded update started
2026/10/23 11:13:15 unattended.go:345: [INFO] [update-leg] plex: step pressed plex=plexinc/pms-docker:1.43.4.10903-e5521bd8c → plex=plexinc/pms-docker:1.43.5.11029-6bf8af3f0
2026/10/23 11:13:15 unattended.go:351: [INFO] [update-leg] plex: security fix CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 taken (plex=plexinc/pms-docker:1.43.4.10903-e5521bd8c → plex=plexinc/pms-docker:1.43.5.11029-6bf8af3f0)
2026/10/23 11:13:15 update.go:1378: [INFO] [stacks] update plex: phase checking
2026/10/23 11:13:15 update.go:795: [INFO] [stacks] update plex: ladder — the last step (1 of 1) — the catalog's current definition
2026/10/23 11:13:15 update.go:823: [INFO] [stacks] update plex: precondition met — Tier 2 (second drive) copy from 2026-10-23T11:13:04Z (0s old, limit 24h0m0s)
2026/10/23 11:13:15 update.go:1378: [INFO] [stacks] update plex: phase safety-dump
2026/10/23 11:13:16 update_guard.go:497: [INFO] [backup] update safety dump for plex: the app has no database — nothing to copy (no-op)
2026/10/23 11:13:16 update.go:855: [INFO] [stacks] update plex: safety dump done (0 file(s)) []
2026/10/23 11:13:17 undo.go:287: [INFO] [stacks] update plex: the undo copy will hold 2 named volume(s), 2.8 MiB
2026/10/23 11:13:17 update.go:1378: [INFO] [stacks] update plex: phase pinning
2026/10/23 11:13:17 pin.go:385: [INFO] [stacks] update plex: pin advanced to /opt/docker/felhom-controller/data/catalog-cache/templates/plex/docker-compose.yml (plex=plexinc/pms-docker:1.43.5.11029-6bf8af3f0)
2026/10/23 11:13:17 update.go:1378: [INFO] [stacks] update plex: phase pulling
2026/10/23 11:13:28 update.go:1378: [INFO] [stacks] update plex: phase copying
2026/10/23 11:13:38 update.go:1378: [INFO] [stacks] update plex: phase copying
2026/10/23 11:13:38 undo.go:437: [INFO] [stacks] update plex: copied plex_plex_config → plex_plex_config.pre-update-20261023T111338Z in 520ms
2026/10/23 11:13:38 update.go:1378: [INFO] [stacks] update plex: phase copying
2026/10/23 11:13:39 undo.go:437: [INFO] [stacks] update plex: copied plex_plex_transcode → plex_plex_transcode.pre-update-20261023T111338Z in 465ms
2026/10/23 11:13:39 update.go:1378: [INFO] [stacks] update plex: phase starting
2026/10/23 11:13:39 update.go:1378: [INFO] [stacks] update plex: phase verifying
2026/10/23 11:13:44 update.go:1006: [INFO] [stacks] update plex: healthy after 5s (the app's health check passed)
2026/10/23 11:13:45 update.go:1043: [INFO] [stacks] update plex: DONE in 29s
2026/10/23 11:13:45 image_retention.go:238: [INFO] [stacks] image retention (update of plex): pass over 40 image(s) of [plexinc/pms-docker] — 0 candidate(s), 0 deleted, the rest kept
2026/10/23 11:13:45 unattended.go:359: [INFO] [update-leg] plex: step ended done after 30.1 s
2026/10/23 11:13:45 unattended.go:257: [INFO] [update-leg] update leg (manual-chain): done=1 undone=0 held=0 failed=0 skipped=1 in 30s [skipped: privatebin=stopped_by_household] [security fix plex: CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 do
identity 200 {"MediaContainer":{"size":0,"apiVersion":"1.2.3","claimed":false,"machineIdentifier":"de0d1cd3ffa436835af296505a1e2534be391d1f","version":"1.43.5.11029-6bf8af3f
state running health None
@@ -0,0 +1,27 @@
### root@192.168.0.154
containers=10 unhealthy=0 restarting=0 exited=[] gitea.dooplex.hu/admin/felhom-controller:0.341.0 Up 35 seconds (healthy)
started=2026-10-23T11:15:27.242236608Z
errors=0 info=126
2026/10/23 11:15:28 [INFO] Self-update enabled (check every 6h, auto-update: false, auto-update time: 04:30)
2026/10/23 11:15:28 [INFO] [scheduler] Registered periodic job: selfupdate-check (every 6h0m0s)
2026/10/23 11:15:59 [INFO] [selfupdate] Current version 0.341.0 is up to date
2026/10/23 11:15:29 [INFO] [sync] Initial sync: Sablonok frissítve — a katalógus új változata betöltve; a telepített alkalmazások fájljai nem változt
### hp
containers=24 unhealthy=0 restarting=0 exited=[] gitea.dooplex.hu/admin/felhom-controller:0.341.0 Up 36 seconds (healthy)
started=2026-10-23T11:15:28.047379649Z
errors=0 info=135
2026/10/23 11:15:29 deploy.go:1442: [WARN] [stacks] Stack bookstack: new field ADMIN_PASSWORD (type=password) requires manual configuration
2026/10/23 11:15:29 deploy.go:1442: [WARN] [stacks] Stack calibre-web: new field ADMIN_PASSWORD (type=password) requires manual configuration
2026/10/23 11:15:29 deploy.go:1442: [WARN] [stacks] Stack plex: new field PLEX_CLAIM (type=text) requires manual configuration
2026/10/23 11:15:29 main.go:833: [INFO] Self-update enabled (check every 6h, auto-update: false, auto-update time: 04:30)
2026/10/23 11:15:29 scheduler.go:120: [INFO] [scheduler] Registered periodic job: selfupdate-check (every 6h0m0s)
2026/10/23 11:16:01 updater.go:196: [INFO] [selfupdate] Current version 0.341.0 is up to date
2026/10/23 11:15:30 sync.go:142: [INFO] [sync] Initial sync: Sablonok frissítve — a katalógus új változata betöltve; a telepített alkalmazások fájljai
### felhom-pve
containers=9 unhealthy=0 restarting=0 exited=[] gitea.dooplex.hu/admin/felhom-controller:0.341.0 Up 40 seconds (healthy)
started=2026-10-23T11:15:11.64495822Z
errors=0 info=141
2026/10/23 11:15:12 [INFO] Self-update enabled (check every 6h, auto-update: false, auto-update time: 04:30)
2026/10/23 11:15:12 [INFO] [scheduler] Registered periodic job: selfupdate-check (every 6h0m0s)
2026/10/23 11:15:44 [INFO] [selfupdate] Current version 0.341.0 is up to date
2026/10/23 11:15:13 [INFO] [sync] Initial sync: Sablonok frissítve — a katalógus új változata betöltve; a telepített alkalmazások fájljai nem változt
@@ -0,0 +1,10 @@
2026-10-23T11:24:47Z
HTTP/1.1 303 See Other
Location: /configuration?flash=floor_set
Effective floor: v0.341.0 — source: DB (hub_settings) ; env fallback would be v0.120.0 Save global floor… DB override: v
clear tester-1 Location: /customers/tester-1?flash=floor_set
clear demo-hp Location: /customers/demo-hp?flash=floor_set
clear demo-felhom Location: /customers/demo-felhom?flash=floor_set
2026/10/23 13:15:19 [INFO] managed floor SERVED for tester-1: floor 0.341.0, agent requirement "0.158.1" from declared (golden 0.331.0)
2026/10/23 13:15:20 [INFO] managed floor SERVED for demo-felhom: floor 0.341.0, agent requirement "0.158.1" from declared (golden 0.331.0)
2026/10/23 13:15:20 [INFO] managed floor SERVED for demo-hp: floor 0.341.0, agent requirement "0.158.1" from declared (golden 0.331.0)
@@ -0,0 +1,33 @@
control NEGATIVE (a stub answering 200 over plain http): convicted, as it must (200 -)
== tester-1 (enkicsifelhom.hu): 6 public name(s)
OK control POSITIVE http://felhom.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://felhom.enkicsifelhom.hu/r1033-check?q=1
OK http://files.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://files.enkicsifelhom.hu/r1033-check?q=1
OK http://no-such-name-r1033.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://no-such-name-r1033.enkicsifelhom.hu/r1033-check?q=1
OK http://paperless.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://paperless.enkicsifelhom.hu/r1033-check?q=1
OK http://paste.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://paste.enkicsifelhom.hu/r1033-check?q=1
OK http://wiki.enkicsifelhom.hu/r1033-check?q=1 -> 301 https://wiki.enkicsifelhom.hu/r1033-check?q=1
== demo-hp (enkisfelhom.hu): 14 public name(s)
OK http://arcade.enkisfelhom.hu/r1033-check?q=1 -> 301 https://arcade.enkisfelhom.hu/r1033-check?q=1
OK http://books.enkisfelhom.hu/r1033-check?q=1 -> 301 https://books.enkisfelhom.hu/r1033-check?q=1
OK http://docs.enkisfelhom.hu/r1033-check?q=1 -> 301 https://docs.enkisfelhom.hu/r1033-check?q=1
OK http://felhom.enkisfelhom.hu/r1033-check?q=1 -> 301 https://felhom.enkisfelhom.hu/r1033-check?q=1
OK http://files.enkisfelhom.hu/r1033-check?q=1 -> 301 https://files.enkisfelhom.hu/r1033-check?q=1
OK http://gist.enkisfelhom.hu/r1033-check?q=1 -> 301 https://gist.enkisfelhom.hu/r1033-check?q=1
OK http://ha.enkisfelhom.hu/r1033-check?q=1 -> 301 https://ha.enkisfelhom.hu/r1033-check?q=1
OK http://no-such-name-r1033.enkisfelhom.hu/r1033-check?q=1 -> 301 https://no-such-name-r1033.enkisfelhom.hu/r1033-check?q=1
OK http://papir.enkisfelhom.hu/r1033-check?q=1 -> 301 https://papir.enkisfelhom.hu/r1033-check?q=1
OK http://paste.enkisfelhom.hu/r1033-check?q=1 -> 301 https://paste.enkisfelhom.hu/r1033-check?q=1
OK http://pdf.enkisfelhom.hu/r1033-check?q=1 -> 301 https://pdf.enkisfelhom.hu/r1033-check?q=1
OK http://plex.enkisfelhom.hu/r1033-check?q=1 -> 301 https://plex.enkisfelhom.hu/r1033-check?q=1
OK http://travel.enkisfelhom.hu/r1033-check?q=1 -> 301 https://travel.enkisfelhom.hu/r1033-check?q=1
OK http://wiki.enkisfelhom.hu/r1033-check?q=1 -> 301 https://wiki.enkisfelhom.hu/r1033-check?q=1
== demo-felhom (demo-felhom.eu): 8 public name(s)
OK http://felhom.demo-felhom.eu/r1033-check?q=1 -> 301 https://felhom.demo-felhom.eu/r1033-check?q=1
OK http://files.demo-felhom.eu/r1033-check?q=1 -> 301 https://files.demo-felhom.eu/r1033-check?q=1
OK http://gist.demo-felhom.eu/r1033-check?q=1 -> 301 https://gist.demo-felhom.eu/r1033-check?q=1
OK http://no-such-name-r1033.demo-felhom.eu/r1033-check?q=1 -> 301 https://no-such-name-r1033.demo-felhom.eu/r1033-check?q=1
OK http://prowlarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://prowlarr.demo-felhom.eu/r1033-check?q=1
OK http://radarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://radarr.demo-felhom.eu/r1033-check?q=1
OK http://sonarr.demo-felhom.eu/r1033-check?q=1 -> 301 https://sonarr.demo-felhom.eu/r1033-check?q=1
OK http://torrent.demo-felhom.eu/r1033-check?q=1 -> 301 https://torrent.demo-felhom.eu/r1033-check?q=1
== every public name redirects http -> https
@@ -0,0 +1,3 @@
9201 login ok, /api/stacks 200
login failed: no session cookie
n100 /api/health 200tester-1 (BASE .148) login ok, /api/stacks 200
@@ -0,0 +1,3 @@
tester-1 HTTP/1.1 303 See Other Location: /customers/tester-1?flash=floor_set
demo-hp HTTP/1.1 303 See Other Location: /customers/demo-hp?flash=floor_set
demo-felhom HTTP/1.1 303 See Other Location: /customers/demo-felhom?flash=floor_set
@@ -0,0 +1,74 @@
# D39 = B — the security-fix lane, built and proven (2026-10-23)
Decision: `architecture/09-update-architecture.md` §3 decision 255 (the operator started the D39 brief ~12:00; R-1239
closed). Read before the work: `09` §3 decisions 13–17, 22, 25–26, 52 and §6.4 parts 4–7; `00-capability-map.md` (the
B rows); `13-threat-model.md`; `runbooks/target-selection.md`; `runbooks/publish-train-rules.md`.
Baselines at start: catalog `cde26ab`, controller `32e61d5` (0.340.0, global floor 06:41 UTC — read from the hub before
the first controller commit), felhom.eu `4b9b0af3`. Machines: DooPlex (builds, the writer), demo-hp (9202 scratch; the
release on 9201), Tester 1, demo-felhom (release only). Not touched: ep0, any household box.
## Venue
9202 was pointed at the drill catalog through its LOCAL mirror (`tools/repoint.py`, copied from
`audits/burndown-3-2026-10-17/tools/`, R-992 — no catalog credential on the box): `repoint-drill.txt`. The drill was
reset to live `main` (`cde26ab`) first. 9202's dashboard password is its own (`REHEARSAL_2026_10_20_9202_PW`; the
demo-hp one was refused — five failed logins hit the one-minute limit; `operations/nodes.md` corrected).
## Part 2 — the lane on the old controller (9202 on 0.340.0)
| Step | Result | File |
|---|---|---|
| First try of the negative control | `inconclusive` — the install was refused before anything was made (Plex wants the drive itself as `HDD_PATH`); the walk gained `--value` | `P2-negative-try1-install-refused/` |
| **Negative control**: FROM Plex 1.43.4.10903, TO `busybox:1.36.1` (exits at once) | **`failed`** — backing-up → … → verifying → undoing → **undone** after 335 s; Plex 1.43.4 back | `P2-negative/walk.txt`, `box-verdict-plex.json` |
| The writer on that walk | **refused**: „the box walk is 'security' with verdict 'failed' — only a PROVEN `box_walk.py --security` walk is written" | `P2-negative/writer-refusal.txt` |
| **The walk**: Plex 1.43.4.10903-e5521bd8c → 1.43.5.11029-6bf8af3f0 | **`proven`** — done in 36.9 s, no undo, no hold; pinned = installed = catalog = live compose = running = TO; digest `sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f` (the registry's, re-read by the writer); soak 600 s, 60 samples, anon peak 10.7 % of 2 GiB (cgroup peak 11.5 %), 0 OOM kills, 0 restarts; `seed: none` (Plex's fixture is a `NoRoute` stub) | `P2-walk/` |
| Setup gate (unclaimed Plex) | a browser (`Accept: text/html`) → 302 to `felhom.<domain>/__gate/start`; a script → 401; the same after the update | `P2-walk/box-verdict-plex.json` |
| The writer, into the DRILL only | wrote the `security_fix` entry: ids CVE-2026-96652/-96654/-96655/-96656; advisory Plex's notice `https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319` (the one CISA KEV cites, all four added 2026-10-20 — `cisa-kev-plex2shell.json`, from CISA's own feed); `fixed_in` 1.43.3.10861; the gate accepts it with its WARN | `P2-walk/writer.txt`; drill `f46e1bc` |
| Old controller, night (`POST /api/debug/backup/night-chain`) | **`[update-leg] plex: skipped — not_proven`**; Plex stays 1.43.4 (control: the same leg judged privatebin) | `P2-oldctl/2-night-chain-0.340.0.txt` |
| Old controller, hand press | **done** in 25.7 s; Plex 1.43.5 at the step's digest; `/identity` 200 with 1.43.5 | `P2-oldctl/3-hand-press-0.340.0.txt` |
**How Plex was put back at 1.43.4 for Part 3:** removed through the product (with its data); drill commit `42945c9`
moved ONLY the compose's image line back to 1.43.4 (the ladder line untouched); a fresh install pinned 1.43.4; `17e0da0`
reverted that commit, so the step is the head again and the badge read „Frissítés elérhető" (`P3-newctl/0-…`).
## Part 3 — the new controller (0.341.0-rc.1 on 9202)
Controller `63dcccf` (CI run 2264 / #471 success), image `0.341.0-rc.1` set by hand (9202's self-update is off). The
night chain: `[update-leg] plex: step pressed …`, **`[update-leg] plex: security fix
CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 taken (plex=…1.43.4… → plex=…1.43.5…)`**, `step ended done
after 30.1 s`; the summary line ends `[security fix plex: … done]`. Backup first: the update's precondition met by a
second-drive copy 0 s old, the undo copy of 2 named volumes (2.8 MiB), then the pin. `/identity` 200 with 1.43.5
(`P3-newctl/1-…`, `2-…`).
## Part 4 — release 0.341.0
Image `0.341.0` (`sha256:8aa4ce60…c0bc`) from `63dcccf`; per-box floors on tester-1, demo-hp, demo-felhom (303
`floor_set`); all three ran 0.341.0 by 11:15:31 UTC. Box walk: 0 unhealthy, 0 restarting, 0 exited, 0 `[ERROR]` lines since
the start (126 / 135 / 141 `[INFO]` lines — the control); selfupdate „0.341.0 is up to date"; the https-only check passes
on every public name; the dashboard login works on demo-hp and Tester 1 (`/api/stacks` 200), the N100's `/api/health`
200 (`P4-release/`). **The operator said yes in chat; the global floor 0.341.0 / MinAgent 0.158.1 was set at 11:24:47
UTC** (303 `floor_set`; the running hub's page reads „Effective floor: v0.341.0 — source: DB"); the per-box floors
cleared.
## Teardown (three layers)
- **Machine (9202):** Plex removed through the product (no plex container or volume left); `controller.yaml` restored
byte-identical (`cmp`) and the catalog cache re-cloned from the live catalog (R-615); this run's saved copy deleted
after the `cmp`; image `0.341.0`. 34 older saved copies from earlier sessions stay — filed R-1240. The drill
repository keeps this run's commits as the record.
- **Host (demo-hp):** nothing provisioned.
- **Hub:** the global floor 0.341.0 (the operator's yes); per-box floors cleared.
## Observations
- FILED: R-1240 — 9202 holds 34 saved `controller.yaml` copies with the catalog token.
- FIXED without a row: drill commits never reached a box pointed at the drill's local mirror (`box_walk.refresh_box_mirror`);
two stale catalog tests (9202 address, gate count + missing sibling in the shallow clone); Tester 1's guest moved
`.101` → `.148` and the box walk had it typed (now read from the guest); `operations/nodes.md` (9202's password,
Tester 1's address).
- NOT-A-FINDING: the writer's own engine-major check is redundant with `check_entry` (two layers on purpose; the test
asserts the refusal); `/opt/docker/stacks/plex` keeps the catalog's template files after a removal, as every catalog
app's folder does (72); the demo-hp start WARNs „new field … requires manual configuration" come from code 0.341.0 did
not change; a waiter of mine matched its own command line (a known trap, memory `pgrep-waiter-matches-itself`) and
was stopped.
@@ -0,0 +1,70 @@
{
"catalogVersion": "2026.10.21",
"dateReleased": "2026-10-21T14:04:39.8983Z",
"entries": [
{
"cveID": "CVE-2026-96656",
"vendorProject": "Plex",
"product": "Media Server",
"vulnerabilityName": "Plex Media Server External Control of File Name or Path Vulnerability",
"dateAdded": "2026-10-20",
"shortDescription": "Plex Media Server contains an external control of file name or path vulnerability which can allow an admin user to write arbitrary files that may be executed on load. This vulnerability can be chained with CVE-2026-96652, CVE-2026-96654, and CVE-2026-96655.",
"requiredAction": "Apply mitigations in accordance with vendor instructions, ensuring compliance with CISA\u2019s BOD 26-04 Prioritizing Security Updates Based on Risk (see URL in Notes) guidance and CISA\u2019s \u201cForensics Triage Requirements\u201d (see URL in Notes). Follow applicable BOD 26-04 guidance for cloud services or discontinue use of the product if mitigations are unavailable. Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.",
"dueDate": "2026-10-23",
"knownRansomwareCampaignUse": "Unknown",
"forensicTriage": "Yes",
"notes": "https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319 ; ; BOD 26-04: https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk ; Forensics Triage Requirements: https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk ; https://nvd.nist.gov/vuln/detail/CVE-2026-96656",
"cwes": [
"CWE-73"
]
},
{
"cveID": "CVE-2026-96655",
"vendorProject": "Plex",
"product": "Media Server",
"vulnerabilityName": "Plex Media Server Server-Side Request Forgery (SSRF) Vulnerability",
"dateAdded": "2026-10-20",
"shortDescription": "Plex Media Server contains a server-side request forgery (SSRF) vulnerability that could allow an authenticated user to request arbitrary internal or external addresses via the '/video/:/transcode/universal' path parameter. This vulnerability can be chained with CVE-2026-96652, CVE-2026-96654, and CVE-2026-96656.",
"requiredAction": "Apply mitigations in accordance with vendor instructions, ensuring compliance with CISA\u2019s BOD 26-04 Prioritizing Security Updates Based on Risk (see URL in Notes) guidance and CISA\u2019s \u201cForensics Triage Requirements\u201d (see URL in Notes). Follow applicable BOD 26-04 guidance for cloud services or discontinue use of the product if mitigations are unavailable. Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.",
"dueDate": "2026-11-03",
"knownRansomwareCampaignUse": "Unknown",
"forensicTriage": "No",
"notes": "https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319 ; ; BOD 26-04: https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk ; Forensics Triage Requirements: https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk ; https://nvd.nist.gov/vuln/detail/CVE-2026-96655",
"cwes": [
"CWE-918"
]
},
{
"cveID": "CVE-2026-96654",
"vendorProject": "Plex",
"product": "Media Server",
"vulnerabilityName": "Plex Media Server Improper Neutralization of Encoded URI Schemes in a Web Page Vulnerability",
"dateAdded": "2026-10-20",
"shortDescription": "Plex Media Server contains an improper neutralization of encoded URI schemes in a web page vulnerability that could allow an attacker to call other plugins' functions and supply their own parameters. This vulnerability can be chained with CVE-2026-96652, CVE-2026-96655, and CVE-2026-96656.",
"requiredAction": "Apply mitigations in accordance with vendor instructions, ensuring compliance with CISA\u2019s BOD 26-04 Prioritizing Security Updates Based on Risk (see URL in Notes) guidance and CISA\u2019s \u201cForensics Triage Requirements\u201d (see URL in Notes). Follow applicable BOD 26-04 guidance for cloud services or discontinue use of the product if mitigations are unavailable. Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.",
"dueDate": "2026-10-23",
"knownRansomwareCampaignUse": "Unknown",
"forensicTriage": "No",
"notes": "https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319 ; ; BOD 26-04: https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk ; Forensics Triage Requirements: https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk ; https://nvd.nist.gov/vuln/detail/CVE-2026-96654",
"cwes": [
"CWE-84"
]
},
{
"cveID": "CVE-2026-96652",
"vendorProject": "Plex",
"product": "Media Server",
"vulnerabilityName": "Plex Media Server Server-Side Request Forgery (SSRF) Vulnerability",
"dateAdded": "2026-10-20",
"shortDescription": "Plex Media Server contains a server-side request forgery (SSRF) vulnerability which could allow an attacker using any X-Plex-Token value to include a full URL in the 'protocol' parameter and force the Plex server to POST to the attacker's chosen destination. This vulnerability can be chained with CVE-2026-96654, CVE-2026-96655, and CVE-2026-96656. ",
"requiredAction": "Apply mitigations in accordance with vendor instructions, ensuring compliance with CISA\u2019s BOD 26-04 Prioritizing Security Updates Based on Risk (see URL in Notes) guidance and CISA\u2019s \u201cForensics Triage Requirements\u201d (see URL in Notes). Follow applicable BOD 26-04 guidance for cloud services or discontinue use of the product if mitigations are unavailable. Stakeholders are responsible for evaluating each asset's internet exposure and ensuring adherence to BOD 26-04 patching guidelines.",
"dueDate": "2026-11-03",
"knownRansomwareCampaignUse": "Unknown",
"forensicTriage": "No",
"notes": "https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319 ; ; BOD 26-04: https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk ; Forensics Triage Requirements: https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk ; https://nvd.nist.gov/vuln/detail/CVE-2026-96652",
"cwes": [
"CWE-918"
]
}
]
}
@@ -0,0 +1,33 @@
mirror main cde26ab plex: guide checked against 1.43.5.11029-6bf8af3f0 (every HU + EN label read from the new web client, all equal); CHANGELOG + REPORT for the Plex2Shell move
drill repo main: cde26ab
26: repo_url: file:///opt/docker/felhom-controller/drill-catalog.git
26c26
< repo_url: https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
---
> repo_url: file:///opt/docker/felhom-controller/drill-catalog.git
Traceback (most recent call last):
File "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/tools/repoint.py", line 86, in <module>
{"mirror": mirror, "drill": drill, "restore": restore, "status": status}[sys.argv[1]]()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/tools/repoint.py", line 74, in drill
restart_sync()
~~~~~~~~~~~~^^
File "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/security-lane-2026-10-23/tools/repoint.py", line 64, in restart_sync
w.sync_rescan()
~~~~~~~~~~~~~^^
File "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts/box_walk.py", line 466, in sync_rescan
ctl("POST", "/api/sync")
~~~^^^^^^^^^^^^^^^^^^^^^
File "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts/box_walk.py", line 132, in ctl
sess = open(f"{SC}/sess{os.getpid()}.txt").read().strip()
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: '/tmp/claude-1000/-mnt-5-hdd-felhom-eu-git/63b6c84e-0c09-4657-a160-855d2e4fe326/scratchpad/sc9202/sess3574518.txt'
26: repo_url: file:///opt/docker/felhom-controller/drill-catalog.git
27: sync_interval: 15m
-rw------- 1 root root 1994 Oct 22 14:47 /var/lib/docker/volumes/felhom-controller-data/_data/controller.yaml.pre-seclane1023
mirror main cde26ab plex: guide checked against 1.43.5.11029-6bf8af3f0 (every HU + EN label read from the new web client, all equal); CHANGELOG + REPORT for the Plex2Shell move
cache HEAD cde26ab plex: guide checked against 1.43.5.11029-6bf8af3f0 (every HU + EN label read from the new web client, all equal); CHANGELOG + REPORT for the Plex2Shell move
file:///opt/docker/felhom-controller/drill-catalog.git
@@ -0,0 +1,3 @@
13:25:23 [X] stop -> 200 {'ok': True, 'message': 'Stack plex stop completed'}
13:25:55 [X] remove (with drive data) -> 200 {'ok': True, 'data': {'removed': 'plex', 'volumes_removed': ['plex_plex_config', 'plex_plex_transcode'], 'hdd_paths_removed': [], 'hdd_paths_preserved': [], 'us
13:26:04 [X] after remove: deployed=False leftovers='/opt/docker/stacks/plex'
@@ -0,0 +1,19 @@
RESTORED-IDENTICAL
26: repo_url: https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
2026/10/23 11:26:11 sync.go:344: [WARN] [sync] git.repo_url changed (cache was cloned from file:///opt/docker/felhom-controller/drill-catalog.git, config says https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git) — re-cloning the catalog cache from the configured repository (R-615)
2026/10/23 11:26:11 sync.go:318: [INFO] [sync] Cloning https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git → /opt/docker/felhom-controller/data/catalog-cache
2026/10/23 11:26:13 sync.go:511: [WARN] [sync] immich: catalog definition REFUSED by the allow-list — the app keeps its last good compose, nothing written: the catalog definition of immich asks for container rights the box does not allow: immich-server: bind /mnt/sizing-bench/appdata/immich -> /usr/src/app/upload rw; immich-server: bind /mnt/sizing-bench/userdata/media/photos -> /external/photos ro
2026/10/23 11:26:13 sync.go:535: [INFO] [sync] Updated plex/docker-compose.yml
2026/10/23 11:26:13 sync.go:535: [INFO] [sync] Updated plex/.felhom.yml
2026/10/23 11:26:13 sync.go:261: [INFO] [sync] catalog moved 17e0da02fd61 -> 389859359491 (0 new, 1 stack dir(s) changed)
2026/10/23 11:26:13 sync.go:299: [INFO] [sync] Catalog sync complete
2026/10/23 11:26:13 sync.go:142: [INFO] [sync] Initial sync: Sablonok frissítve — frissítve: plex
26: repo_url: https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
27: sync_interval: 15m
-rw------- 1 root root 1994 Oct 22 14:47 /var/lib/docker/volumes/felhom-controller-data/_data/controller.yaml.pre-seclane1023
mirror main 17e0da02 Revert "DRILL plex: compose image line back to 1.43.4 ONLY (the ladder untouched) — a fresh install at FROM for the Part 3 proof; reverted right after"
cache HEAD 3898593 D39 = B: the security-fix lane — a `security_fix` ladder step (box walk required, bench optional, CVE/GHSA notice), its gates + 8 decoys, the writer (--write-ladder --security), the box venue (box_walk.py --security, drill-mirror refresh); two stale tests fixed
https://gitea.dooplex.hu/admin/app-catalog-felhom.eu.git
@@ -0,0 +1,4 @@
felhom-controller gitea.dooplex.hu/admin/felhom-controller:0.341.0 Up 25 seconds (healthy)
0
removed-identical-save
34
@@ -0,0 +1,25 @@
"""chain.py — press "run tonight's chain now" (POST /api/debug/backup/night-chain, R-705) on the box and quote the update
leg's own lines; then read Plex's four observables. D39 = B proof (felhom.eu audits/security-lane-2026-10-23)."""
import json, re, sys, time
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
import box_walk as w
w.LOG = []
w.login()
w.refresh_box_mirror()
w.sync_rescan("plex", "plexinc/pms-docker:1.43.5.11029-6bf8af3f0", tries=20, delay=6)
print("before:", json.dumps(w.observables("plex")))
print("badge before:", w.badges("plex"))
since = w.guest("date -u +%Y-%m-%dT%H:%M:%SZ").strip()
code, d = w.ctl("POST", "/api/debug/backup/night-chain")
print("night chain ->", code, str(d)[:200])
leg = ""
for _ in range(240):
time.sleep(10)
leg = w.guest("docker logs --since %s felhom-controller 2>&1 | grep -E 'update-leg' | grep -v DEBUG | cut -c1-400" % since)
if re.search(r"update leg .*: done=", leg):
break
print("the leg's own lines:\n" + leg)
time.sleep(10)
print("after:", json.dumps(w.observables("plex")))
st = w.stack("plex")
print("state", st.get("state"), "hold", st.get("hold_reason"), "phase", st.get("update_phase"))
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""repoint.py mirror|drill|restore|status — point a box (scratch 9202; copied from audits/burndown-3-2026-10-17/tools/ for the D39 security lane, 2026-10-23) at the drill catalog WITHOUT a credential (R-992).
WHY A LOCAL MIRROR. `09` §6.5's route needs a catalog credential on the box: the drill repo is private (R-992). This
session could not mint a READ-ONLY one — the Gitea credential on DooPlex is itself a token, and Gitea answers 403 to a
token asking to list or create tokens (measured 2026-10-14) — and the night of 2026-10-06 put the admin WRITE token
into the box's controller.yaml, which this task forbids. The cache-staging workaround of 2026-10-12 does not hold for a
test that lasts days: every sync (and every controller start) re-applies the live catalog over the staged templates
and over the installed apps' compose files (Syncer.copyTemplates, no deployed check).
So the drill catalog is MIRRORED onto the box: a bare git repository inside the controller's own data volume, and
`git.repo_url: file:///opt/docker/felhom-controller/drill-catalog.git`. The controller's sync runs exactly as for a
remote (clone/fetch/reset, the R-615 re-clone on a changed URL); no secret is on the box. DooPlex updates the mirror
from the drill repo with a git bundle (`mirror`). The drill repo on Gitea stays the record.
SC=~/.felhom-tester1 TARGET=tester-1 python3 repoint.py mirror # (re)load the mirror from the drill repo main
... repoint.py drill # save controller.yaml (once), set repo_url to the mirror, restart, sync, rescan
... repoint.py restore # put the saved controller.yaml back (byte-identical), restart, sync, rescan
... repoint.py status
"""
import os, subprocess, sys, time
sys.path.insert(0, "/mnt/5_hdd/felhom.eu/git/app-catalog-felhom.eu/scripts")
import box_walk as w
DRILL = "/mnt/5_hdd/felhom.eu/drill/app-catalog-drill"
VOL = "/var/lib/docker/volumes/felhom-controller-data/_data" # guest path of the controller's data volume
CVOL = "/opt/docker/felhom-controller" # the same, inside the controller container
SAVE = f"{VOL}/controller.yaml.pre-seclane1023"
MIRROR_URL = f"file://{CVOL}/drill-catalog.git"
def status():
print(w.guest(f"""grep -nE 'repo_url|sync_interval' {VOL}/controller.yaml; ls -l {SAVE} 2>&1 | tail -1
docker exec felhom-controller sh -c 'git -C {CVOL}/drill-catalog.git log -1 --format="mirror main %h %s" main 2>&1;
git -C {CVOL}/data/catalog-cache log -1 --format="cache HEAD %h %s" 2>&1; git -C {CVOL}/data/catalog-cache remote get-url origin'"""))
def mirror():
b = "/tmp/drill-seclane1023.bundle"
subprocess.run(["git", "-C", DRILL, "bundle", "create", b, "main"], check=True, capture_output=True)
head = subprocess.run(["git", "-C", DRILL, "rev-parse", "--short", "main"], capture_output=True, text=True).stdout.strip()
ssh = w.ssh_args()
# bundle -> PVE host -> guest -> controller volume; the bare repo is made and fetched BY the controller's own user
subprocess.run(["scp", "-q", "-o", "StrictHostKeyChecking=accept-new"] + (["-J", w._T["jump"]] if w._T["jump"] else [])
+ [b, f"{w._T['ssh']}:{b}"], check=True)
subprocess.run(ssh + [f"pct push {w.GUEST} {b} {VOL}/drill-seclane1023.bundle && rm -f {b}"], check=True)
print(w.guest(f"""set -e
docker exec felhom-controller sh -c 'test -d {CVOL}/drill-catalog.git || git init -q --bare -b main {CVOL}/drill-catalog.git
git -C {CVOL}/drill-catalog.git fetch -q {CVOL}/drill-seclane1023.bundle +main:main && rm -f {CVOL}/drill-seclane1023.bundle
git -C {CVOL}/drill-catalog.git log -1 --format="mirror main %h %s" main'"""))
print("drill repo main:", head)
os.remove(b)
def restart_sync():
w.guest("docker restart felhom-controller >/dev/null")
for _ in range(60):
time.sleep(3)
try:
w.login()
break
except SystemExit:
continue
w.sync_rescan()
time.sleep(3)
print(w.guest("docker logs --since 3m felhom-controller 2>&1 | grep -E '\\[sync\\]' | grep -v DEBUG | tail -8"))
def drill():
print(w.guest(f"""set -e
test -f {SAVE} || cp -p {VOL}/controller.yaml {SAVE}
sed -i -E 's#^(\\s+repo_url: ).*$#\\1{MIRROR_URL}#' {VOL}/controller.yaml
grep -n 'repo_url' {VOL}/controller.yaml; diff {SAVE} {VOL}/controller.yaml || true"""))
restart_sync()
status()
def restore():
print(w.guest(f"""set -e
cp -p {SAVE} {VOL}/controller.yaml
cmp {SAVE} {VOL}/controller.yaml && echo RESTORED-IDENTICAL; grep -n repo_url {VOL}/controller.yaml"""))
restart_sync()
status()
{"mirror": mirror, "drill": drill, "restore": restore, "status": status}[sys.argv[1]]()