You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
Record each installed feature's applied options (after defaults) in its label entry, alongside the resolvedRef and dependsOn it already carries.
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.
Labels that don't record options keep the current permissive match. Under StrictFeatureVersionMatch they are rejected.
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.
Activity
docs(features): record the baked match's option gap for dependencies
docs(features): record the baked match's option gap for dependencies
fix(features): never take a dependsOn dependency from the base image
bilby91 commentedon Nov 5, 2026
Since #151 (4811e0a), dependencies pulled in through
dependsOnare 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.feat(features): install features reachable only through dependsOn (#151)