Skip to content

fix(signal): preserve reverse-proxy path prefixes#110495

Merged
steipete merged 1 commit into
openclaw:mainfrom
VectorPeak:fix/signal-baseurl-prefix
Jul 18, 2026
Merged

fix(signal): preserve reverse-proxy path prefixes#110495
steipete merged 1 commit into
openclaw:mainfrom
VectorPeak:fix/signal-baseurl-prefix

Conversation

@VectorPeak

@VectorPeak VectorPeak commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where users running the native Signal channel behind a reverse proxy path prefix, such as http://127.0.0.1:8080/signal, would still send RPC, health-check, and SSE requests to the origin root (/api/v1/...) instead of the configured prefix (/signal/api/v1/...).

That can make Signal send/check/receive flows fail with 404s even though channels.signal.httpUrl points at the correct mounted Signal service.

Why This Change Was Made

resolveSignalEndpointUrl now keeps the parsed base URL pathname before appending the Signal native endpoint suffix. Root-mounted base URLs keep the existing /api/v1/... behavior, while path-prefixed base URLs now resolve beneath the configured prefix.

The change is limited to the native Signal client URL join helper. Container-mode Signal URL construction is separate and already preserves its configured path prefix, so it is intentionally unchanged.

User Impact

Operators can run the native Signal HTTP/SSE API behind a path-prefixed reverse proxy and use the same configured httpUrl for sends, health checks, and event streaming.

Evidence

Live reverse-proxy behavior proof

I ran the current PR head against a local path-prefixed reverse-proxy setup:

OpenClaw Signal native client
-> http://127.0.0.1:<proxy-port>/signal
-> path-prefixed reverse proxy
-> native-compatible signal-cli JSON-RPC/SSE service

This proof does not use a private Signal account or credentials. It validates the deployment behavior changed by this PR: the native OpenClaw Signal client preserves the configured httpUrl pathname before sending RPC, health-check, and SSE requests.

[proof topology] OpenClaw Signal native client -> path-prefixed reverse proxy -> native-compatible signal-cli JSON-RPC/SSE service
[proof baseUrl] http://127.0.0.1:63713/signal
[before-current-main-shape] new URL('/api/v1/check', baseUrl).pathname=/api/v1/check -> HTTP 404
[openclaw] signalCheck(baseUrl) -> ok=true status=204
[openclaw] signalRpcRequest('version') -> {version:proof-signal-native}
[openclaw] streamSignalEvents(account=<redacted-e164>) -> [{event:message,data:{"source":"reverse-proxy-proof"},id:proof-1}]
[proxy] GET /api/v1/check rejected outside /signal mount -> 404
[proxy] GET /signal/api/v1/check -> 204
[proxy] POST /signal/api/v1/rpc -> 200
[proxy] GET /signal/api/v1/events?account=<redacted-e164> -> 200
[mock-native-signal] GET /api/v1/check -> 204
[mock-native-signal] POST /api/v1/rpc method=version -> 200
[mock-native-signal] GET /api/v1/events?account=<redacted-e164> accept=text/event-stream -> 200

Focused tests

Focused behavior covered in tests:

  • RPC request: http://server/signal/ resolves to /signal/api/v1/rpc.
  • Health check: http://server/signal resolves to /signal/api/v1/check.
  • SSE receive stream: http://server/signal resolves to /signal/api/v1/events?account=....

Local validation:

D:\ZXY\Dev\nodejs\node.exe scripts/run-vitest.mjs extensions/signal/src/client.test.ts
# Test Files 1 passed (1)
# Tests 22 passed (22)

D:\ZXY\Dev\nodejs\node.exe scripts/run-vitest.mjs extensions/signal/src/client.test.ts extensions/signal/src/client-adapter.test.ts extensions/signal/src/client-container.test.ts
# Test Files 3 passed (3)
# Tests 120 passed (120)

git diff --check
# passed

pnpm exec oxfmt --check extensions/signal/src/client.ts extensions/signal/src/client.test.ts
# All matched files use the correct format.

pnpm exec oxlint --tsconfig config/tsconfig/oxlint.extensions.json extensions/signal/src/client.ts extensions/signal/src/client.test.ts
# passed

pnpm check:changed was also attempted locally, but it did not reach repository checks because the local crabbox binary failed its basic --version / --help sanity check before dispatching Blacksmith Testbox.

Remote CI note: the PR's own extensions/signal/src/client.test.ts shard passed on GitHub. The current red checks-node-changed-* jobs fail in existing Signal monitor harness tests that do not execute this URL helper; those failures are tracked separately from this path-prefix proof.

Open PR overlap checked with gh search prs for signal baseUrl path prefix, resolveSignalEndpointUrl, and signal reverse proxy path; no matching open PR was found.

Prepared with AI assistance; the commit includes the verified Codex bot co-author trailer.

@openclaw-barnacle openclaw-barnacle Bot added channel: signal Channel integration: signal size: S labels Jul 18, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jul 18, 2026
@clawsweeper

clawsweeper Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 18, 2026, 10:15 AM ET / 14:15 UTC.

Summary
The PR updates the native Signal endpoint URL resolver and regression tests so a path prefix in channels.signal.httpUrl applies to RPC, health-check, and SSE requests.

PR surface: Source +5, Tests +52. Total +57 across 2 files.

