fix: read YAML the way Docker reads it (1.2 booleans)#62
Merged
Conversation
PyYAML implements YAML 1.1, where a bare on/off/yes/no is a boolean. Docker
parses YAML 1.2, where each is an ordinary string. One difference, two bugs:
environment:
SSL: on -> emitted -e "SSL=true" (docker: -e SSL=on) silent, exit 0
on: 1 -> key resolved to True, refused as a non-string key
-- rejecting a file docker compose runs fine
Neither is repairable downstream: once PyYAML has resolved `on` to True, the
spelling is gone. Fixed at the only place it can be -- the loader. The CLI now
reads YAML with a SafeLoader whose bool resolver matches only true/false, the
YAML 1.2 core schema Docker's parser implements.
The non-string-key rule itself stands and MATCHES Docker, which refuses one too
("non-string key in services.app.environment: 3306"). The architecture doc
claimed the opposite -- that Docker accepts {3306: db} and compose2pod
deliberately diverges. That claim was false and is corrected.
Verified against docker compose config: on/off/yes/no now accepted as keys and
preserved as values; 3306/true still refused as keys, by both.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the last known divergence from
docker compose. Design:planning/changes/2026-07-14.09-yaml-12-booleans.md.One root cause, two bugs
PyYAML implements YAML 1.1, where a bare
on/off/yes/nois a boolean. Docker parses YAML 1.2, where each is an ordinary string.Silent corruption, exit 0:
The application reads
"true"where its author wroteon. Nothing is reported.A working file rejected:
PyYAML resolves the key to the boolean
True, and the string-key rule refuses it. Refusing a file Docker runs is the one direction that must never happen for a drop-in replacement.Neither is repairable downstream: once the loader has turned
onintoTrue, the spelling is gone."on"is not recoverable fromTrue. So it is fixed at the only place it can be — the loader. The CLI now reads YAML with aSafeLoaderwhose boolean resolver matches onlytrue/false: the YAML 1.2 core schema Docker's parser implements.I also had a false claim in the architecture doc
It said rejecting a non-string key was "a deliberate divergence from Docker —
environment: {3306: db}is valid Compose and Docker accepts it."Docker refuses it too:
non-string key in services.app.environment: 3306. The rule was never a divergence; it matches Docker. That paragraph is corrected here. What Docker never sees is a non-stringon:key — because to Docker,onis a string.Verification
Measured against
docker compose configv5.1.2, both axes:on→on,off→off,yes→yes,no→no,true→true,false→false. All six match Docker.on/off/yes/noaccepted (emiton=1);3306:/true:refused — by both.The loader surgery is the risk, so I diffed our loader against plain
yaml.safe_loadacross booleans, ints, floats, nulls, quoted strings, timestamps, octal, anchors and merge keys: the only differences are the intended ones (on/off/yes/no, including where they arrive via an anchor).true/falsestill resolve as booleans;y/nwere already strings in PyYAML and are untouched. The Loader is a genuineSafeLoadersubclass.Scope holds: the core stays stdlib-only (
import compose2podworks with PyYAML absent; onlycli.pytouches yaml), and the JSON path is unchanged — JSON keys are strings by construction.Three existing tests used
on:as their "non-string key" example, which is now a legal string key; they were switched to an int key (3306:), which is non-string under YAML 1.2 and refused by Docker too — so they still test what they claim.650 tests at 100% coverage; integration green against real podman.
🤖 Generated with Claude Code