release: v3.0.7 β gateway token security, post-update smokes, codex pin, Telegram progress toggle - #158
Conversation
We pin the OpenClaw core (config/openclaw-target.txt) but installed the codex plugin unpinned β `openclaw plugins install codex` resolves @latest. So the plugin drifts ahead of the pinned core and every Codex chat crashes with "_diagnosticRuntime.createDiagnosticTraceContextFrom ActiveScope is not a function" (the newer plugin calls a runtime API the pinned core doesn't expose). Two customers on the latest ClawBox hit this; "You're up to date" boxes can't self-heal via the updater. - gateway-pre-start.sh: read the openclaw-target pin; reinstall codex when its version != the core target (not just when missing/broken); install the scoped pinned spec @openclaw/codex@<target> instead of the bare @latest alias. Drifted boxes now self-heal on next gateway start. - install.sh: the plugin-refresh loop derives each plugin's npm package from rootDir and pins @openclaw/* plugins to $TARGET instead of reinstalling by bare id (which also resolved @latest). - bump version 3.0.5 -> 3.0.6 so already-current devices receive the fix. Validated on a Jetson: forced codex to 2026.5.27 against core 2026.5.22, ran the heal path, confirmed it detected the mismatch and realigned to 2026.5.22.
β¦fig keys Closes #149, #150. The gateway auth token gates LAN access to the agent's privileged tools (run_command / file_write / system_power). Two bugs shipped the public literal "clawbox" (documented in open-source history) as the live token: 1. gateway-pre-start.sh ran `set_if(auth, "token", "clawbox")` on EVERY gateway start, clobbering the strong per-device token the configure route generates β so the rotation never stuck. 2. clawbox-gateway.service launched with `--token clawbox`, overriding config at runtime and drifting from what the Control UI (which reads gateway.auth.token) used β the #150 source-of-truth mismatch. Fix β config is the single source of truth: - gateway-pre-start.sh preserves a strong token (configure-route random hex, a ${ENV} interpolation, or a SecretRef object with a known env/file/exec key) and only generates a fresh secrets.token_hex(32) when the value is missing or the weak legacy literal. - clawbox-gateway.service drops --token; the gateway resolves gateway.auth.token from openclaw.json (OPENCLAW_GATEWAY_TOKEN ?? configuredToken), the same value gateway-proxy.ts injects into the SPA. - install.sh / install-x64.sh seed a random token instead of the literal, only when missing/weak. The install-x64 JS predicate is kept in lockstep with the python one (rejects arrays + empty/keyless objects + empty ${}). Also self-heal a config-validation residue class (the agentRuntime incident): gateway-pre-start.sh strips an orphaned `agentRuntime` key from agents.defaults.models[*] β written by @openclaw/codex >= 2026.5.27 and left behind when the plugin is realigned to the pinned core, which fails strict validation and bricks the AI provider page until `doctor --fix`. Adds src/tests/unit/gateway-pre-start-token.test.ts, which extracts the real predicate from the shipped script and asserts preserve/rotate + pythonβJS parity. Validated end-to-end on a Jetson: clawbox/empty-dict rotate to 64-hex, strong tokens preserved across restarts, Control UI authenticates against the config token with no --token flag.
β¦t file/exec SecretRefs Address CodeRabbit review on #155: - install.sh / install-x64.sh: the bash seed predicate only treated empty / "clawbox" / <32-char as weak, so a `${ENV}` interpolation token (e.g. ${OPENCLAW_GATEWAY_TOKEN}, 16 chars) was rotated to a random value β clobbering an externally-managed token before the later checks run. Add a `^\$\{.+\}$` regex branch so interpolation tokens are preserved, matching is_strong_gateway_token in gateway-pre-start.sh and the JS predicate in install-x64.sh. - test: cover SecretRef objects with `file` and `exec` keys (not just `env`) so dropping an accepted key from the predicate is caught.
β¦pdate smokes Closes #114, closes #151. #114 β e2e reliability: The E2E Tests job ran the suite against a single shared `bun run dev` (Turbopack) server under workers:1. Turbopack recompiles routes on first hit, and under per-test load on the GH-Actions runner that recompile starved ~6 interaction specs into timeouts β so they were test.fixme()'d and silently skipped (zero coverage for browser/VNC, ClawKeep unpair, desktop selection, installed-app settings, mascot context, terminal reconnect). The webServer now serves a production build (`next build` + production-server.js) in CI β pre-built routes, no per-request compile, and closer to what ships on the device β and the 6 specs are re-enabled. Adds a .next/cache CI cache so the build stays incremental and the 30-min job budget stays comfortable. The two clawkeep-flow specs stay fixme'd: they target unreleased ClawKeep UI, a separate concern. #151 β post-update smokes: post_update previously only confirmed services were *running*. A bad update can silently break gateway auth or Telegram delivery while health still looks green β exactly the failure mode behind this week's incidents. New advisory `step_update_smoke` (run at the end of step_post_update, also `--step update_smoke`) checks: (1) gateway reachable + a strong auth token in config, (2) Telegram bot identity via getMe, (3) a real message send gated behind CLAWBOX_SMOKE_TELEGRAM_CHAT_ID so production devices skip it gracefully and CI/QA can exercise a true round trip. The smoke is ALWAYS non-fatal β it logs [ok]/[WARN] and never rolls back an update. The bot token never reaches a logged string. Validated on a Jetson: smoke reports gateway reachable + token strong + Telegram getMe verified, send-smoke skipped without a QA chat id, exit 0.
The EXISTING_GW_TOKEN read I added runs `openclaw config get
gateway.auth.token`, which exits non-zero on a fresh install (the key
doesn't exist yet). Under `set -euo pipefail` the bare assignment
propagated that non-zero status and aborted install.sh right after
setting gateway.auth.mode β bricking first-boot install. The e2e-install
harness caught it ("install.sh did not finish within 2400000ms").
Append `|| true` so the probe never aborts the installer; an empty
result correctly falls through to seeding a fresh per-device token.
Same fix in install-x64.sh. Reproduced the abort and verified the fix
under set -euo pipefail.
The production-build e2e webServer broke 33/41 specs on CI: the suite was written against `bun run dev` and the standalone production server differs enough (middleware/origin/instrumentation) that nearly every page-loading test failed. Reverting playwright.config.ts, the 6 un-fixme'd specs, and the .next/cache workflow step back to beta β #114 stays unsolved (specs remain skipped, no regression) and needs a different approach that reworks how the suite bootstraps. This PR now carries only #151 (advisory post-update smokes in install.sh), which is independent and validated on a Jetson.
β¦elfheal fix(gateway): preserve per-device auth token + self-heal orphaned config keys
β¦pdate-smokes feat(install): advisory post-update smokes (#151)
When the agent takes >5s on a task, OpenClaw streams live tool/research
progress drafts ("Bubblingβ¦", Web Search/Fetch/Firecrawl lines) to the
Telegram chat before the final answer. That's noisy for a chat bot.
Adds Settings β Telegram β "Show research progress" (default ON, so no
behavior change for existing users). Turning it off makes the bot deliver
the final answer only.
- openclaw-config.ts: get/setTelegramProgressStreaming. Off writes
channels.telegram.streaming = { mode: "off" } (OpenClaw gates the
progress draft on streaming mode); On removes the override to restore
the default. Spreads the existing telegram object so botToken/enabled
survive; never writes dmPolicy/allowFrom (same invariant as
setTelegramToken). gateway-pre-start.sh already leaves the streaming
key untouched on restart, so the choice persists.
- New /setup-api/telegram/streaming route (GET reads, POST writes +
restartGateway; 502 = saved-but-restart-failed like ai-models/configure).
- SettingsApp: a switch in the connected card, optimistic with a pending
spinner (the POST restarts the gateway).
- i18n: settings.telegramProgress + Hint across all 10 locales.
- Unit tests for the get/set helpers (default ON, offβmode:off preserving
botToken, onβremoves override, never dmPolicy/allowFrom).
The skill-install / provider-change flows already show a progress-bar
overlay ("Reloading skillsβ¦") while the gateway bounces and the chat WS
reconnects. Any other gateway restart β the new Telegram streaming
toggle, a settings change, a crash β just froze the chat behind the bare
"connecting" spinner.
Generalize it: in the WS onClose, if we'd already connected once
(connectedOnceRef) and aren't already mid-reload, treat the drop as a
gateway restart and show the same overlay with a new 'restart' reason
("Restarting chatβ¦"). It reuses the existing extended retry budget +
the resolve-callback clear path (reason 'restart' keeps the visible
history, like a provider change, and shows no banner). Connection-driven
so it covers every restart cause without each one needing to fire an
event.
/simplify pass on the Telegram progress-toggle + chat reconnect-bar work: - extract the duplicated reload progress-timer setInterval into a shared startReloadProgressTimer() helper (was byte-identical in onClose and the skill/provider event handler) - narrow makeHandler's reason param back to 'skill' | 'provider' (the 'restart' reason is set directly in onClose, never via makeHandler) - flatten the keepHistoryReload branch in the hello-resolve callback by hoisting the provider banner out of the nested guard - revert the Telegram streaming toggle to the captured prior value instead of assuming !next
When the WS drops after a successful connection, onClose shows the reload overlay and uses the extended retry budget. If the gateway never comes back, retries exhaust and we set status='error' β but reloadingSkill stayed true, so the overlay kept rendering (parked at 90%) on top of the error panel and the chat looked stuck forever. Tear the overlay down, stop the progress timer, and reset the reload flags in the exhaustion branch so the error panel renders and a manual retry starts clean. Addresses CodeRabbit review on PR #157.
Follow-up to the CodeRabbit review on PR #157. The previous fix only cleared the overlay in the onClose retry-exhaustion branch, but there's a sibling exhaustion path in connect()'s ws-config catch. On a reboot where /setup-api/gateway/ws-config keeps failing, retries exhaust there instead of in onClose β and it only set status='error' without resetting reloadingSkill. The error panel is gated on !reloadingSkill so it never rendered, and the safety-net effect (error && reloadingSkill) reset the retry count and reconnected forever. Extract a shared tearDownReloadOverlay() helper and call it from both exhaustion paths.
feat(telegram): Settings toggle to disable bot progress streaming
|
Warning Review limit reached
More reviews will be available in 51 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. β How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. π¦ How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. βΉοΈ Review infoβοΈ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: π Files selected for processing (15)
β¨ Finishing Touchesπ§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The setup wizard showed 'No networks found' because the boot-time pre-AP scan in start-ap.sh fired 'nmcli ... rescan' then waited only 'sleep 2' before reading the list. nmcli populates scan results asynchronously over 5-10s, so it read an empty list and cached '[]'. The live 'iw scan' fallback can't recover on single-radio adapters because the radio can't scan while beaconing as an AP (it hangs until timeout). - start-ap.sh: wait for the interface to be up, then poll 'nmcli wifi list' (re-triggering rescan) until real networks appear, bounded by PRE_AP_SCAN_TIMEOUT (default 20s). - network.ts: cap the iw-scan timeout at 15s (was 60s) so a doomed AP-mode scan fails fast, and fall back to the pre-AP boot cache when the live scan returns nothing, so the rescan button still surfaces the boot-time networks.
When the gateway closes the WS with an auth rejection (code 1008 / 'unauthorized' / rate-limited β it rate-limits a client after too many failed auth attempts), the reconnect loop retried on the fast 3s RETRY_DELAY cadence, which re-tripped the limiter so the 'too many failed authentication attempts (retry later)' lockout never cleared. onClose now detects an auth-rejection close, tears down the reconnect overlay, surfaces the gateway's reason, and schedules a single 30s backoff retry so the cooldown can expire and the chat self-heals without a manual reload.
The chat fetched /setup-api/gateway/ws-config without cache:'no-store', and the route set no Cache-Control. When the per-device gateway token is regenerated (reseed, settings change, post-update), a cached ws-config response replays the OLD token on every reconnect, so the gateway rejects it with 'token mismatch' indefinitely β only a hard reload recovers. Add cache:'no-store' to the fetch and Cache-Control:no-store on the route so reconnects always pick up the current token. This matters for the #155 token-hardening rollout: open chat tabs would otherwise get stuck after the token changes on update.
- start-ap.sh: validate PRE_AP_SCAN_TIMEOUT is a non-negative integer before using it in arithmetic β a malformed env override would otherwise be a $((...)) syntax error and abort the script under set -euo pipefail, stopping the AP from coming up. - ChatPopup.connect(): clear any pending retry/auth-backoff timer at the start so an explicit reconnect (Try again) can't race with a previously scheduled timer and fire a duplicate connect.
fix(wifi+chat): reliable setup-wizard scan + gateway auth-rejection backoff
Release v3.0.7 β beta β main
Promotes the post-3.0.6 hardening work from
betatomainand bumps the version to 3.0.7.Closes #149
Closes #150
Closes #151
What ships
Security β gateway auth token (#155)
gateway.auth.token(env / secret-ref) ingateway-pre-start.sh; stop shipping a literalclawboxtoken. Closes Preserve secret-managed gateway.auth.token values in gateway-pre-start.sh and stop shipping a literal gateway tokenΒ #149.Reliability β post-update smokes (#156)
webServerapproach (it broke 33/41 specs); the 6 CI-only-flaky specs stayfixme'd under e2e: 6 tests fail only on GitHub Actions despite passing locallyΒ #114.Customer fix β codex plugin pin (#152)
@openclaw/codexto the core OpenClaw version (2026.5.22) so plugin/core drift no longer triggers thecreateDiagnosticTraceContextFromActiveScope is not a functionerror on "Activate ClawBox AI".Feature β Telegram progress toggle + chat reconnect bar (#157)
Not included
After merge
git describe+ newest reachablevX.Y.Z), so the tag onmainis what lets devices onmainsee and pull the update.