Skip to content

fix: set default base image in Dockerfiles and improve syntax handling - #1271

Open
Kaniska244 wants to merge 2 commits into
devcontainers:mainfrom
Kaniska244:invalid-arg-fix
Open

fix: set default base image in Dockerfiles and improve syntax handling#1271
Kaniska244 wants to merge 2 commits into
devcontainers:mainfrom
Kaniska244:invalid-arg-fix

Conversation

@Kaniska244

@Kaniska244 Kaniska244 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Related #1229. Fixes the InvalidDefaultArgInFrom build warning emitted by Docker/BuildKit when building dev containers. The warning is raised whenever a FROM instruction references a build ARG that has no in-scope default value at parse time.

 1 warning found (use docker --debug to expand):
 - InvalidDefaultArgInFrom: Default value for ARG $BASE_IMAGE results in empty or invalid base image name (line 2)
[303440 ms] Start: Run: docker events --format {{json .}} --filter event=start
[303442 ms] Start: Starting container

This warning does not come from the user's project Dockerfile — it originates from the internal Dockerfiles the CLI generates (and the static updateUID.Dockerfile), where FROM referenced _DEV_CONTAINERS_BASE_IMAGE / BASE_IMAGE without a declared default.

Root cause

Two patterns were triggering the linter:

  1. No default on the ARGscripts/updateUID.Dockerfile declared ARG BASE_IMAGE (no default) and then used FROM $BASE_IMAGE.
  2. Shell-style fallback that the linter doesn't credit — the generated feature Dockerfiles used FROM ${_DEV_CONTAINERS_BASE_IMAGE:-scratch}. The ${VAR:-scratch} form is a runtime shell expansion; it is not recognized as an ARG default by the static linter, so the warning persisted even when a global ARG ... = placeholder was declared.

The fix

Declare the base-image ARG with a real default (scratch for the generated files, placeholder for the UID script) immediately before it's used, and reference it plainly as $VAR — the form the linter recognizes as having a valid default.

  • src/spec-configuration/containerFeaturesConfiguration.ts — add ARG _DEV_CONTAINERS_BASE_IMAGE=scratch before the FROM stages in the generated feature base Dockerfile (the FROM lines already reference the ARG directly).
  • src/spec-node/containerFeatures.ts — change the prefix ARG default from placeholder to scratch in both getImageBuildOptions (no-features path) and getFeaturesBuildOptions (features path).
  • scripts/updateUID.Dockerfile — change ARG BASE_IMAGEARG BASE_IMAGE=placeholder.

Behavior is unchanged at build time

The CLI always passes the real image via --build-arg (_DEV_CONTAINERS_BASE_IMAGE=<image>, and BASE_IMAGE=<image> for the UID Dockerfile), so the scratch / placeholder defaults only ever exist to satisfy the static linter and never affect the actual build.

Tests

Added a daemon-free unit test suite in src/test/container-features/generateFeaturesConfig.test.ts (validate generated Dockerfiles avoid InvalidDefaultArgInFrom) that:

  • Introduces a findFromArgsWithoutDefault() helper mimicking the InvalidDefaultArgInFrom rule (flags any ARG used in a FROM without a default declared before it).
  • Asserts the generated feature base Dockerfile declares _DEV_CONTAINERS_BASE_IMAGE with a default, references it directly, and does not use the ${VAR:-default} shell fallback.
  • Asserts scripts/updateUID.Dockerfile declares BASE_IMAGE with a default before FROM.

These run without Docker, so they execute in CI as part of npm test.

Files changed

File Change
src/spec-configuration/containerFeaturesConfiguration.ts Declare ARG _DEV_CONTAINERS_BASE_IMAGE=scratch before FROM
src/spec-node/containerFeatures.ts ARG default placeholderscratch in both build-option paths
scripts/updateUID.Dockerfile ARG BASE_IMAGEARG BASE_IMAGE=placeholder
src/test/container-features/generateFeaturesConfig.test.ts Add InvalidDefaultArgInFrom regression tests

Notes / follow-ups

  • The getImageBuildOptions no-features path is covered indirectly (its ARG default was corrected), but its Dockerfile string is built inline and isn't directly unit-tested. A small follow-up could extract that string into an exported helper to unit-test it the same way.
  • .devcontainer/devcontainer-lock.json shows a trailing-newline-only change; consider reverting that if it's unintentional.

@Kaniska244
Kaniska244 marked this pull request as ready for review July 28, 2026 09:24
@Kaniska244
Kaniska244 requested a review from a team as a code owner July 28, 2026 09:24
});

// returns the names of any ARGs used in a `FROM` that lack a default declared before them.
function findFromArgsWithoutDefault(dockerfile: string): string[] {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not also want to use this for other features?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants