extractUdpPort: handle Komodo's newline-string ports form

Real Komodo GetDeployment responses render config.ports as a single
newline-delimited string ("28963:28963/udp\n28963:28963/tcp\n"), not as
the array shapes we already handled. The walker only descended into
arrays and objects, so the string was skipped entirely and every Komodo
probe on a real deployment fell through to no-udp-in-response.

When the walker hits a value under a ports-keyed field that's a string,
split it on \r\n , ; and treat the resulting parts as a preferred string
array — the existing "host:container/udp" and "container/udp" regexes
handle each part.

Fixture pulled verbatim from the t5-nacht-1 response the fleet UI
surfaced. Also covers single-line, host-network (no host prefix), and
TCP-only-shouldn't-match cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 10:59:07 -04:00
co-authored by Claude Opus 4.7
parent 1e9d08f27e
commit 15ea2ddfce
2 changed files with 38 additions and 0 deletions
+12
View File
@@ -301,6 +301,18 @@ export function extractUdpPort(payload: unknown): number | null {
}
}
for (const [key, val] of Object.entries(obj)) {
// Komodo's GetDeployment renders `config.ports` as a single
// newline-delimited string ("28963:28963/udp\n28963:28963/tcp").
// Synthesize an array from it and treat as a preferred candidate.
if (PORT_ARRAY_KEYS.has(key) && typeof val === 'string' && val.trim()) {
const parts = val
.split(/[\r\n,;]+/)
.map((s) => s.trim())
.filter(Boolean);
if (parts.length > 0) {
candidates.push({ arr: parts, preferred: true });
}
}
walk(val, PORT_ARRAY_KEYS.has(key));
}
};