Skip to content

fix: accept Compose's 'host=ip' separator in extra_hosts#59

Merged
lesnik512 merged 2 commits into
mainfrom
fix/extra-hosts-equals-separator
Jul 14, 2026
Merged

fix: accept Compose's 'host=ip' separator in extra_hosts#59
lesnik512 merged 2 commits into
mainfrom
fix/extra-hosts-equals-separator

Conversation

@lesnik512

Copy link
Copy Markdown
Member

Stacked on #58 (it shares the extra_hosts normalizer). Design: planning/changes/2026-07-14.06-extra-hosts-equals-separator.md.

The bug: silent corruption, exit 0

Compose documents extra_hosts list entries as host=ip and also accepts the legacy host:ip. compose2pod only ever split on :, so the documented form was accepted by the gate and then mangled:

extra_hosts:
  - "somehost=162.242.195.82"      # Compose's own documented form
podman pod create ... --add-host "somehost=162.242.195.82:"

The whole string became the hostname; the address came out empty. An entry with no separator at all (- "no-separator") had the same face — accepted, emitted as --add-host "no-separator:".

The fix

keys.split_extra_host is the single reader shared by every site that parses an entry — the gate, the emitter, and the extends merge — so they cannot disagree about where an entry divides.

= wins when present, and that disambiguation is the crux: an IPv6 address is full of colons, so splitting on the first one would tear it apart. myhostv6=::1('myhostv6', '::1'). The colon form still splits on the first colon, so myhost:::1 keeps working. An entry with neither separator now raises instead of emitting a broken flag.

A regression I introduced, and caught

The first pass re-split every entry — including mapping-form ones — because _add_host_flags joined {host: addr} into "host:addr" and then re-parsed it. With = now winning, a mapping value containing an = re-divided at the wrong character:

extra_hosts: {somehost: "weird=address"}
→ --add-host "somehost:weird:address"     # host AND address wrong, exit 0

That is the exact corruption class this PR exists to close, reintroduced one layer up. Round-tripping structured data through a string is the flaw: the mapping form arrives already divided and must never be joined and re-parsed.

keys.extra_host_entries now yields (host, address) pairs from either form — the mapping straight through, the list via split_extra_host. extra_host_pairs had no other caller and is deleted.

Verification

Every form emits identical flags: host=ip, host:ip, and mapping all produce --add-host "somehost:162.242.195.82". IPv6 survives both separators. Mapping values containing = are preserved. Conflict detection, ${VAR} interpolation, and the mapping form's Docker-style boolean normalization all unchanged.

593 tests at 100% coverage; integration green against real podman.

🤖 Generated with Claude Code

Base automatically changed from fix/extends-merge-policy to main July 14, 2026 16:11
Compose documents extra_hosts list entries as `host=ip` and also accepts the
legacy `host:ip`. compose2pod only ever split on ':', so the documented form
was accepted by the gate and then silently mangled:

  extra_hosts: ["somehost=162.242.195.82"]
  -> podman pod create ... --add-host "somehost=162.242.195.82:"

The whole string became the hostname and the address came out empty. An entry
with no separator at all had the same face: accepted, emitted as
`--add-host "no-separator:"`.

keys.split_extra_host is now the one reader every site shares -- the gate, the
emitter, and the extends merge -- so they cannot disagree about where an entry
divides. '=' wins when present, because an IPv6 address is full of colons and
splitting on the first one would tear it apart; the colon form still splits on
the first colon only, so `myhost:::1` keeps working. An entry with neither
separator now raises.
The first pass re-split every entry -- including mapping-form ones -- through
split_extra_host, after extra_host_pairs had joined them into 'host:address'.
With '=' now winning over ':', a mapping value containing an '=' re-divided at
the wrong character:

  extra_hosts: {somehost: "weird=address"}
  -> --add-host "somehost:weird:address"     (host and address both wrong)

Silent, exit 0 -- the same corruption class this change exists to close,
reintroduced one layer up.

The mapping form arrives already divided, so it should never be joined and
re-parsed. keys.extra_host_entries yields (host, address) pairs from either
form: the mapping straight through (via _render_scalar, so a boolean address
still normalizes like docker compose config), the list via split_extra_host.
extra_host_pairs had no other caller and is gone.
@lesnik512 lesnik512 force-pushed the fix/extra-hosts-equals-separator branch from 5296ee2 to 6575909 Compare July 14, 2026 16:13
@lesnik512 lesnik512 merged commit 6729a1b into main Jul 14, 2026
7 checks passed
@lesnik512 lesnik512 deleted the fix/extra-hosts-equals-separator branch July 14, 2026 16:15
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.

1 participant