You get: Node 24 plus OpenClaw v2026.5.x, loopback versus SSH exposure, HMAC-first webhooks, and one merged JSON blob for PR bots.
Related: gateway status JSON, onboard merge gate. Canonical: this slug.
Pain points when flags move faster than dependency proofs
- Unauthenticated JSON. Parsing before HMAC verification invites replay and leaks repo identifiers.
- Split observability. Separate gateway health and CI logs hide correlated regressions in merge queues.
- Fragile ingress. Half-configured loopback or SSH yields HTTP 408 when tunnels stall mid-preflight.
Exposure matrix: loopback TLS versus SSH tunnel
| Pattern | Best when | Trade-off on remote Mac |
|---|---|---|
| Loopback plus TLS terminate | You own certs and want predictable SaaS RTT | Forward headers carefully; fence admin routes |
| SSH remote forward | No public listener allowed; bastion fronts HTTPS | Reconnect churn; set ServerAliveInterval for overnight queues |
| Split DNS only | Sources stay inside VPC peered to Mac VLAN | LaunchDarkly cloud still needs reachable HTTPS or a proxy path |
Environment preparation and version locking
Install Node 24 LTS, pin npm install -g openclaw@^2026.5.0, log the resolved semver, then run openclaw onboard, openclaw onboard --install-daemon, and openclaw doctor under the CI service account until docs.openclaw.ai checks pass.
export OPENCLAW_HOME="/var/lib/openclaw/job-${JOB_ID}"
node -v # expect v24.x
openclaw doctor
Store OPENCLAW_GATEWAY_TOKEN in root-owned mode six hundred files referenced by launchd, never inline.
Gateway loopback health versus SSH tunnel exposure
Loopback first: bind automation HTTP to 127.0.0.1, terminate TLS upstream, forward minimal paths.
SSH path: ssh -R 0.0.0.0:8443:127.0.0.1:PORT bastion when no public port is allowed.
Smoke-test with curl --max-time 12 from LaunchDarkly egress; keep proxy reads above slow preflight but inside vendor SLA.
Webhook routing, LaunchDarkly signatures, and least-privilege tokens
Point LaunchDarkly HTTPS deliveries at your endpoint; store the signing secret in /etc/launchdarkly/webhook.secret mode six hundred.
Hash raw body bytes with HMAC SHA256, compare signatures in constant time, return HTTP 401 on mismatch.
Add a read-only API token with flag-read scope only when metadata beyond the webhook is required—never reuse admin tokens.
Merge gateway status JSON with preflight failures for one PR summary
After auth, capture openclaw gateway status JSON, clone into a tree keyed by LaunchDarkly project or env keys, run npm bundler or Gradle preflight, then fold stdout stderr exit codes into one payload for Git automation.
gateway, preflight, launchdarklyDeliveryId.FAQ: HTTP 401 and HTTP 408 on the Mac handler
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 right after deployment | HMAC used parsed JSON instead of raw bytes, or newline drift in the secret file | Hash raw bytes with timing-safe compare; trim secret newlines |
| 408 from LaunchDarkly delivery logs | Preflight commands exceeded the webhook SLA or SSH tunnel wedged | Shorten sync work; backoff two four eight seconds; curl max near twenty-five seconds |
| 401 only under launchd | Different environment variables than interactive shells | Mirror EnvironmentVariables in the plist exactly as doctor expects |
Citable operating parameters
- Backoff: two four eight seconds between summary POST attempts.
- Curl ceiling: about twenty-five seconds per attempt.
- Doctor cadence: rerun after Node or OpenClaw bumps.
Summary and public next steps
Lock Node 24 with OpenClaw 2026.5.x, verify HMAC on raw bodies, merge gateway JSON with preflight before PR bots comment.