Harden VNC setup calls against expired auth - #294
Conversation
* Harden gateway recovery after updates (ID-Robots#263) * fix: migrate legacy openai/<gpt> model+fallbacks to codex on startup (ID-Robots#266) ChatGPT-subscription boxes (Codex OAuth, no OpenAI API key) that stored their active model or a fallback as `openai/gpt-5.5` (etc.) before the setup UI routed ChatGPT picks through Codex hit `401 Missing bearer or basic authentication in header` on api.openai.com/v1/responses β often only as a FailoverError days into use, once the OAuth token first refreshes and the failover chain reaches the keyless `openai/*` fallback. The chat-model pick route already rewrites openai/<gpt> -> codex/<gpt>, but only when the user re-picks the model; existing configs never re-pick, so an updated box stays broken until manually re-selected. Migrate primary + fallbacks in gateway-pre-start.sh on gateway start, guarded on "codex OAuth present AND no OpenAI API key" so keyed / dual-auth boxes (where openai/* is a valid route) are left untouched. Mirrors CODEX_SUPPORTED_MODEL_RE / hasOpenAiApiKeyProfile / hasCodexOauthProfile in src/app/setup-api/chat/model/route.ts. Verified against 6 fixtures: openai->codex primary+fallback migrate; keyed box untouched; non-supported (gpt-4o) primary left as-is; already-codex no-op; no-codex-auth untouched; composes with the retired-Sonnet migration. bash -n and py_compile pass. Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(3.1.10): responsive chat header pills (wrap instead of overlap on narrow chat) (ID-Robots#267) * fix: chat header pills squeeze + truncate cleanly on narrow panels On a narrow chat the provider / model / thinking selector pills overlapped into an unreadable strip. Two parts: 1. .header-dropdown-trigger gets width:100% so the button fills its flex-shrinking .header-dropdown parent. Previously the button kept its content width and spilled past the shrunk parent, so overflow:hidden on .chat-header-pills clipped / overlapped the pills instead of the labels truncating. Now every pill gives ground evenly and its label ellipsizes (the chevron stays β it's reserved in the 24px right padding). 2. Single row (no wrap) + overflow:hidden, and the chat window clamps to MIN_CHAT_WIDTH (340px) on both resize paths + the rendered width, so the window stops shrinking once the pills reach a readable minimum instead of smashing them. The open menu is portaled to <body> (HeaderDropdown), so clipping the row can't hide it. Verified at 320-420px: even truncation, carets visible, zero overlap. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: open chat from mascot with a macOS-style animation, no corner flash - Stop streaming the frozen mascot's position into mascotX while the chat is open (page.tsx). That nudged mascotX for a frame right after opening, so the popup flashed to the wrong corner before settling. mascotX is now captured once from the tap. - Grow the popup OUT of the mascot: transform-origin pinned to the popup's bottom edge, aligned horizontally with the mascot, and scale 0.82 -> 1 on an easeOutExpo curve (cubic-bezier(0.16,1,0.3,1)) over 0.36s. Smooth, premium, emanates from where you tapped instead of scaling from the popup centre. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: bump SW cache clawbox-v3 -> v4 to invalidate stale assets on the 3.1.10 chat-UI changes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix: keep chat popup header on-screen on short/zoomed viewports The un-dragged popup anchors from the bottom (bottom:170 above the mascot, bottom:65 in tray mode) but its maxHeight budget was a flat 100vh-60px, so on viewports shorter than ~680px (small windows, browser zoom) a 500px-tall popup shoved its whole header β pills, status dot, close button β off the TOP of the screen (rect.y = -76 measured on a 594px viewport). Subtract the bottom anchor from the height budget per mode (+12px top margin) so the header is always visible and the popup just gets shorter instead. Found by driving the real desktop over CDP and sampling the popup rect during open; the same probe confirmed the mascot-open animation runs and there is no left-corner flash. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Mike (IDRobots) <mike@idrobots.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Merges beta into main for the 3.1.11 release. The conflicts came from ID-Robots#264 (the 3.1.10 gateway-recovery squash landing on main) diverging from the same work as it evolved on beta; every one resolved to the beta side. The resulting tree is byte-identical to origin/beta -- the exact code verified on hardware today. What ships: - codex: route codex turns through the app-server harness (ID-Robots#280). Without agentRuntime, core posts to /backend-api/responses -- a browser endpoint Cloudflare challenges -- and every turn dies with an HTML error page. - codex: restore the credential ID-Robots#278 broke, and migrate legacy auth profiles into the sqlite store core actually reads (ID-Robots#279). - codex: stop mirroring the rotating refresh token into every codex-home, so a single-use refresh token cannot be spent twice (ID-Robots#278). - codex: default ChatGPT auth to gpt-5.5; unblock GPT-5.6 for entitled accounts (ID-Robots#275, ID-Robots#276). - gateway: stop update/boot from bricking the box; parameterised health and recovery waits. - memory: local embeddings so semantic memory works without an API key. - docs/site: point references at clawbox.com; measured Wi-Fi and local-model performance figures. Hardware verification (2026-07-28, boxes .52 and todor): - HTML/Cloudflare failure reproduced on the old build, fixed by the update - 401 profile=- auth failure reproduced, fixed by the update - forced OAuth token rotation x2 on both boxes -- codex survived both - 3.1.10 -> 3.1.11 through the shipped updater: pass - 3.1.5 -> 3.1.11 through the shipped updater incl. reboot: pass, ~4 min - CI: 1499 unit tests, E2E, E2E-install in a real systemd container Known, not a regression (present in 3.1.10, fix queued for 3.1.12): the Codex model picker offers gpt-5.4/gpt-5.4-mini, which free-tier ChatGPT accounts cannot run -- upstream 400s with no failover. The default is gpt-5.5, which every tier runs, so this only bites a user who picks an older model by hand.
Release v3.1.11 β promote beta to main
π WalkthroughWalkthroughVNC setup requests now use ChangesVNC authentication handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant VNCApp
participant fetchSetupJson
participant SetupAPI
VNCApp->>fetchSetupJson: Send setup request with JSON Accept header
fetchSetupJson->>SetupAPI: Request setup endpoint
SetupAPI-->>fetchSetupJson: Return 401 or redirect to /login
fetchSetupJson-->>VNCApp: Return auth-expired result
VNCApp->>VNCApp: Clear operation state and stop repair or polling
Suggested reviewers: π₯ Pre-merge checks | β 4 | β 1β Failed checks (1 warning)
β Passed checks (4 passed)
β¨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 1
π€ Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/fetch-setup-json.ts`:
- Around line 9-12: Update redirectedToLogin to classify any redirect pathname
ending with "/login", including base-path routes such as "/clawbox/login", while
preserving the existing redirect and URL guards. Add a unit test covering a
login URL mounted below the origin root.
πͺ Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
βΉοΈ Review info
βοΈ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 6fea7c94-9937-4423-b240-333795042d9b
π Files selected for processing (4)
src/components/VNCApp.tsxsrc/lib/fetch-setup-json.tssrc/tests/components/vnc-app.test.tsxsrc/tests/unit/fetch-setup-json.test.ts
Prior art and current-version verificationThis PR supersedes the unmerged work in #253. That PR proposed the same core approachβrequest JSON, detect both This implementation applies that design to the current codebase and additionally:
Compatibility was reverified against current ClawBox Both branches pin OpenClaw 2026.7.1. This change is confined to the ClawBox setup UI/middleware boundary and does not call or modify the OpenClaw runtime. |
π¦ ClawReviewClaws waving β here's what this change is about. This PR fixes the VNC app's handling of expired sessions by replacing all five raw fetch calls (initial probe, repair trigger, reboot, reboot polling, clipboard) with a new shared helper β fetchSetupJson β that sets Accept: application/json and detects both 401 responses and already-followed redirects to /login. When auth expires, all VNC activity stops immediately and a clear 'Refresh to sign in again' button surfaces instead of confusing parse errors or misleading HTTP status messages. The helper lives in src/lib/ and is shaped for reuse across other setup-api callers. At a glance
Good to know
β ClawReview π¦, your resident reef crab. Just orientation β CodeRabbit does the line-by-line, humans do the merge. Conventions: docs. |
|
Retargeted |
Summary
/loginTesting
bun run test:unitbun run test:componentsbun run buildCloses #231
Summary by CodeRabbit