Skip to content

Pre-baked feature match ignores options #154

Open

Description

@bilby91

Gap

markAlreadyInstalled / bakedFeature treat a feature in the base image's devcontainer.metadata label as satisfying a request when its id and version match (feature.Matches), plus, since #153, its recorded artifact. The options the request asks for are never compared with the ones the image was built with.

So a request for ghcr.io/x/b:1 with {"flavor": "spicy"} is satisfied by a base image that installed b with its defaults. The requested options are silently not applied. This has been true for declared features since the pre-baked fast path was added. With #151 it also applies to features pulled in through dependsOn, which the DAP review flagged there (dap-finding 3903).

Why it isn't a one-line fix

  • The label doesn't record the options a feature was installed with.
  • It doesn't carry the feature's option schema either, so the defaults can't be applied to the request before comparing. Without that, {} and {"flavor": "plain"} would compare unequal.
  • Labels written before options are recorded can't be checked at all. Rejecting them would make every existing pre-baked image reinstall its features on the next Up. Accepting them keeps today's behaviour.

Proposed

  1. Record each installed feature's applied options (after defaults) in its label entry, alongside the resolvedRef and dependsOn it already carries.
  2. In the baked match, apply the feature's defaults to the request and compare it with the recorded options. A baked feature whose options differ is fetched and installed as usual.
  3. Labels that don't record options keep the current permissive match. Under StrictFeatureVersionMatch they are rejected.

Follow-up to #151 / #153.

Activity

  1. bilby91 commented on Nov 5, 2026

    @bilby91
    MemberAuthor

    Since #151 (4811e0a), dependencies pulled in through dependsOn are never taken from the base image, because this match can't verify their options. Once this issue adds option matching, dependencies() can go back to reusing a baked dependency whose recorded options match. That restores the fast path for pre-baked images whose features have dependencies.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions