Prepare private dispatcher queue on Kubernetes fsGroup volumes
All checks were successful
CI Smoke / host-smoke (push) Successful in 1s
CI Smoke / container-smoke (push) Successful in 2s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
tegwick 2026-10-05 00:05:35 +02:00
parent c69c4c6f2c
commit 1321361d85
4 changed files with 81 additions and 5 deletions

View file

@ -65,3 +65,9 @@ Live observation: State Hub's API Service selects app=state-hub. This worker
does not carry that label, so it cannot enter the API endpoints. At inspection
there were no other State Hub NetworkPolicies; recheck effective selection before
activation. Its own policy allows only DNS and the exact intake peer on 8081.
The approved Kubernetes deployment prepares the private queue with a non-root
init container using the identical image. It removes inherited setgid only on
an empty, owned 2700 directory and otherwise requires 0700. It never changes
existing nonempty evidence custody. This covers local-path fsGroup behavior
that a plain Docker volume does not reproduce.

View file

@ -9,7 +9,7 @@
"name": "state-hub-memo-dispatch",
"namespace": "state-hub",
"annotations": {
"state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required"
"state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover"
}
},
"spec": {
@ -31,7 +31,7 @@
"name": "state-hub-memo-dispatch",
"namespace": "state-hub",
"annotations": {
"state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required"
"state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover"
}
},
"spec": {
@ -131,6 +131,42 @@
]
}
}
],
"initContainers": [
{
"name": "prepare-private-queue",
"image": "forgejo.coulomb.social/coulomb/state-hub-memo-dispatch@sha256:410fb6b6c9fd7a7ee0b63d727fd3249fb3ae13943421d6a5ce88b7ad2520bd2f",
"command": [
"python",
"-c",
"import os, stat\np='/data/private'\ntry:\n os.mkdir(p, 0o700)\nexcept FileExistsError:\n pass\nfd=os.open(p, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)\ntry:\n info=os.fstat(fd)\n if info.st_uid != os.getuid():\n raise SystemExit('queue owner refused')\n mode=stat.S_IMODE(info.st_mode)\n if mode == 0o2700 and not os.listdir(fd):\n os.fchmod(fd, 0o700)\n elif mode != 0o700:\n raise SystemExit('queue mode refused')\nfinally:\n os.close(fd)\n"
],
"securityContext": {
"allowPrivilegeEscalation": false,
"readOnlyRootFilesystem": true,
"capabilities": {
"drop": [
"ALL"
]
}
},
"resources": {
"requests": {
"cpu": "5m",
"memory": "24Mi"
},
"limits": {
"cpu": "100m",
"memory": "96Mi"
}
},
"volumeMounts": [
{
"name": "queue",
"mountPath": "/data"
}
]
}
]
}
}
@ -143,7 +179,7 @@
"name": "state-hub-memo-dispatch",
"namespace": "state-hub",
"annotations": {
"state-hub.coulomb.social/admission": "proposal; STATE-WP-0096 / INFD-WP-0007 approved rollout required"
"state-hub.coulomb.social/admission": "approved; INFD-WP-0007 cutover"
}
},
"spec": {

View file

@ -124,3 +124,26 @@ def test_transport_suppresses_proxy_redirect_and_oversized_response(monkeypatch)
transport('POST',origin+'/v1/memos',{}, {})
finally:
server.shutdown();server.server_close();thread.join(timeout=2)
def test_kubernetes_queue_init_handles_setgid_without_taking_over_data(tmp_path):
manifest = json.loads((Path(__file__).parents[1] / 'deploy/informed-decision/dispatcher.candidate.json').read_text())
pod = next(item for item in manifest['items'] if item['kind'] == 'Deployment')['spec']['template']['spec']
init = pod['initContainers'][0]
assert init['image'] == pod['containers'][0]['image']
tmp_path.chmod(0o2770)
private = tmp_path / 'private'
code = init['command'][2].replace('/data/private', str(private))
def run():
return subprocess.run([sys.executable, '-c', code], capture_output=True).returncode
assert run() == 0
assert stat.S_IMODE(private.stat().st_mode) == 0o700
retained = private / 'retained'
retained.write_text('existing evidence')
assert run() == 0
private.chmod(0o2700)
assert run() != 0 # Existing nonempty custody is never repaired silently.
retained.unlink()
assert run() == 0 # Empty directory left by the initial failed startup.
private.chmod(0o755)
assert run() != 0

View file

@ -8,7 +8,7 @@ status: active
owner: codex
topic_slug: netkingdom
created: "2026-10-04"
updated: "2026-10-04"
updated: "2026-10-05"
related: [INFD-WP-0005, INFD-WP-0007]
state_hub_workstream_id: "4cca4a91-3b21-51f0-a61f-902ccb1289c6"
---
@ -53,7 +53,7 @@ caller identity.
```task
id: STATE-WP-0096-T03
status: todo
status: progress
priority: high
state_hub_task_id: "1aeb4da7-5411-5634-ae6a-2e4bf0e8738b"
```
@ -85,3 +85,14 @@ Final Forgejo image 410fb6b (source 4a59b23) passed five installed-container
checks and Trivy HIGH/CRITICAL scan (zero findings). Owner tests: 28 passed.
Cross-service suite: 663 passed, one skipped. Both projected audiences and final
image pin passed server dry-run. Receipts: docs/evidence/2026-10-04-memo-dispatch/.
## Approved native cutover — 2026-10-05
Founder approved the cutover (State Hub decision d2eaa2e9-6d11-4676-a07f-e3b7e59a88e3).
The worker was deployed by a pinned manual Argo application. Native startup
exposed inherited setgid on the newly created private queue (2700 instead of
0700). A same-image, non-root init container normalizes only an empty owned
2700 directory; existing nonempty or unsafe custody fails closed. Regression
coverage exercises first start under setgid, restart preservation, the empty
failed-start repair, and rejection of nonempty or world-readable custody.
Human acceptance remains pending.