pin-extension-version

disallow a “customizations.vscode.extensions” entry without an explicit pinned version

Category
reproducibility
Applies to
devcontainer
Platforms
vscode, codespaces

Why

An extension ID on its own installs whatever the marketplace publishes at the moment the container is created, so two developers on the same devcontainer.json can end up with different formatters, linters, or language server versions — and an extension update can change the environment without any commit. Appending a version (publisher.name@1.2.3) makes the editor tooling as pinned as the rest of the image. publisher.name@prerelease is reported as well: it follows the newest pre-release build.

An entry without a version is not reported when another entry in the same list pins the same extension ID, since the version is resolved per ID. That is how to pin an extension a Feature or the base image contributes, which --merge folds into this list: list the ID again with the version you want.

Bad

{
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "customizations": {
    "vscode": {
      "extensions": ["golang.go"]
    }
  }
}

Good

{
  "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
  "customizations": {
    "vscode": {
      "extensions": ["golang.go@0.50.0"]
    }
  }
}

References