fix(bonjour): truncate mDNS service name and hostname to 63-byte DNS label limit [AI-assisted]#72809
Conversation
Greptile SummaryThis PR adds Confidence Score: 4/5Safe to merge; the fix is correct and well-scoped, with only minor edge-case and test-coverage concerns. No P0 or P1 issues found. Two P2 findings: a theoretical trailing-hyphen edge case in the truncation helper (only reachable via a contrived OPENCLAW_MDNS_HOSTNAME value), and a test that doesn't fully exercise the hostname truncation path because the chosen fixture is below the 63-byte threshold. extensions/bonjour/src/advertiser.test.ts — first new test should use a hostname longer than 63 bytes to properly exercise the hostname truncation branch. Prompt To Fix All With AIThis is a comment left during a code review.
Path: extensions/bonjour/src/advertiser.ts
Line: 198
Comment:
**Truncation may produce a trailing hyphen**
After slicing at byte 63, the result could end with `-` (e.g. if `OPENCLAW_MDNS_HOSTNAME` is set to a long value like `very-long-host-name-....-`). RFC 1035 §2.3.1 forbids labels that start or end with a hyphen, and `@homebridge/ciao` validates this. Consider stripping trailing hyphens after decoding.
```suggestion
return decoded.replace(/\uFFFD$/, "").replace(/-+$/, "").trim() || "OpenClaw";
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: extensions/bonjour/src/advertiser.test.ts
Line: 737
Comment:
**Test hostname is below the 63-byte limit**
`app-41627eae5842473f9e05f139ea307277-7f9477f4d6-lqqzf` is 53 bytes — well under the 63-byte threshold — so `truncateToDnsLabel` returns it unchanged for the `hostname` field. The assertion `encode(hostname).byteLength ≤ 63` passes trivially without exercising the truncation path. Truncation of the service name IS exercised (because appending ` (OpenClaw)` yields 64 bytes), but the dedicated hostname-truncation branch remains untested. Use a hostname of 64+ bytes (e.g. `"a".repeat(64)`) to cover that path.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(bonjour): truncate mDNS service name..." | Re-trigger Greptile |
| const truncated = encoded.slice(0, MAX_DNS_LABEL_BYTES); | ||
| const decoded = new TextDecoder("utf-8", { fatal: false }).decode(truncated); | ||
| // Strip any replacement character from incomplete multi-byte sequence at the end | ||
| return decoded.replace(/\uFFFD$/, "").trim() || "OpenClaw"; |
There was a problem hiding this comment.
Truncation may produce a trailing hyphen
After slicing at byte 63, the result could end with - (e.g. if OPENCLAW_MDNS_HOSTNAME is set to a long value like very-long-host-name-....-). RFC 1035 §2.3.1 forbids labels that start or end with a hyphen, and @homebridge/ciao validates this. Consider stripping trailing hyphens after decoding.
| return decoded.replace(/\uFFFD$/, "").trim() || "OpenClaw"; | |
| return decoded.replace(/\uFFFD$/, "").replace(/-+$/, "").trim() || "OpenClaw"; |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/bonjour/src/advertiser.ts
Line: 198
Comment:
**Truncation may produce a trailing hyphen**
After slicing at byte 63, the result could end with `-` (e.g. if `OPENCLAW_MDNS_HOSTNAME` is set to a long value like `very-long-host-name-....-`). RFC 1035 §2.3.1 forbids labels that start or end with a hyphen, and `@homebridge/ciao` validates this. Consider stripping trailing hyphens after decoding.
```suggestion
return decoded.replace(/\uFFFD$/, "").replace(/-+$/, "").trim() || "OpenClaw";
```
How can I resolve this? If you propose a fix, please make it concise.| @@ -735,6 +735,54 @@ describe("gateway bonjour advertiser", () => { | |||
| await started.stop(); | |||
| }); | |||
|
|
|||
There was a problem hiding this comment.
Test hostname is below the 63-byte limit
app-41627eae5842473f9e05f139ea307277-7f9477f4d6-lqqzf is 53 bytes — well under the 63-byte threshold — so truncateToDnsLabel returns it unchanged for the hostname field. The assertion encode(hostname).byteLength ≤ 63 passes trivially without exercising the truncation path. Truncation of the service name IS exercised (because appending (OpenClaw) yields 64 bytes), but the dedicated hostname-truncation branch remains untested. Use a hostname of 64+ bytes (e.g. "a".repeat(64)) to cover that path.
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/bonjour/src/advertiser.test.ts
Line: 737
Comment:
**Test hostname is below the 63-byte limit**
`app-41627eae5842473f9e05f139ea307277-7f9477f4d6-lqqzf` is 53 bytes — well under the 63-byte threshold — so `truncateToDnsLabel` returns it unchanged for the `hostname` field. The assertion `encode(hostname).byteLength ≤ 63` passes trivially without exercising the truncation path. Truncation of the service name IS exercised (because appending ` (OpenClaw)` yields 64 bytes), but the dedicated hostname-truncation branch remains untested. Use a hostname of 64+ bytes (e.g. `"a".repeat(64)`) to cover that path.
How can I resolve this? If you propose a fix, please make it concise.f485b34 to
102fbbf
Compare
|
Re-reviewed against current This is the active fix path for #37705: No blocker from me. Please keep #72332 separate/closed; that PR was for the older Windows/ciao fatal-crash cluster and is now superseded by |
102fbbf to
eefbc98
Compare
steipete
left a comment
There was a problem hiding this comment.
Verified this against the reported #37705 crash path and current ciao behavior.
@homebridge/ciao asserts each DNS label with Buffer.byteLength(label) <= 63; the reported Kubernetes-style host is 53 bytes, but the default service instance label becomes 64 bytes after appending (OpenClaw), so this is the right failure boundary. Current main only trims safeServiceName() and passes the host label through unclamped.
Current head clamps both the service instance label and hostname with byte-aware UTF-8 truncation, strips trailing hyphens after truncation, preserves the existing fallback behavior, and covers the reported overlong path plus multibyte truncation.
Local proof on head 102fbbf897a9caf6a972e4c3bd6a63ff95c28029:
pnpm test extensions/bonjour/src/advertiser.test.ts-> 23 passedpnpm check:changed-> passed
Good to land. Keep #37705 open until this merges, then close it as fixed by this PR.
…label limit When the system hostname exceeds 63 bytes (common with Kubernetes pod names), the @homebridge/ciao DNS label encoder throws an AssertionError that crashes the gateway on startup. Add truncateToDnsLabel() that safely truncates UTF-8 strings at byte boundaries, applied to both the service instance name and hostname before passing them to ciao. Closes openclaw#37705 AI-assisted (built with Hermes orchestration).
eefbc98 to
1c5a681
Compare
Summary
app-41627eae5842473f9e05f139ea307277-7f9477f4d6-lqqzf), the@homebridge/ciaoDNS label encoder throws anAssertionErrorthat crashes the gateway on startup.truncateToDnsLabel()that safely truncates UTF-8 strings to the 63-byte DNS label limit (RFC 1035), applied to both the mDNS service instance name and hostname before passing them to ciao.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause
safeServiceName()only checked for empty strings but did not enforce the 63-byte DNS label limit from RFC 1035. Long hostnames (e.g., Kubernetes pod names) were passed directly to@homebridge/ciao'sDNSLabelCoder, which asserts label length ≤ 63 bytes.Regression Test Plan
extensions/bonjour/src/advertiser.test.tsUser-visible / Behavior Changes
Diagram (if applicable)
N/A
Security Impact (required)