Skip to content

release: v3.0.7 β€” gateway token security, post-update smokes, codex pin, Telegram progress toggle - #158

Merged
KrasimirKralev merged 21 commits into
mainfrom
beta
May 29, 2026
Merged

KrasimirKralev merged 21 commits into
mainfrom
beta

Conversation

@KrasimirKralev

Copy link
Copy Markdown
Contributor

Release v3.0.7 β€” beta β†’ main

Promotes the post-3.0.6 hardening work from beta to main and bumps the version to 3.0.7.

Closes #149
Closes #150
Closes #151

What ships

Security β€” gateway auth token (#155)

Reliability β€” post-update smokes (#156)

Customer fix β€” codex plugin pin (#152)

  • Pin @openclaw/codex to the core OpenClaw version (2026.5.22) so plugin/core drift no longer triggers the createDiagnosticTraceContextFromActiveScope is not a function error on "Activate ClawBox AI".

Feature β€” Telegram progress toggle + chat reconnect bar (#157)

  • Settings β†’ Telegram β†’ "Show research progress" β€” default ON (no behavior change on upgrade); off = the bot delivers the final answer only.
  • Chat shows the reconnect overlay on any gateway restart instead of freezing, and tears the overlay down on terminal failure so the error panel renders (no stuck-at-90% loop).

Not included

After merge

  • Tag v3.0.7 on the merge commit + cut the GitHub release. The updater is tag-based (git describe + newest reachable vX.Y.Z), so the tag on main is what lets devices on main see and pull the update.

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
@KrasimirKralev
KrasimirKralev requested a review from a team as a code owner May 29, 2026 08:48
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@KrasimirKralev, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7a0a0673-cc9c-4e4d-87bb-e2e59df08e69

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between e2e3b1a and a7ab420.

πŸ“’ Files selected for processing (15)
  • config/clawbox-gateway.service
  • install-x64.sh
  • install.sh
  • package.json
  • scripts/gateway-pre-start.sh
  • scripts/start-ap.sh
  • src/app/setup-api/gateway/ws-config/route.ts
  • src/app/setup-api/telegram/streaming/route.ts
  • src/components/ChatPopup.tsx
  • src/components/SettingsApp.tsx
  • src/lib/network.ts
  • src/lib/openclaw-config.ts
  • src/lib/translations.ts
  • src/tests/unit/gateway-pre-start-token.test.ts
  • src/tests/unit/openclaw-config.test.ts
✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 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.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 29, 2026

Copy link
Copy Markdown

CI Summary

βœ… Tests

  • Result: passed
  • View run
  • Coverage: statements 70.7%, branches 60.18%, functions 66.7%, lines 72.86%

βœ… E2E

βœ… E2E Install

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
@KrasimirKralev
KrasimirKralev merged commit 3c1bf5f into main May 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant