Skip to content

fix(docker): give the Go runtime user a writable HOME - #3161

Open
teemow wants to merge 1 commit into
kagent-dev:mainfrom
giantswarm:upstream/go-runtime-writable-home
Open

teemow wants to merge 1 commit into
kagent-dev:mainfrom
giantswarm:upstream/go-runtime-writable-home

Conversation

@teemow

@teemow teemow commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Problem

The Go runtime image (go/Dockerfile, used for the golang-adk and controller images) runs as uid 65532, which has no /etc/passwd entry. Its HOME is therefore /, owned by root. The bash tool's commands inherit the runtime's HOME, so every tool an agent runs that writes a per-user file fails: git config --global, and CLIs that create $HOME/.config on start. The GitLab CLI is one; it creates its config directory on every command, --version included.

Reproduction against the current image:

$ docker run --rm --entrypoint sh <golang-adk image> -c 'id; echo $HOME; mkdir -p "$HOME/.config"; git config --global user.name x'
uid=65532 gid=65532 groups=65532
/
mkdir: can't create directory '//.config': Permission denied
error: could not lock config file //.gitconfig: Permission denied

With glab added to the image, every command fails the same way:

failed to read configuration:  failed to create config directory: mkdir /.config: permission denied

Change

go/Dockerfile, final stage:

  • uid 65532 gets a passwd entry, user and group kagent (gid 65532), with /home/kagent as its home, created by adduser and owned by the user.
  • ENV HOME=/home/kagent, so a runtime that does not derive HOME from passwd (a Substrate actor takes its environment from the image's ENV and the template, not from passwd) hands the same home to the runtime and its commands.

The uid and gid, the working directory, the entrypoint and the existing directories (/skills, /plugins, /data) are unchanged. The controller image built from the same Dockerfile gets the same home, which it does not use.

Verification

The final stage's new steps on alpine:3.24, run as 65532:65532:

uid=65532(kagent) gid=65532(kagent) groups=65532(kagent)
HOME=/home/kagent
drwxr-sr-x    2 kagent   kagent        4096 /home/kagent
kagent:x:65532:65532::/home/kagent:/sbin/nologin
$ mkdir -p "$HOME/.config" && touch "$HOME/.config/probe" && echo ok
ok
$ git config --global user.name x && git config --global user.name
x

Written by an agent.

The Go runtime image (the golang-adk and controller images) runs as uid
65532, which has no /etc/passwd entry, so HOME is / and owned by root.
The bash tool's commands inherit that HOME, and any tool that writes a
per-user file fails: git config --global, and CLIs that create
$HOME/.config on start, such as glab:

  mkdir /.config: permission denied

The image now gives uid 65532 a passwd entry (user and group kagent)
with /home/kagent as its home, created and owned by it, and sets
HOME=/home/kagent, so a runtime that does not derive HOME from passwd
gets it too. The uid, gid, working directory and entrypoint are
unchanged.

Signed-off-by: Timo Derstappen <teemow@gmail.com>
@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant