From 9dfbbf9e760d3a744075ea280c141f04fde95145 Mon Sep 17 00:00:00 2001 From: Alberto Arroyo Raygada Date: Tue, 4 Aug 2026 10:31:31 -0500 Subject: [PATCH] fix(helm): the MCP chart ran the pod as a user that owns none of its corpus (#425) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `src/packages/mcp-server/Dockerfile` creates `evolith` at uid 1001, `chown -R evolith:evolith /repo /app`, and declares `USER evolith`. The chart pinned `runAsUser: 1000`, which overrides the image's USER and lands the process on the base image's `node` user. The symptom is remote from the cause and total. `policy.wasm` ships mode 600 owned by 1001, so at uid 1000 the OPA engine gets EACCES: permission denied, open '.../rulesets/opa/policy.wasm' and dispatch requires BOTH the native and OPA engines to allow. OPA erroring fail-closes, so EVERY `tools/call` returns FORBIDDEN: a deployed MCP server that advertises 51 tools and can execute none. Found by running the `core-integration` robot against a live two-cluster stack for the first time — it is excluded from the default RoboSoft list and had never executed. The pod reported `uid=1000(node)` while the file it could not open was owned by `evolith`. `evolith-core-api` and `evolith-agent-runtime` already pin 1001; this chart was the odd one out, which is why only the MCP surface failed. Verified on the live cluster after the change: the pod reports `uid=1001(evolith)` and the wasm is readable. Not in this change, and separate: the same robot found `/core/evaluate` returning 201 with no gates, and `/assistant/converse` 502 on a 401 from the agent-runtime (a key mismatch in my local wiring, not the product). Both still to be run down. Co-authored-by: Claude Opus 5 --- product/infra/helm/evolith-mcp/values.yaml | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/product/infra/helm/evolith-mcp/values.yaml b/product/infra/helm/evolith-mcp/values.yaml index f9d6749a..5a73928f 100644 --- a/product/infra/helm/evolith-mcp/values.yaml +++ b/product/infra/helm/evolith-mcp/values.yaml @@ -80,11 +80,27 @@ resources: cpu: 500m memory: 256Mi +# 1001, NOT 1000. `src/packages/mcp-server/Dockerfile` creates `evolith` at uid +# 1001, `chown -R evolith:evolith /repo /app`, and declares `USER evolith`. A +# chart that pins 1000 overrides the image's USER and lands the process on the +# base image's `node` user, which owns none of the corpus. +# +# The symptom is remote from the cause and total: `policy.wasm` ships mode 600 +# owned by 1001, so at uid 1000 the OPA engine gets +# `EACCES: permission denied, open '.../policy.wasm'`. Dispatch requires BOTH +# the native and OPA engines to allow, so OPA erroring fail-closes EVERY +# `tools/call` with FORBIDDEN — a deployed MCP server that advertises 51 tools +# and can execute none. Observed 2026-08-04 by the `core-integration` robot +# against a live cluster; the pod reported `uid=1000(node)` while the file it +# could not open was owned by `evolith`. +# +# `evolith-core-api` and `evolith-agent-runtime` already pin 1001; this chart was +# the odd one out. podSecurityContext: runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 + runAsUser: 1001 + runAsGroup: 1001 + fsGroup: 1001 seccompProfile: type: RuntimeDefault @@ -93,7 +109,7 @@ containerSecurityContext: privileged: false readOnlyRootFilesystem: true runAsNonRoot: true - runAsUser: 1000 + runAsUser: 1001 capabilities: drop: - ALL