#1300·cli

Podman: --userns=keep-id and --security-opt label=disable are never applied on the Docker Compose path

Author: screwyprofCreated Sep 2, 2026Updated Sep 2, 2026

The problem

getPodmanArgs() — which adds --security-opt label=disable and, for a non-root remoteUser, --userns=keep-id — lives in src/spec-node/singleContainer.ts and is typed to DevContainerFromDockerfileConfig | DevContainerFromImageConfig. src/spec-node/dockerCompose.ts contains no podman handling at all, so a compose-based dev container on rootless podman gets neither flag.

Result: with rootless podman, the host user maps to container root, so a workspace bind mount appears as root:0 inside and the non-root remoteUser cannot write to it.

Reproduction

devcontainer CLI 0.87.0, podman 5.8.2 rootless, Linux. Two configs differing only in single-container vs compose, both "remoteUser": "vscode", same base image.

repro-sc/.devcontainer/devcontainer.json

{ "name": "sc", "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "remoteUser": "vscode" }

repro-co/.devcontainer/devcontainer.json + docker-compose.yml

{ "name": "co", "dockerComposeFile": "docker-compose.yml", "service": "app",
  "workspaceFolder": "/workspace", "remoteUser": "vscode" }
services:
  app:
    image: mcr.microsoft.com/devcontainers/base:ubuntu
    command: sleep infinity
    volumes: [ "..:/workspace:cached" ]
devcontainer up --workspace-folder repro-sc --docker-path $(which podman) --docker-compose-path $(which docker-compose)
devcontainer up --workspace-folder repro-co --docker-path $(which podman) --docker-compose-path $(which docker-compose)

--docker-path/--docker-compose-path are explicit only to make podman detection unambiguous; lookupCLIVariant correctly reports Podman in both runs.

Result

podman inspect <sc> --format '{{.HostConfig.UsernsMode}} {{.HostConfig.SecurityOpt}}'
  private  [label=disable]

podman inspect <co> --format '{{.HostConfig.UsernsMode}} {{.HostConfig.SecurityOpt}}'
  (empty)  []

Both workspaces are dev:1000 on the host:

workspace owner inside write as remoteUser
single container vscode:1000 OK
compose root:0 Permission denied

Expected

The compose path should apply the same podman handling as the single-container path — emitting the flags into the generated docker-compose.devcontainer.*.yml override (userns_mode, security_opt) for the primary service.

Related but different

#1004 / #1018 (omit keep-id for root) and #1284 / #1285 (derive the mapping from the remote user's real UID/GID) all concern how getPodmanArgs should behave. This is that the compose path never calls it. Whatever #1285 settles for the mapping should presumably apply to both paths.