Skip to content

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

Description

@shrinedogg

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 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

  1. Build a Linux container image from v0.10.4.
  2. 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).
  3. 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

  1. 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.
  2. All call sites in src/main.c pass a NULL runtime parent (L1540, L2453, L2613). The only relocation hook, CBM_TEST_DAEMON_RUNTIME_PARENT (L1265-L1272), is compiled out unless CBM_ENABLE_TEST_SEAMS is 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).
  3. 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.
  4. 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

  1. 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.
  2. Until that lands, document the container contract (sticky root-owned /tmp, euid-owned cache dir) in a deployment guide.
  3. Optional, separate decision: accept group ownership of the cache dir when it matches the process egid, which covers the standard Kubernetes fsGroup pattern.

Related issues

Activity

  1. DeusData commented on Aug 17, 2026

    @DeusData
    Owner

    The supported override you asked for exists since v0.10.5: CBM_RUNTIME_DIR (#1645) relocates the coordination runtime parent for every entry point (MCP server, cli, daemon) in product builds — no compile-time seam involved. Verified live on the POSIX path (identical code Linux/macOS): daemon + cli come up cleanly with the runtime dir under a 0700 directory, and the strictness checks travel with it (owned by you, not world-writable, no allow-ACL — the refusal names the exact ancestor since daac6bd). For the Kubernetes shape specifically: point it at a volume you can hold at 0700 — e.g. an emptyDir mounted at /var/run/cbm with an initContainer or fsGroup arrangement that yields mode 0700 for the runtime user, then CBM_RUNTIME_DIR=/var/run/cbm in the container env. Your repaired-/tmp attempt then also stops mattering: nothing under /tmp is required anymore. If v0.10.5+ still refuses in your k3s setup with that arrangement, please reopen with the refusal line and the mount's effective mode/owner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    windowsWindows-specific issues

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions