You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Linux: no product-build way to relocate the daemon runtime dir off /tmp; Kubernetes emptyDir (0777, no sticky bit) fails the ancestor walk (v0.10.4) #1672
Linux (x64): Kubernetes (k3s, containerd), container image built from this repo
Install channel
Built from source (container image)
Binary variant
standard
What happened, and what did you expect?
Every cbm process (the MCP server, and any cli invocation) exits 1 immediately with:
codebase-memory-mcp: secure CLI coordination could not be created (endpoint)
when /tmp is a Kubernetes emptyDir volume. After repairing /tmp permissions from a privileged init container, the next gate fails with ... (cache-private).
Expected: a supported way to point the coordination runtime directory somewhere the process controls (like CBM_CACHE_DIR does for the cache), or a documented container deployment contract. Note this is a regression for container deployments: the identical pod shape ran 0.9.0 without issue, and the daemon coordination layer introduced in the 0.10 series added these requirements.
Reproduction
Build a Linux container image from v0.10.4.
Run it in Kubernetes as a non-root user (uid 1000, readOnlyRootFilesystem: true), with /tmp backed by an emptyDir volume and CBM_CACHE_DIR backed by a PVC (any provisioner; volume roots are root-owned).
Run any CLI command, e.g. codebase-memory-mcp cli index_repository --repo-path <repo> --mode full --name demo.
Observed: exit 1 with secure CLI coordination could not be created (endpoint). After chmod 1777 /tmp, exit 1 with ... (cache-private).
Root cause
src/daemon/ipc.c (cbm_daemon_ipc_endpoint_new, ~L869): the runtime parent defaults to /tmp on Linux (/private/tmp on macOS). No environment variable is consulted.
posix_directory_parent_secure (src/daemon/ipc.c, ~L1386) accepts a world-writable ancestor only when it is root-owned AND sticky (the standard /tmp pattern). A Kubernetes emptyDir mounts as root:root 0777 WITHOUT the sticky bit, and no pod-spec field can set it (fsGroup only adds group permissions; it never sets S_ISVTX or clears other-write). So the check can never pass on a stock emptyDir.
Second gate: main_build_identity (src/main.c L1236) requires CBM_CACHE_DIR to be owned by the process euid. PVC volume roots are root:root, and fsGroup changes only the group, which the check rejects, so non-root containers fail (cache-private) as well.
Workaround we shipped
A root init container with CAP_CHOWN that runs chmod 1777 /tmp and chown <uid>:<gid> "$CBM_CACHE_DIR" before any cbm process starts. This works, but it is brittle, needs a capability that restricted Pod Security namespaces deny, and is undocumented.
Suggested fix
In product builds, resolve the runtime parent from an environment override (for example CBM_RUNTIME_DIR), or honor XDG_RUNTIME_DIR with a fallback to TMPDIR and then /tmp, running the existing ancestor validation on the resolved path. On Linux, XDG_RUNTIME_DIR (/run/user/<uid>, 0700, user-owned) passes the walk trivially and is the semantically correct home for the socket directory.
Until that lands, document the container contract (sticky root-owned /tmp, euid-owned cache dir) in a deployment guide.
Optional, separate decision: accept group ownership of the cache dir when it matches the process egid, which covers the standard Kubernetes fsGroup pattern.
Version
codebase-memory-mcp 0.10.4(c0bd4bb)Platform
Linux (x64): Kubernetes (k3s, containerd), container image built from this repo
Install channel
Built from source (container image)
Binary variant
standard
What happened, and what did you expect?
Every cbm process (the MCP server, and any
cliinvocation) exits 1 immediately with:when
/tmpis a KubernetesemptyDirvolume. After repairing/tmppermissions from a privileged init container, the next gate fails with... (cache-private).Expected: a supported way to point the coordination runtime directory somewhere the process controls (like
CBM_CACHE_DIRdoes for the cache), or a documented container deployment contract. Note this is a regression for container deployments: the identical pod shape ran 0.9.0 without issue, and the daemon coordination layer introduced in the 0.10 series added these requirements.Reproduction
readOnlyRootFilesystem: true), with/tmpbacked by anemptyDirvolume andCBM_CACHE_DIRbacked by a PVC (any provisioner; volume roots are root-owned).codebase-memory-mcp cli index_repository --repo-path <repo> --mode full --name demo.Observed: exit 1 with
secure CLI coordination could not be created (endpoint). Afterchmod 1777 /tmp, exit 1 with... (cache-private).Root cause
src/daemon/ipc.c(cbm_daemon_ipc_endpoint_new, ~L869): the runtime parent defaults to/tmpon Linux (/private/tmpon macOS). No environment variable is consulted.src/main.cpass a NULL runtime parent (L1540, L2453, L2613). The only relocation hook,CBM_TEST_DAEMON_RUNTIME_PARENT(L1265-L1272), is compiled out unlessCBM_ENABLE_TEST_SEAMSis defined, so product builds cannot relocate the runtime dir. Same gap as No product-build way to relocate the daemon runtime directory when %LOCALAPPDATA% has a capability-SID ACE #1574 (Windows) and CBM_CACHE_DIR ignored; daemon still requires /private/tmp/cbm-daemon-<uid> on macOS #1621 (macOS).posix_directory_parent_secure(src/daemon/ipc.c, ~L1386) accepts a world-writable ancestor only when it is root-owned AND sticky (the standard/tmppattern). A KubernetesemptyDirmounts asroot:root 0777WITHOUT the sticky bit, and no pod-spec field can set it (fsGrouponly adds group permissions; it never sets S_ISVTX or clears other-write). So the check can never pass on a stockemptyDir.main_build_identity(src/main.cL1236) requiresCBM_CACHE_DIRto be owned by the process euid. PVC volume roots areroot:root, andfsGroupchanges only the group, which the check rejects, so non-root containers fail(cache-private)as well.Workaround we shipped
A root init container with
CAP_CHOWNthat runschmod 1777 /tmpandchown <uid>:<gid> "$CBM_CACHE_DIR"before any cbm process starts. This works, but it is brittle, needs a capability that restricted Pod Security namespaces deny, and is undocumented.Suggested fix
CBM_RUNTIME_DIR), or honorXDG_RUNTIME_DIRwith a fallback toTMPDIRand then/tmp, running the existing ancestor validation on the resolved path. On Linux,XDG_RUNTIME_DIR(/run/user/<uid>, 0700, user-owned) passes the walk trivially and is the semantically correct home for the socket directory./tmp, euid-owned cache dir) in a deployment guide.fsGrouppattern.Related issues
CBM_CACHE_DIRignored for relocation)