From 67fd9bf7532143ace367e133019917c70db78094 Mon Sep 17 00:00:00 2001 From: Daniel Genis Date: Tue, 21 Apr 2026 12:04:39 +0200 Subject: [PATCH] fix(images): use UID 1000 for agent user instead of 1001 UID 1000 is the conventional first non-system user on Linux and avoids conflicts with pre-existing UIDs on the host when using hostPath volumes or bind mounts. The previous choice of 1001 required removing the ubuntu user (UID 1000) which is fragile across base image versions. Changes: - Dockerfile: create agent user with UID/GID 1000, remove ubuntu user first - k8s-workload-service: update securityContext and init container to 1000 This reverts the UID portion of commit 8a7db32 while keeping the alignment between Dockerfile and K8s securityContext. --- apps/api/src/services/k8s-workload-service.ts | 14 +++++++------- images/base.Dockerfile | 8 +++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/apps/api/src/services/k8s-workload-service.ts b/apps/api/src/services/k8s-workload-service.ts index 6cb49c1e..49225610 100644 --- a/apps/api/src/services/k8s-workload-service.ts +++ b/apps/api/src/services/k8s-workload-service.ts @@ -528,14 +528,14 @@ export class K8sWorkloadManager { } // Pod-level security context for StatefulSets — ensures PVC mounts are - // writable by the agent user (UID/GID 1001). fsGroup sets the group owner - // of all files in mounted volumes. UID 1001 matches the `agent` user + // writable by the agent user (UID/GID 1000). fsGroup sets the group owner + // of all files in mounted volumes. UID 1000 matches the `agent` user // created in images/base.Dockerfile and owns /workspace in the image. if (restartPolicy === "Always") { const podSecCtx = new V1PodSecurityContext(); - podSecCtx.fsGroup = 1001; - podSecCtx.runAsUser = 1001; - podSecCtx.runAsGroup = 1001; + podSecCtx.fsGroup = 1000; + podSecCtx.runAsUser = 1000; + podSecCtx.runAsGroup = 1000; podSpec.securityContext = podSecCtx; } @@ -550,7 +550,7 @@ export class K8sWorkloadManager { const initContainers: V1Container[] = []; // For StatefulSets, prepend an initContainer that chowns the home PVC - // mount to UID 1001 (the `agent` user in images/base.Dockerfile). This + // mount to UID 1000 (the `agent` user in images/base.Dockerfile). This // is necessary because some storage classes (docker-desktop's hostpath, // GKE default) don't honor the pod's fsGroup setting, leaving the mount // root-owned and unwritable by the main container. Running chown as @@ -561,7 +561,7 @@ export class K8sWorkloadManager { permInit.name = "home-perm-fix"; permInit.image = spec.image; permInit.imagePullPolicy = spec.imagePullPolicy ?? "IfNotPresent"; - permInit.command = ["sh", "-c", "chown -R 1001:1001 /home/agent && chmod 755 /home/agent"]; + permInit.command = ["sh", "-c", "chown -R 1000:1000 /home/agent && chmod 755 /home/agent"]; const initSec = new V1SecurityContext(); initSec.runAsUser = 0; initSec.runAsGroup = 0; diff --git a/images/base.Dockerfile b/images/base.Dockerfile index 098fb5de..f2f5c767 100644 --- a/images/base.Dockerfile +++ b/images/base.Dockerfile @@ -69,9 +69,11 @@ COPY scripts/optio-gh-wrapper /usr/local/bin/optio-gh-wrapper COPY scripts/optio-glab-wrapper /usr/local/bin/optio-glab-wrapper RUN chmod +x /usr/local/bin/optio-git-credential /usr/local/bin/optio-gh-wrapper /usr/local/bin/optio-glab-wrapper -# Non-root user (UID 1001 to match k8s securityContext) -RUN groupadd -g 1001 agent \ - && useradd -m -s /bin/bash -u 1001 -g 1001 agent \ +# Non-root user (UID 1000 to match k8s securityContext) +# Ubuntu 24.04 ships with 'ubuntu' user at UID 1000 — remove it first +RUN userdel -r ubuntu 2>/dev/null || true \ + && groupadd -g 1000 agent \ + && useradd -m -s /bin/bash -u 1000 -g 1000 agent \ && chown -R agent:agent /workspace USER agent WORKDIR /workspace