Skip to content

Reject top-level sections indented under services with a clear error - #1583

Open
Thanatos9404 wants to merge 1 commit into
containers:mainfrom
Thanatos9404:reject-misplaced-top-level-sections
Open

Thanatos9404 wants to merge 1 commit into
containers:mainfrom
Thanatos9404:reject-misplaced-top-level-sections

Conversation

@Thanatos9404

Copy link
Copy Markdown

When networks, volumes, secrets or configs is indented under services by mistake, YAML parses the section as a service with that name. podman-compose then fails late with a traceback whose message hides the cause, or does not fail at all:

  • networks (the compose file from the issue): RuntimeError: missing networks: mynet from _parse_compose_file(), although mynet is in the file.
  • volumes: RuntimeError: volume [data] not defined in top level.
  • secrets and configs: podman-compose config accepts the file and prints the section as a service.

Fixes: #1549

With this change, podman-compose config on the file from the issue prints

Error: service `networks` has no `image` or `build`. If it is meant to be the top-level `networks` section, it is indented under `services` by mistake.

and exits with 1, without a traceback (main() already catches PodmanComposeError). The compose file from #552, where both networks and volumes are indented this way, gets the same message.

Which services are reported

A service may legitimately be called networks, volumes, secrets or configs: the Compose schema accepts any service name matching ^[a-zA-Z0-9._-]+$, and Docker Compose rejects the file in the issue because mynet is not a service attribute, not because of the service name. podman-compose has no list of service attributes to check against, so this looks at what a real service needs instead. A service with one of these four names is reported only when it has none of these keys (image and x-podman.rootfs count only as strings):

  • image or build: Docker Compose refuses a service that has neither, apart from the newer provider services that podman-compose does not support (checkConsistency in compose-go: "has neither an image nor a build context specified").
  • extends: the image or build can come from the extended service. The check runs before extends is resolved.
  • x-podman.rootfs: podman-compose runs such a service without an image.

A section moved under services by mistake has build or extends only if one of its entries is itself named that way (a volume called build, say). That case is not detected and fails as before; every other misplaced section is reported, including one with an entry named image, since an entry is a mapping or null rather than a string. A service that Docker Compose accepts under one of these names keeps working, and services with other names are not checked. The only file that stops working is one with a service named like this that has none of the keys above, which podman-compose would run from an image named after the project and service; Docker Compose rejects that file too (apart from provider services, which podman-compose does not support).

The check is a new check_misplaced_top_level_sections(), called in _parse_compose_file() once the compose files are merged, before extends, networks and volumes are resolved.

Tests

New tests/unit/test_misplaced_top_level_sections.py, through _parse_compose_file():

  • the compose file from the issue, verbatim;
  • each of networks, volumes, secrets and configs indented under services, next to a service that uses it;
  • services named networks, volumes, secrets and configs with image, with build, with extends and with x-podman.rootfs, which still parse;
  • a misplaced networks or volumes section with an entry named image, which is still reported;
  • a service named volumes that gets its image from a second compose file, which still parses.

On main, 7 of the 12 tests fail: the misplaced networks cases with RuntimeError: missing networks: ..., the volumes cases with RuntimeError: volume [...] not defined in top level, and secrets and configs because nothing is raised. The 5 tests for real services pass on main as well and guard against rejecting them.

Results on Ubuntu 24.04 (WSL), Python 3.12.3, with requirements.txt and test-requirements.txt installed:

  • python -m unittest discover tests/unit: 509 tests OK (497 on main, also OK).
  • ruff format --check, ruff check, mypy . and pylint podman_compose.py (10.00/10): pass.
  • The config output above was checked with --dry-run, as there is no Podman on this machine, so the integration tests were not run. The change only affects parsing.

Checklist

  • Read CONTRIBUTING.md (one commit, signed off, no fix: prefix)
  • Release note: newsfragments/reject_misplaced_top_level_sections.bugfix
  • Unit tests: tests/unit/test_misplaced_top_level_sections.py
  • Not a new compose feature, so no spec link is needed; the service name pattern is in the Compose schema.

When `networks`, `volumes`, `secrets` or `configs` is indented under
`services` by mistake, YAML turns the section into a service with that
name. podman-compose then failed later with a traceback that hides the
cause, such as `RuntimeError: missing networks: mynet` for the compose
file in the issue, or it accepted a misplaced `secrets` or `configs`
section as a service.

This commit adds check_misplaced_top_level_sections(), which runs in
_parse_compose_file() before `extends` and the networks are resolved.
When a service with one of these names has no `build` or `extends` and
no string `image` or `x-podman.rootfs`, it raises a PodmanComposeError
that names the section and points at the indentation. A service may be
named `networks` and the like, and such a real service has one of these
keys, so it keeps working.

The downside of this rule: a misplaced section with an entry named
`build` or `extends` is not detected and fails as before.

Fixes: containers#1549
Signed-off-by: Yashvardhan Thanvi <yashvt9404@gmail.com>
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.

Unclear error when networks/volumes are accidentally indented under services

1 participant