diff --git a/docs/INSTALLATION_AND_DEPLOYMENT_ARCHITECTURE.md b/docs/INSTALLATION_AND_DEPLOYMENT_ARCHITECTURE.md index 8d6bfcf..d84a54c 100644 --- a/docs/INSTALLATION_AND_DEPLOYMENT_ARCHITECTURE.md +++ b/docs/INSTALLATION_AND_DEPLOYMENT_ARCHITECTURE.md @@ -162,6 +162,9 @@ Ingress acceptance streams generated configuration into Docker-managed volumes before starting the read-only containers. It therefore also works when an Actions job reaches a host or remote Docker daemon through a mounted socket; the drill never assumes that a job-container path is visible to that daemon. +The bounded setup helper writes only generated public configuration as root so +it can initialize a new volume; the actual HAProxy process retains the image's +non-root identity and runs read-only with all capabilities dropped. The manifest contract is [`runtime-distribution-manifest.schema.json`](runtime-distribution-manifest.schema.json), diff --git a/tests/test_managed_ingress_drill.py b/tests/test_managed_ingress_drill.py index 1423891..6bdc840 100644 --- a/tests/test_managed_ingress_drill.py +++ b/tests/test_managed_ingress_drill.py @@ -37,6 +37,7 @@ class ManagedIngressDrillTests(unittest.TestCase): argv = run.call_args.args[0] self.assertIn("type=volume,src=config-volume,dst=/govoplan-config", argv) + self.assertIn("0:0", argv) self.assertNotIn("type=bind", " ".join(argv)) self.assertEqual( ":8080 { respond /health 200 }\n", diff --git a/tools/checks/managed-ingress-drill.py b/tools/checks/managed-ingress-drill.py index 0af19b7..a7cc254 100644 --- a/tools/checks/managed-ingress-drill.py +++ b/tools/checks/managed-ingress-drill.py @@ -64,6 +64,8 @@ def _write_volume_file( "run", "--rm", "--interactive", + "--user", + "0:0", "--mount", f"type=volume,src={volume},dst=/govoplan-config", "--entrypoint",