fix(port): preserve tie order for dual-stack port publishers - #14213
fix(port): preserve tie order for dual-stack port publishers#14213glours wants to merge 1 commit into
Conversation
`docker compose port SERVICE PORT` picks the first matching publisher as its answer, but containerPublishers()'s sort.Slice does not guarantee tie order, so a dual-stack publish (same target port on both an IPv4 and an IPv6 address) could non-deterministically return either one. Switch to sort.SliceStable to preserve the daemon's original order for ties. Also drops a dead length check and a duplicated host:port formatter. Signed-off-by: Guillaume Lours <glours@users.noreply.github.com>
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟢 APPROVE
The changes are correct and well-scoped. The switch from sort.Slice to sort.SliceStable in containerPublishers() correctly fixes the non-deterministic tie-breaking for dual-stack port publishers. The removed redundant length guard in cmd/compose/port.go is safe because Ports() guarantees a non-empty slice when port != 0 and no error is returned. The regression test correctly validates stable sort behaviour using 16 elements (>12 to force the quicksort path), and the new table-driven tests for Ports() provide solid coverage.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
ndeloof
left a comment
There was a problem hiding this comment.
Reviewed in depth: the sort.SliceStable switch is exactly right — sort.Slice's pdqsort scrambles same-PrivatePort ties once past the small-slice insertion-sort path, and the single-port lookup added by #13577 takes publishers[0] as THE answer, so a dual-stack publish could non-deterministically print the ::-side. Verified the dropped len(publishers)>0 guard in cmd/port.go is safe: Ports() already errors on an unmatched port, so publishers[0] is unreachable empty. The tie-order test forcing the quicksort partitioning path (>12 tied elements) is a nice touch — a small fixture genuinely cannot catch this. Tests green locally with -race, CI green. LGTM.
What I did
Follow-up to #13577, which made
docker compose port SERVICE [PRIVATE_PORT]list all port mappings whenPRIVATE_PORTis omitted, by routing throughcontainerPublishers()(shared withdocker compose ps).containerPublishers()sorts byPrivatePortusingsort.Slice, which does not guarantee tie order. That didn't matter forps, but the single-port lookup path added by #13577 now takes the first matching entry as the answer, so a dual-stack publish (same target port exposed on both an IPv4 and an IPv6 host address) could non-deterministically return either one.sort.Slicetosort.SliceStableincontainerPublishers()so ties preserve the daemon's original order.Ports()'s protocol/port filtering and its not-found error path (previously only covered by two e2e assertions).docker compose port#13577's review.Related issue
N/A
(not mandatory) A picture of a cute animal, if possible in relation to what you did
