Skip to content

loader: detect unsupported compose-file attributes - #927

Merged
ndeloof merged 3 commits into
compose-spec:mainfrom
glours:feat/unsupported-attributes-loader-option
Sep 8, 2026
Merged

ndeloof merged 3 commits into
compose-spec:mainfrom
glours:feat/unsupported-attributes-loader-option

Conversation

@glours

@glours glours commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Adds an opt-in Options.UnsupportedAttributesCheck to the loader,
combining two rule sets over one walk of the model:

  • Denylist (Patterns / WithUnsupportedAttributesCheck):
    caller-supplied tree.Path patterns for attributes known not to be
    honored, with an optional value predicate (e.g. ports[].mode: host).
  • Allowlist (Supported / WithSupportedAttributes): fail-closed —
    declare what the runtime supports, via schema.AttributePaths() minus
    what's unimplemented. Anything else is reported, including attributes
    the spec adds later. x-* extensions are always exempt.

New tree.Matcher (Matches/MayContain) backs the allowlist matching.

Groundwork for docker/compose#14196, replacing its hand-maintained
blocklist (docker/compose#13150)

docker/compose currently hand-maintains a blocklist of compose-file
attributes it accepts but doesn't honor outside Swarm mode (deploy.mode,
credential_spec, label_file, ports[].mode: host, cluster volumes, ...).
Any new attribute compose-spec adds falls through silently until someone
remembers to add a check downstream.

WithUnsupportedAttributesCheck lets a caller supply tree.Path patterns
(with an optional value predicate for cases like ports[].mode) and get
every match reported once, after loading. compose-go has no built-in
notion of "unsupported" — the pattern list stays entirely caller-supplied.

Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
…ributes check

Deny patterns alone reproduce the problem they solve: every attribute
the specification gains later falls through silently until someone adds
a check. This layers the complementary allowlist onto
UnsupportedAttributesCheck, sharing its walk and report:

- Supported (or the composable WithSupportedAttributes option) declares
  the attribute paths the runtime implements; anything matching none of
  them is reported alongside the deny-pattern findings. Extension keys
  (x-*) and everything under them are exempt from this rule set (deny
  patterns still apply below them).

- schema.AttributePaths derives the complete attribute-path inventory
  from the embedded JSON schema (pattern-keyed mappings as '*',
  sequence items as '[]', $ref cycles terminated, '^x-' pattern
  properties excluded, since a wildcard there would blanket-accept
  every undeclared sibling). A runtime builds its declaration by
  removing what it does not implement from the full specification.

- tree.Matcher gives Path pattern sets a first-class matching API:
  exact Matches — declaring a path accepts that node only, so removing
  one leaf reliably surfaces it — plus MayContain for walkers that must
  know when a declared attribute lives deeper.

Matching stays exact by design: subtree removal reports once at its
root, leaf removal reports each leaf, and declared siblings keep the
descent open.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
loader: fail-closed allowlist screening on top of the unsupported-attributes check
@glours glours changed the title loader: add WithUnsupportedAttributesCheck loader option loader: detect unsupported compose-file attributes Sep 8, 2026

@ndeloof ndeloof left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Deny patterns for the value-dependent cases, schema-derived allowlist for fail-closed exhaustiveness — one walk, one report. CI green, combined-usage covered by tests.

@ndeloof
ndeloof merged commit cda1852 into compose-spec:main Sep 8, 2026
15 checks passed
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