release: promote develop → main — security (cross-org IDOR #11981 + app-key scope #11943/#11958) + money fixes to prod - #12051
Conversation
…idation on UPDATE_APP/UPDATE_MONETIZATION
Three confirmed bugs from the 07-02 Fable adversarial apps-surface scan:
- MED: DEPLOY_FRONTEND claimed 'v{N} is now live' unconditionally after
deployAppFrontend, but the deployment can settle into a 'ready' (built, not
serving) state where activation failed/pended. Reporting that as live is a
lie the user acts on. Now branch on deployment.status === 'active': live copy
only when truly active; otherwise report 'built but NOT yet live (status: X)'.
- LOW: UPDATE_APP and UPDATE_MONETIZATION mutated app state without calling
invalidateAppsCache(runtime), so the ~60s provider WeakMap cache served stale
name/description/monetization to the next turn (documented cache-invalidation
invariant; every other mutating action already calls it). Added the eviction.
plugin-cloud-apps: 288 pass / 0 fail; biome clean.
…ce 'meeting', plugin-meetings package + internal seams (#11856) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…1856) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… STT gate (#11856) Registers the existing handleTranscription in the always-on models map so useModel(TRANSCRIPTION) can arbitrate local-first with Eliza Cloud fallback (/api/v1/voice/stt). Widens input handling to all documented param shapes (Buffer/Blob/audioUrl/string via SSRF-guarded fetch), adds isCloudSttAvailable (ELIZAOS_CLOUD_ENABLED || ELIZAOS_CLOUD_USE_STT) mirroring the TTS gate, and typed CloudSttUnavailableError for clean router fallthrough. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ges in Transcripts view (#11856) client-meetings ElizaClient methods (/api/meetings), MeetingWsEvent guards, live confirmed+pending pane with ws-fresh poll suppression, paste-URL join bar validated by parseMeetingUrl, platform/participant metadata on meeting records. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t join, DOM speaker attribution, humanized input, browser audio capture (#11856) runMeetingFlow state machine + selector racing + playwright-core stealth launch; Meet anonymous guest join/admission/removal with verbatim Vexa selectors and reCAPTCHA-stay; vote-and-lock speaker identity; per-element 16kHz ScriptProcessor capture via exposeBinding; pluggable InputDriver (Playwright min-jerk trajectories / Linux XTEST xdotool). 119 unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…greement-2), useModel ASR backend, hallucination filter, WAV codec (#11856) Faithful Vexa port: per-speaker buffered windows (2s cadence, 30s cap, 15s idle), word-prefix confirmation with double-match fallback, retry/backoff ASR via ModelType.TRANSCRIPTION, verbatim multi-language hallucination corpus, session mix for retained audio. 40 real-logic tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Teams: guest prejoin, live-caption enablement, caption-author speaker routing (10s RMS ring buffer, 2s lookback), voice-level fallback, Edge-preferred launch. Zoom: web-client join (waiting room/passcode/host-not-started), capability-detected capture (element → PulseAudio null-sink parecord on Linux → hard error, no silent success), active-speaker vote-and-lock. Vexa selectors verbatim; 33 real-logic tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…S events, transcript writer + plugin assembly (#11856) Session state machine (single bot per meeting, rooms/entities wiring), JOIN/LEAVE/GET_MEETING_TRANSCRIPT actions, /api/meetings rawPath routes, meeting-status + throttled meeting-transcript WS envelopes via the connector-setup broadcastWs seam, transcript writer producing records the existing /api/transcripts routes + Transcripts view render (golden-tested against the view reader), knowledge mirror via documents service. Opt-in via ELIZA_MEETINGS_ENABLED. 24 tests; plugin suite 119/119. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t-to-meeting UX (#11856) Auto-join policy off|ask|all: relative_to_anchor(-1min) join tasks with calendar_event subjects + per-event anchors that follow reschedules; ask mode = approval task + after_task join; typed DispatchResult failures through the spine's retry/escalation. meeting_join channel registered by the PA host. Google conferenceData fix: prefer video entry point over dial-in. Calendar views gain Send-agent button + in-meeting badge. 25 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…live transcription (#11856) Tees each speaker's decoded PCM (per-SSRC = exact diarization) into the plugin-meetings pipeline; transcript writer + live WS envelopes; /transcribe start|stop slash command + DISCORD_VOICE_TRANSCRIPTS gate (default off); existing utterance-reply, barge-in, and TTS paths untouched. 26 new tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…connector consumers (#11856) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e link (#11856) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- meeting-flow: race join + admission phases against the abort signal so a user-requested stop mid-join short-circuits to graceful leave (browser closes via adapter finally) instead of running every remaining Playwright step first — found by the live-LLM JOIN_MEETING trajectory. - MeetingJoinBar: widen bot-name input so the placeholder no longer clips. - TranscriptsView: nowrap+truncate the meeting meta row (no ragged wrap in the narrow sidebar). - Add live-join-meeting scenario + PR evidence: 14 UI screenshots (desktop + mobile), live Cerebras trajectory (planner genuinely selected JOIN_MEETING, real Chromium reached Meet's guest page), backend logs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…contrast (#11864) The WebSocket reconnecting banner rendered in document flow as a shrink-0 flex sibling of the page (App.tsx:2479), so it pushed the header + content down on every reconnect blip. It also used bg-warn (#ff8a24) with white text (~2:1 contrast, fails WCAG). - Render the transient "reconnecting" state as a floating overlay pill (absolutely positioned, out of flow) → 0px content shift. - Near-black text on the orange pill for ~8:1 contrast. - Keep the persistent, actionable "connection lost" state as an in-flow bar (Retry/Dismiss), preserving the macOS titlebar-banner integration. - Add ConnectionFailedBanner.test.tsx (overlay vs in-flow regression), a ReconnectingOverContent story, and a Playwright proof measuring the header Y delta (in-flow bar = 44px shift, overlay pill = 0px). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eployment docs (#11856) launch.ts resolves headless via ELIZA_MEETINGS_HEADLESS or display autodetect (--headless=new keeps getUserMedia/WebAudio); new platform-support.ts (resolveMeetingRuntimeSupport / chromiumExecutable / resolveHeadlessMode) so the plugin refuses cleanly on mobile or no-Chromium hosts and no longer auto-enables on iOS/Android; docs/DEPLOYMENT.md covers the Eliza Cloud container (Xvfb + PulseAudio + apt/Dockerfile) and why on-device mobile routes to a cloud-hosted agent instead. +19 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d, target resolution, reply helper (#11856) Dedupes the service-missing guard (requireMeetingService), the near-identical leave/get target picker (resolveTargetSession with single-or-ambiguous vs most-recent fallback), and the callback+return boilerplate (reply). Net −61 handler lines, behavior-identical. +59 tests incl. adversarial URL parsing (multiple/wrapped/punctuated links, empty/non-string text, planner-nested options) and every action error path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…m) with typed error (#11856) requestJoin now calls resolveMeetingRuntimeSupport before launching; mobile or no-Chromium hosts get MeetingJoinError('unsupported_host') → HTTP 422 instead of a doomed browser start. Wires H-B's capability probe into the service. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…overage + mock audit (#11856) Real headless Chromium drives a local fake-meeting page (per-participant WebAudio streams) through the REAL browser capture → pipeline → transcript writer with only a scripted ASR backend — proves capture→transcript runs headless with no real Meet and no real ASR (18/18 assertions). +8 tests (pipeline/writer finalize-throw fallback, world-retry, stop-aborts-and-awaits, concurrent joins, empty-segment + audio null/present). MOCK-AUDIT.md confirms no unit test hits a real network/model/browser. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…me upgrades New real-Chromium ui-smoke gate tap-target-geometry-all-views.spec.ts asserts every interactive element's rendered bbox meets the 44x44px minimum + role<->DOM coherence across app views; all-views-interaction.spec.ts upgrades a subset of 'no page error' assertions to semantic outcomes. Test-only (no product source). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d lane Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…invalid-URL, multi-meeting (#11856) Mock adapter + canned pipeline injected via a custom seed that overrides MeetingService.dependencyFactory before the service starts, so the model→action →service→transcript-writer path is proven in CI with no browser and no model dependency (deterministic lane). 4 scenarios; happy path hand-reviewed to produce a real ready transcript with the scripted two-speaker text. Mock scaffolding appended additively to test-support.ts. Live browser scenario kept. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ription, examples) (#11856) Live-model routing was flaky — the planner often picked calendar/reminder/reply over JOIN_MEETING when a meeting URL was present. Add explicit similes (TAKE_MEETING_NOTES / TRANSCRIBE_MEETING / RECORD_MEETING / SEND_NOTETAKER / JOIN_CALL), a description that names the URL patterns and says to prefer this over schedule/acknowledge actions when a joinable link is present, and Zoom + Teams examples so the planner selects it reliably. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…a finish error
The in-chat first-run wizard could loop forever with no escape. On any
finish/provision error, `seedError` re-appended the runtime CHOICE
(`${message}\n\n${RUNTIME_CHOICE}`), so a persistent failure — e.g. the
"Not found" 404 from `POST /api/first-run` — re-offered the same runtime
question indefinitely with no distinct error surface and no way out. The
"Other / configure in Settings" provider pick made it worse: it ran a local
finish that hit the same 404 and re-looped instead of ever opening Settings.
This is the UX/navigation fix (the underlying 404 is a separate backend/env
issue, out of scope):
- Finish errors now seed a DISTINCT, non-looping recovery turn
(`first-run:error:*`) with a human message and a dedicated
`[CHOICE:first-run id=error]`: Try again (`error:retry`, re-runs the last
runtime's finish), Choose a different way to run (`error:restart`, re-offers a
fresh unlocked runtime CHOICE), and Configure in Settings (`error:settings`).
- "Other / configure in Settings" (`provider:other`) now opens the Settings tab
(`setTab("settings")`) and exits first-run (`completeFirstRun("settings")`)
via a shared `exitToSettings` helper, latched by `completedRef` so a
double-tap can't flip the gate twice.
- Raw terse errors ("Not found", "Failed to fetch", …) are wrapped in a clear,
human sentence via `finishErrorMessage`.
Local-success, cloud, and needs-cloud-login paths are unchanged.
Tests: updated the affected conductor tests and added coverage for the
persistent-404 no-loop + retry + Settings escape, the cloud `error:retry`
re-run, and `provider:other` -> Settings exit. Also hardened `beforeEach` to
restore default mock implementations (clearAllMocks keeps implementations, so a
leaked mockRejectedValue would poison later tests). Full src/first-run suite:
191 passed.
Closes #11882
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…kslash escapes (#12037) sendMessageInChunks escapes each chunk via convertMarkdownToTelegram, and on a MarkdownV2 parse-entity 400 the sendWithRetry fallback resent that SAME escaped chunk with no parse_mode — so the user saw literal backslashes ("Sure\! Step 1 \- done\.") instead of clean text. The sibling editMessage fallback already does this right (cleanText(text)). Fix: the fallback sends cleanText(chunks[i]) — the ORIGINAL unescaped chunk — so a parse failure degrades to clean unformatted text. Test: new send-resilience case asserting the fallback text carries no backslash escapes. 37/37 green; red without the fix (fallback text contains backslashes). typecheck + biome clean. Tracked in #12030. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Makes the #12031 evidence files parseable and whitespace-clean without changing the captured evidence.
…ll-UUID choice rejection, dangling topics fragment (#12040) - RECENT_MESSAGES provider: a message with no metadata from a sender whose entity row is unresolvable threw on metaData.entityName; the catch then collapsed the ENTIRE conversation history to 'No recent messages available' for the turn. Optional-chain the metadata read. - CHOOSE_OPTION action: the taskId parameter is documented as 'Short or full ID of the pending choice task' but the lookup map only keyed the 8-char short id, so a model passing the task's real UUID got TASK_NOT_FOUND. Key the map by both short and full ids. - CHARACTER provider: when the deterministically-picked topic is the only topic (or all remaining topics equal it), the 'is also interested in' list was empty and the prompt rendered the dangling fragment 'X is also interested in '. Omit the sentence when no other topics remain. Each fix ships a mutation-checked vitest regression test.
…10721) (#12045) Capture a real-model LifeOps benchmark run for the #10721 PA audit closure, using a REAL local model on-host (no proxy/mock judge, no registerCalibratedJudgeFixture). - Serve eliza-1-2b (gemma-4-E2B) and eliza-1-4b (gemma-4-E4B Q8) via a locally-built llama.cpp llama-server (CPU backend — host GPU wedged), and drive packages/benchmarks/lifeops-bench (Hermes adapter, --mode static, deterministic state-hash scoring — no hosted judge). - Score history retained under .github/issue-evidence/10721-lifeops-benchmark-history/: perfect-oracle smoke pass@1=1.000 (validates the scorer), eliza-1-2b + eliza-1-4b smoke pass@1=0.000, eliza-1-2b 10-scenario calendar slice pass@1=0.000, with per-scenario JSON (raw agent_message, tokens, latency), stdout logs, and scenario-runner trajectory bundle. - Hand-review: the 4B reasons correctly (right tool + args) but emits gemma-native tool syntax the Hermes adapter cannot parse; the native eliza-runtime path (faithful adapter) is environment-blocked on CPU (40k+ token PA turns exceed budget). All caveats + skipped-scenario reasons documented in the evidence README. - Add SCENARIO_TURN_TIMEOUT_MS env override to the scenario-runner CLI so a slow local-model CPU lane can raise the 120s default per-turn budget. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
… (#12047) The embeddings route omitted affiliateCode from its reserveCredits context — a residual of #11972 that the #11976 reserve-inclusion fix covered on /v1/chat/completions and /v1/messages but not here. The upfront hold was base+platform only (buffered 1.5x), while the deferred billUsage still credited the affiliate the full attacker-set markup (up to 1000%) as cashable redeemable earnings. With the org balance exhausted, the settle recorded an uncollectable overage and the affiliate credit stood — minting money the platform never collected, repeatable per request via 2-account collusion. Thread affiliateCode into the reserve context exactly like the covered routes, so resolveBillableAffiliate folds the markup into the hold via estimatedCostMultiplier and the payout is always backed by collected money (fail-closed at reserve time). Regression suite drives the REAL route + REAL reserveCredits/billUsage (affiliate resolution, markup math, earnings credit all real; only auth/embedder/pricing/ledger-reserve/writers stubbed) and asserts the money invariant itself: reserved >= settled with the affiliate present, plus no-header / self-referral / inactive-code guards. The key test fails on the unfixed route (hold multiplier absent, /usr/bin/zsh.15 hold vs .10 settle). Fixes #12017
…12049) The chat-first onboarding composer placeholder shipped as "Pick an option to continue" (ContinuousChatOverlay.tsx), but the shared ui-smoke helper expectChatFirstOnboarding still asserted the stale "Tap a highlighted option above to continue" copy, failing all onboarding-to-home specs that route through it. Update the spec to match the shipped copy.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
|
Too many files changed for review. ( |
…xports fix(cloud): unblock the prod Worker deploy — add missing @elizaos/core stub exports (completes #12051 security promote)
…e stub exports (#12807) The #12051 develop→main promote brought code that imports two @elizaos/core symbols the Worker bundle's stub (wrangler [alias] target) does not export, so 'wrangler deploy' esbuild fails and the API Worker never shipped: - runWithTrajectoryPurpose — pulled in via @elizaos/shared email-classification; stubbed as a passthrough, same rationale as the existing runWithTrajectoryContext stub (no trajectory manager on the Worker). - fetchWithSsrfGuard — pulled in via plugin-elizacloud transcription (audioUrl fetch). Stubbed as a real Worker-safe port of core/network/fetch-guard (http(s)-only, blocked-hostname + private/reserved-IP-literal rejection incl. v4-mapped IPv6, manual redirect following with per-hop re-validation, cross-origin credential stripping, spec 301/302/303 GET rewrites, timeout wiring) — NOT a bare fetch passthrough, so the SSRF guarantee survives if the path ever runs on the Worker. DNS pinning is not portable to workerd (no node:dns) and is the one intentional delta. Deploy typecheck ('Verify Worker') resolves the real @elizaos/core types, so this class of break only surfaces at the wrangler bundling step; the stub parity test now imports and exercises both new exports so 'bun test' catches the next one. Unblocks the security promote (#11981 cross-org IDOR + #11943/#11958 app-key scope + money fixes) reaching the production Worker. Co-authored-by: nubs <nubsontopgang@gmail.com> Co-authored-by: Shaw <shawmakesmagic@gmail.com>
|
Heads-up: this promote's prod deploy FAILED at the wrangler Worker build (run 28680305905 — Fix is up: PR #12870 (Worker core-stub exports, #11845/#11875 drift class — dry-run build proof attached there). Note the develop deploy lane also has a second, independent blocker that must clear before the next promote ships: #12872 ( [cloud-security] |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
LifeOps Benchmark —
|
Promote develop → main (prod)
Carries 174 commits from develop to main, headlined by today's merged security fixes:
1e0f35c6fdGET /apps/:id, close the read-only cross-app row disclosure fix(cloud): close the #10852 app-key scope gap on frontend/review/backup routes [cloud-security] #11943 missed —2a4c7000bffad9bdf4d5plus the money fixes and general hardening merged to develop since the last promote.
Safety checks (pre-merge)
git merge-tree --write-tree origin/main origin/develop→ conflict-free (treebbf5d2f442), incl. no cloud-cf-deploy.yml conflict.packages/cloud/shared/src/db/migrations/0171_press_release_domain.sql(runs fail-closed on the prod approval gate).5161348e2a(accidental generated/asset files) is exactly reverted by0bc446f16e(net ~zero, restored to pre-fix(ios): keep KeepAwakeBridge core JavaScriptCore-free (unblocks full-Bun device build) #12016 treec9803c422); remaining WIP commits are test-only salvage.Merging with a merge commit (not squash) per promote convention.
— [cloud-frontdoor]