Skip to content

Feature-contributed mounts skip variable substitution — ${devcontainerId} reaches Docker literally #52

Description

@bilby91

Symptom

Container create fails when a feature contributes a mount whose source uses a substitution variable. Observed with the docker-in-docker feature, which declares:

"mounts": [{
  "source": "dind-var-lib-docker-${devcontainerId}",
  "target": "/var/lib/docker",
  "type": "volume"
}]

Docker daemon rejects the create:

create dind-var-lib-docker-${devcontainerId}: "dind-var-lib-docker-${devcontainerId}" includes invalid characters for a local volume name, only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed.

The literal ${devcontainerId} reaches ContainerCreate because it was never substituted.

Root cause

  1. config/resolve.go:190substituteAll runs as part of ResolveBytes. This correctly resolves ${devcontainerId} in the user's devcontainer.json mounts.
  2. up.go:264, up.go:278, up.go:485 — later, applyMetadataMergeconfig.MergeMetadata appends feature-contributed mounts to cfg.Mounts (config/merge_metadata.go:76-81).
  3. No substitution runs after the merge. Feature mount sources keep their literal ${devcontainerId} and flow straight into the ContainerCreate payload.

Same risk exists for any other string field a feature/base-metadata layer can contribute that may include substitution variables (containerEnv, remoteEnv, lifecycle hooks).

Suggested fix

Two shapes:

  • Local fix: in applyMetadataMerge (up.go:897), after MergeMetadata, run a substitution pass over the merged-in fields. Rebuild a SubstitutionContext from cfg.DevcontainerID, cfg.LocalWorkspaceFolder, cfg.ContainerWorkspaceFolder, and the same localEnv ResolveBytes saw.
  • Cleaner: have MergeMetadata accept a SubstitutionContext and substitute as it folds layers in, preserving the invariant that every string in ResolvedConfig is host-substituted.

Leaning toward the second so callers don't have to remember.

Repro

Any devcontainer that depends on the docker-in-docker feature (e.g. dap-workspace-55 in dap-ephraim-sandbox).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions