feat(infrahub-enterprise): add an OpenShift values overlay
Problem
OpenShift's default restricted-v2 SCC rejects a pod that pins runAsUser, runAsGroup or fsGroup outside the range allocated to the namespace, and assigns a uid from that range itself. Every uid this chart ships falls outside it: 1000 for Infrahub and Prefect, 7474 for Neo4j, 1001 for the Bitnami sub-charts.
Change
charts/infrahub-enterprise/values.openshift.yaml clears them all, and is layered after a config preset:
helm install infrahub-enterprise ... -f values.medium.yaml -f values.openshift.yaml
Two things are worth calling out.
The clearing has to come from a values file. --set <key>=null is ignored by Helm 3 (it keeps the chart default); a null inside a -f file removes the key on both Helm 3 and Helm 4. Overriding a security context with {} never works on either version, because Helm merges maps and the defaults survive. Helm 3 also prints a cannot overwrite table with non table warning per cleared block — cosmetic, the block is still dropped.
Clearing the uids is not sufficient on its own. The Infrahub image owns /prom_shared and /opt/infrahub/git as uid 1000 with mode 0755, so an arbitrary uid can write to neither: prometheus_client cannot create its multiprocess metric files and gunicorn exits with Worker failed to boot, and the task worker cannot clone repositories. The overlay redirects both onto storage the SCC's fsGroup makes writable. The durable fix belongs in the image (g+w on those two paths), which would let the overlay shrink back to just the uid clearing.
Testing
Two manual-marked e2e modules; neither runs in CI, where a second enterprise stack would double the job.
test_infrahub_enterprise_openshift.py deploys the overlay together with openshift-scc-simulation.yaml, which stands in for the SCC's mutation (arbitrary uid, gid 0, matching fsGroup). Without it a vcluster leaves every container on its image's own uid — root for Neo4j and the Bitnami images, which Neo4j refuses to start as — a configuration OpenShift cannot produce.
uv run pytest -v -m "enterprise or manual" tests/e2e/test_infrahub_enterprise.py tests/e2e/test_infrahub_enterprise_openshift.py
4 passed in 147s
- the unchanged enterprise chart still deploys and passes its SDK round-trip
- rendered with the overlay, no workload pins a uid/gid
- every pod runs as the assigned uid, and the stack passes the SDK round-trip under it
Rendering was checked under both Helm 3.19 and Helm 4.1, across all five config presets, with infrahub-backup and infrahub-mcp enabled.
test_infrahub_upstream_playwright.py runs Infrahub's own pytest-playwright suite against this deployment instead of the testcontainers stack it boots by default, so the browser flows are exercised on the OpenShift configuration. With INFRAHUB_ADDRESS set the suite skips its container and no-ops its data fixtures, so the chart's demo-data Job supplies the dataset instead.
uv run pytest -v -s -m manual tests/e2e/test_infrahub_upstream_playwright.py
upstream suite (infrahub-v1.11.0): 272 tests, 0 failed, 0 flaky
253 passed, 19 skipped, 3 deselected
The 19 skips are upstream's own fixmes. Three specs are deselected, each with its reason recorded beside it:
repository/test_repository_objects.py(2 specs) registers a repository athttps://github.com/opsmill/infrahub-demo-edge.git. Upstream that URL is free, because its fixture registers demo-edge from a local path the compose stack serves; the chart's Job has no local remote and registers the public URL, and Infrahub enforces uniqueness on a repository'slocation. Every other repository-derived spec — artifacts, proposed changes, CoreGraphQLQuery, breadcrumb — passes against the Job's registration.- one dropdown spec ends on a
Cancelclick that is ambiguous while the inline creation form dismisses; every functional assertion in it passes first.
Two settings ride along with the deployment for this run. The demo-data Job's backoffLimit goes to 20 — this looks like a real chart weakness: the Job starts with the release and every attempt fails until the API answers, and the chart's default of 4 left no margin, with 3 attempts burnt before the first success on every run here. And the server Service becomes a LoadBalancer, because a real browser opens more concurrent connections than a kubectl port-forward tunnel survives.
Known gap
The upgrade Job reuses infrahubServer.infrahubServer.env, so it picks up the /tmp redirect, but its template supports no extraVolumes — if infrahub upgrade writes to /opt/infrahub/git it cannot be patched from values. That needs a chart change, not an overlay.
🤖 Generated with Claude Code