Reproducibility: yes. at source level: resolving an absolute /api/v1/... endpoint against a base URL mounted at /signal discards that mount path; the supplied reverse-proxy transcript shows the current shape fail and the patched three-operation path succeed.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/signal/src/client.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Next step before merge

  • [P2] No mechanical repair remains; this focused, proof-backed patch needs ordinary assigned-owner merge review.

Security
Cleared: The final two-file Signal client-and-test diff introduces no concrete security or supply-chain concern.

Review details

Best possible solution:

Land the focused native Signal URL repair after ordinary assigned-owner review, retaining the three endpoint regression tests and reverse-proxy behavior proof.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level: resolving an absolute /api/v1/... endpoint against a base URL mounted at /signal discards that mount path; the supplied reverse-proxy transcript shows the current shape fail and the patched three-operation path succeed.

Is this the best way to solve the issue?

Yes. Preserving the parsed native-client base pathname in the shared endpoint resolver is the narrowest maintainable fix because it repairs RPC, health-check, and SSE callers without changing container-mode construction.

AGENTS.md: unclear because the file could not be read completely.

Codex review notes: model internal, reasoning high; reviewed against 3f976a949ad3.

Label changes

Label justifications:

  • P2: This fixes a bounded native Signal deployment failure for reverse-proxy path prefixes, with no evidence of urgent broad message loss or runtime unavailability.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR supplies redacted after-fix terminal evidence from a path-prefixed reverse proxy, including successful RPC, health-check, and SSE requests with visible corrected request paths. (github.com)
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR supplies redacted after-fix terminal evidence from a path-prefixed reverse proxy, including successful RPC, health-check, and SSE requests with visible corrected request paths. (github.com)
Evidence reviewed

PR surface:

Source +5, Tests +52. Total +57 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 6 1 +5
Tests 1 52 0 +52
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 58 1 +57

What I checked:

  • Current fix boundary: The current head changes only the native Signal URL join helper: it retains the configured base pathname, removes an endpoint’s leading slashes, and clears query/hash before dispatching the endpoint URL. (extensions/signal/src/client.ts:68, c4517a95a0b9)
  • Three caller paths covered: Focused tests cover path-prefixed RPC, health-check, and event-stream URLs, which are the three native operations affected by this resolver. (extensions/signal/src/client.test.ts:92, c4517a95a0b9)
  • After-fix runtime proof: The PR body includes a redacted reverse-proxy terminal transcript showing root requests rejected with 404 and patched RPC, health-check, and SSE requests succeeding under /signal/api/v1/.... (github.com) (c4517a95a0b9)
  • Scope and review history: The latest commit is fix(signal): preserve base URL path prefixes, authored by steipete and co-authored by VectorPeak; the timeline also shows steipete self-assigned the PR after the earlier combined branch was narrowed. (github.com) (extensions/signal/src/client.ts:68, c4517a95a0b9)

Likely related people:

  • steipete: steipete authored the current focused head, self-assigned this PR, and merged adjacent Signal ownership work referenced from its timeline. (role: recent Signal-area contributor and assigned reviewer; confidence: high; commits: c4517a95a0b9, 684ae080d4f1; files: extensions/signal/src/client.ts, extensions/signal/src/client.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (16 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-18T08:57:01.430Z sha 00ab8ea :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T09:06:15.218Z sha 368b4c5 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T09:42:36.888Z sha b5f09f7 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T09:53:04.185Z sha 48f5d7b :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T11:46:39.820Z sha cf85f38 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T11:59:40.458Z sha 1cf8763 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T12:15:15.042Z sha f4e3f06 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-18T12:48:15.600Z sha 8f65d39 :: needs maintainer review before merge. :: none

@VectorPeak

Copy link
Copy Markdown
Contributor Author

Updated the PR body with the requested real behavior proof.

The new Evidence section includes a redacted live terminal transcript for:

OpenClaw Signal native client
-> http://127.0.0.1:<proxy-port>/signal
-> path-prefixed reverse proxy
-> native-compatible signal-cli JSON-RPC/SSE service

It shows the current-main URL shape being rejected outside the /signal mount, then the PR head succeeding for signalCheck, signalRpcRequest('version'), and streamSignalEvents, with proxy logs for /signal/api/v1/check, /signal/api/v1/rpc, and /signal/api/v1/events.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jul 18, 2026
@VectorPeak
VectorPeak force-pushed the fix/signal-baseurl-prefix branch 4 times, most recently from c8ccdce to 2d83df1 Compare July 18, 2026 08:05
@steipete steipete self-assigned this Jul 18, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 18, 2026
@VectorPeak
VectorPeak requested a review from a team as a code owner July 18, 2026 09:38
@clawsweeper clawsweeper Bot added merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. and removed status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Jul 18, 2026
@steipete
steipete force-pushed the fix/signal-baseurl-prefix branch from 48f5d7b to cf85f38 Compare July 18, 2026 11:43
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 18, 2026
@VectorPeak
VectorPeak force-pushed the fix/signal-baseurl-prefix branch from 1cf8763 to f4e3f06 Compare July 18, 2026 12:11
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. labels Jul 18, 2026
@VectorPeak
VectorPeak force-pushed the fix/signal-baseurl-prefix branch from f4e3f06 to 8f65d39 Compare July 18, 2026 12:45
@steipete
steipete force-pushed the fix/signal-baseurl-prefix branch from 8f65d39 to c4517a9 Compare July 18, 2026 14:12
@steipete
steipete merged commit 4dff4c4 into openclaw:main Jul 18, 2026
84 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: signal Channel integration: signal P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants