chore(deps): bump github.com/pion/webrtc/v4 from 4.0.0 to 4.2.3 in /apps/agent - #6
Conversation
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
Bumps [github.com/pion/webrtc/v4](https://github.com/pion/webrtc) from 4.0.0 to 4.2.3. - [Release notes](https://github.com/pion/webrtc/releases) - [Commits](pion/webrtc@v4.0.0...v4.2.3) --- updated-dependencies: - dependency-name: github.com/pion/webrtc/v4 dependency-version: 4.2.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
408f15c to
eb22e2c
Compare
|
@dependabot rebase |
|
The dependabot.yml entry that created this PR has been deleted so this PR can't be rebased. Please close the PR so Dependabot can create a new one with the current dependabot.yml. |
|
Closing: the Go agent was moved from apps/agent/ to agent/. These dependency updates target the old path. Dependabot should auto-create new PRs for agent/ (see dependabot.yml). |
|
OK, I won't notify you again about this release, but will get in touch when a new version is available. If you'd rather skip all updates until the next major or minor version, let me know by commenting If you change your mind, just re-open this PR and I'll resolve any conflicts on it. |
Database-layer hardening following the RLS security review. The app previously connected as POSTGRES_USER (SUPERUSER with BYPASSRLS), making every RLS policy a no-op. Closes that gap and fixes every hole that was hiding behind it. - Add unprivileged breeze_app role (NOSUPERUSER, NOBYPASSRLS) via new ensureAppRole bootstrap in autoMigrate. API connects via DATABASE_URL_APP with a startup warning if the connected user still has BYPASSRLS. (Finding #1) - Rewrite broken backup/DR/C2C/vault policies that referenced an unset session variable app.current_org_id. 15 tables now use breeze_has_org_access(org_id) + FORCE ROW LEVEL SECURITY. (Finding #2) - Add org_id column + RLS policies to device_metrics, backfilled from parent devices table. (Finding #3) - Restrict cis_check_catalog write policies to system scope. (Finding #4) - Replace withSystemDbAccessContext with org-scoped contexts in AI agent services (aiAgentSdk, aiAgentSdkTools, scriptBuilder, streamingSessionManager). Capture canonical orgId on ActiveSession. (Finding #5) - Fix 13 runOutsideDbContext sites in commandQueue and backup restore/vmrestore that would have silently failed once BYPASSRLS is removed. (Finding #7) audit_logs NULL org_id (Finding #6) is intentional and unchanged — system-level events are only visible to system scope by design. Verified: 3114/3120 API tests pass; same 6 pre-existing failures in enrollmentKeys_installer.test.ts on main. Manual DB check: breeze_app sees 0 devices without scope, 6 with system scope — RLS now enforced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e fixes Addresses review findings on PR #389 (heartbeat starvation instrumentation): CRITICAL #1 -- timedRWMutex now instruments write-lock HOLD time in addition to wait time. Long holds under contention (e.g. handleConnection holding b.mu.Lock across a 15s SendCommandAndWait) were invisible to the existing wait-only instrumentation, defeating the diagnostic goal for the exact bug class it was designed to surface. Implementation tracks acquiredAt inside Lock()/Unlock() -- safe because exactly one writer holds the lock at a time. Read-lock hold time is NOT instrumented: a single field is racy with multiple concurrent RLock holders, and alternatives (gid maps, tokens, atomic pointers) either race or uglify the API. RLock holders in this broker never perform long-blocking work, so instrumenting Lock holds alone captures the dangerous class of bug. slowLockThreshold extracted to a package var (1s default) so tests can shorten it. CRITICAL #2 -- snapshotSessions now copies the live map inside the locked fallback path instead of returning it and iterating after the deferred RUnlock fires. A one-time WARN log is emitted via atomic.Bool if the fallback ever fires in production (tests construct Broker{} directly). IMPORTANT #3 -- sendHeartbeatWithWatchdog uses `defer close(done)` so a panic in sendHeartbeat cancels the watchdog instead of letting it dump a misleading "exceeded 15s" warning. sync.Once removed (the select fires at most once). heartbeatWatchdogTimeout extracted to a package var and a sendHeartbeatFn field added to *Heartbeat so tests can inject fast/slow implementations and a short timeout without waiting 15 real seconds. IMPORTANT #4 -- Session.GetCapabilities() added. It takes s.mu.Lock() and returns a copy. All snapshot-path readers (FindCapableSession, preferredDesktopSessionFromSnap, preferredDesktopSessionLocked, reapIdleSessions) now go through it instead of reading s.Capabilities directly. Before PR #389, b.mu.RLock() accidentally serialised those reads with SetCapabilities writers; with the snapshot refactor the accidental protection is gone and direct reads race under -race. The log site inside TypeCapabilities handling now reads from the locally-held sanitized copy instead of a post-Set read of s.Capabilities. IMPORTANT #5 -- TCCStatus now loads b.snap directly and only falls back to snapshotSessions when snap is nil. Eliminates the ad-hoc partial sessionSnapshot construction (byIdentity was nil) that would silently break any future reader touching snap.byIdentity. publishSnapshotLocked is now the sole construction site for sessionSnapshot outside the fallback. IMPORTANT #6 -- BenchmarkFindCapableSessionUnderConcurrentConnections now asserts FindCapableSession returns non-nil. The benchmark pre-registers capture-capable sessions in WinSessionID "1" and write-storm goroutines only churn storm-* sessions, so nil indicates a regression. Suggestions applied: noCopy sentinel on timedRWMutex for go vet, sync/atomic merged into the sync import group, callerName closure-suffix stripping fixed to handle both "-" and "." separators, CloseSessionsByDesktopContext stale-snapshot latency window documented. All tests pass with -race. No public API changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Database-layer hardening following the RLS security review. The app previously connected as POSTGRES_USER (SUPERUSER with BYPASSRLS), making every RLS policy a no-op. Closes that gap and fixes every hole that was hiding behind it. - Add unprivileged breeze_app role (NOSUPERUSER, NOBYPASSRLS) via new ensureAppRole bootstrap in autoMigrate. API connects via DATABASE_URL_APP with a startup warning if the connected user still has BYPASSRLS. (Finding #1) - Rewrite broken backup/DR/C2C/vault policies that referenced an unset session variable app.current_org_id. 15 tables now use breeze_has_org_access(org_id) + FORCE ROW LEVEL SECURITY. (Finding #2) - Add org_id column + RLS policies to device_metrics, backfilled from parent devices table. (Finding #3) - Restrict cis_check_catalog write policies to system scope. (Finding #4) - Replace withSystemDbAccessContext with org-scoped contexts in AI agent services (aiAgentSdk, aiAgentSdkTools, scriptBuilder, streamingSessionManager). Capture canonical orgId on ActiveSession. (Finding #5) - Fix 13 runOutsideDbContext sites in commandQueue and backup restore/vmrestore that would have silently failed once BYPASSRLS is removed. (Finding #7) audit_logs NULL org_id (Finding #6) is intentional and unchanged — system-level events are only visible to system scope by design. Verified: 3114/3120 API tests pass; same 6 pre-existing failures in enrollmentKeys_installer.test.ts on main. Manual DB check: breeze_app sees 0 devices without scope, 6 with system scope — RLS now enforced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…500) ## Summary Closes 13 of 14 findings from the 2026-04-20 security review of `feature/device-org-move-wip`. 12 discrete tasks + 2 correction commits, each independently revertible. Full plan: `docs/superpowers/plans/2026-04-20-security-review-remediations.md`. ## Findings addressed | # | Sev | Area | Fix | |---|---|---|---| | #1 | HIGH | uninstall scripts | Publish SHA256SUMS + surface hash/verify cmd in `AddDeviceModal` | | #2 | HIGH | public-download token in URL | One-time Redis handle via new `POST /enrollment-keys/:id/download-handle`; back-compat `?token=` path retained with deprecation warning | | #3 | HIGH | enrollment-key write routes unrated | New `userRateLimit` middleware (10/60s per user) on all 5 write routes (create / rotate / delete / installer-link / bootstrap-token) | | #4 | MEDIUM | 8h viewer JWT | Dropped to 2h; added `jti` claim; Redis-backed revocation + per-tunnel-session revoke-on-close | | #5 / #6 | MEDIUM | tunnels.ts `:id` / `siteId` unvalidated | `zValidator('param'/'query', …)` on 7 routes | | #7 | MEDIUM | install.bat template | `assertValidEnrollmentKey` (64-hex regex) + quoted `ENROLLMENT_KEY` | | #8 | MEDIUM | viewer HTTP allowlist | `isLocalhost()` replaces `isPrivateHost()` — 127.0.0.1 / ::1 / localhost only | | #9 | MEDIUM | VNC server reason → UI | `KNOWN_VNC_REASONS` allowlist + `friendlyReason()` fallback (incl. ARD form) | | #10 | MEDIUM | siteId ownership on enroll create | Query `sites` WHERE `sites.orgId = orgId` before insert | | #12 | MEDIUM | short-link claim race | Atomic UPDATE folds expiry + max-usage into WHERE; claim-before-insert | | #13 | LOW | helper install templates | `Exec=%q` on Linux; `xml.EscapeText` on Darwin plist | | #14 | LOW | session config perms | 0644 → 0600 on 3 write sites | Finding #11 (encrypted `enrollment.json` inside installer zip) and other low-severity items were intentionally deferred — documented in the plan's "Out of scope" section. ## Test plan - [x] API: `pnpm --filter @breeze/api test:run` — 3247 passed, 25 skipped - [x] Viewer: `npx vitest run` in `apps/viewer` — 114 passed - [x] Web: `npx vitest run` in `apps/web` — 279 passed - [x] Agent helper: `cd agent && go test -race ./internal/helper/...` — ok - [ ] Manual smoke: trigger a macOS installer download from staging and confirm the agent enrolls (exercises finding #2 + #7 + #10 end-to-end). - [ ] Manual smoke: open a WebRTC session, hit DELETE `/tunnels/:id`, confirm the viewer sees a 401 on its next poll (exercises finding #4). - [ ] Visual review: uninstall-script SHA256 block renders correctly below each download link. ## Notes for the reviewer - Two commits (`7db3b1fb`, `845e2483`, `6be03849`) have muddled boundaries because several subagents staged changes concurrently in the same worktree. The tree state is correct; only the commit-per-task narrative got blurred. Squash-merge will render this moot. - `enrollmentKeys.ts` grew to 1333 lines. It's cohesive but approaching hard-to-navigate; candidate for a follow-up split of `publicEnrollmentRoutes` + `publicShortLinkRoutes` + `serveInstaller` into a `enrollmentKeys.public.ts`. - `/:id/download-handle` uses `===` on SHA-256 digests rather than `timingSafeEqual`. Low risk given both sides are digests + the route is auth-gated + rate-limited, but the convention elsewhere (`apiKeyAuth.ts`) uses `timingSafeEqual`. Trailing TODO worth picking up. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… fix (#753) ## Summary - Phase 1: cursor fan-out for `alertWorker` and `offlineDetector`, plus an env-tunable per-run cap on `staleCommandReaper`. Removes implicit fleet-size caps in the alert/offline/reaper jobs. - Phase 2: seven `CREATE INDEX IF NOT EXISTS` migrations targeting `/devices`, `/alerts`, `audit_logs`, `device_software`, `script_executions`, `device_patches`, and `agent_logs`. Plain (non-concurrent) `CREATE INDEX` because `autoMigrate` wraps each migration in a transaction; `CONCURRENTLY` requires running outside a tx. - Phase 2.2 (bug fix, load-bearing): rewrite of `breeze_accessible_org_ids` / `breeze_accessible_partner_ids` to drop the plpgsql `EXCEPTION WHEN others` blocks. Without this, the Phase 2 indexes will crash `/devices` on any partner-scope tenant. - Phase 3 (server side only): additive cursor pagination for `/mobile` list endpoints. Existing page-based callers unchanged. ## Why this batch The RLS helper rewrite is the load-bearing reason these ship together. `2026-05-17-e` (already in this PR set) marks `breeze_accessible_org_ids` and `breeze_accessible_partner_ids` as `PARALLEL SAFE LEAKPROOF`, but the bodies still wrap the parse in `EXCEPTION WHEN others`. Postgres `EXCEPTION` blocks create implicit subtransactions, which cannot run inside parallel workers. The label is honored, the runtime is not. In steady state on small fleets the planner doesn't choose parallel scans, so this is latent. Once the Phase 2 indexes land and `/devices` starts going parallel on partner-scope reads, every request 500s with: ``` cannot start subtransactions during a parallel operation ``` Reproduced this in production tonight on a 78-device fleet. Phase 2 indexes alone made `/devices` unreachable for partner-scope users; the `2026-05-18-a` rewrite (regex pre-validation, same fail-closed semantics, no implicit subtransaction) restored it. Anyone deploying the Phase 2 indexes without the rewrite will hit this. ## Verified numbers (production, 78-device fleet) - `GET /devices?limit=500` partner scope: 10s timeout → 154ms. Crash fixed by the RLS rewrite; latency gain stacks on top of the LATERAL+LIMIT 1 work in #747. - `audit_logs` org-scoped list query (`WHERE org_id = ? ORDER BY timestamp DESC LIMIT 50`): pre-index pattern was Parallel Seq Scan over the full table (~140ms+ on 448k rows). Post-index is Index Scan on `audit_logs_org_timestamp_idx`, **0.43ms execution / 52 buffer hits** at 448k rows. Scales as `O(log n)` instead of `O(n)`. - `alertWorker` on a 78-device fleet: with cursor fan-out enabled, `[AlertWorker] Evaluate-all completed: 71/72 devices queued` consistently across last 10 runs (live log, this PR's branch). The prior `Math.min(100)` cap was the difference between alerting ~1.7% of fleet per cycle and 100% at 10k. ## Commits ``` 1461910 perf(db): add scale-readiness indexes (Phase 2: S4-S8) 9dbf925 perf(jobs): cursor fan-out for alertWorker + offlineDetector (Phase 1: S1+S2) b943fc7 perf(jobs): raise StaleCommandReaper per-run cap to env-tunable 5000 (Phase 1: S3) e635413 perf(db): add device_patches scale indexes + agent_logs composite (Phase 2.1) e17a829 perf(db): rewrite RLS helpers to drop EXCEPTION blocks (Phase 2.2) 40dd3be feat(api): /mobile cursor pagination — additive (Phase 3: PR-S9 server-side) ``` Branch: `bdunncompany:scale-pack-pr-2026-05-18` (cherry-picked clean from `bdunncompany:scale-readiness-2026-05-17`; Huntress integration fixes on the source branch are intentionally excluded and would land separately). Compare: `main...bdunncompany:scale-pack-pr-2026-05-18` ## Migrations (all idempotent) ``` 2026-05-17-a-devices-scale-indexes.sql 2026-05-17-b-alerts-scale-indexes.sql 2026-05-17-c-audit-logs-scale-indexes.sql 2026-05-17-d-device-software-script-executions-indexes.sql 2026-05-17-e-rls-helpers-leakproof-parallel-safe.sql 2026-05-17-f-device-patches-indexes.sql 2026-05-17-g-agent-logs-composite-index.sql 2026-05-18-a-rls-helpers-parallel-safe-rewrite.sql ``` Safety notes: - Index migrations use `CREATE INDEX IF NOT EXISTS`. Plain (non-concurrent) `CREATE INDEX` takes a `SHARE` lock on the target table for the build — blocks writes, allows reads. Re-running on a populated DB is a no-op (IF NOT EXISTS). - `2026-05-17-e` (already in tree) and `2026-05-18-a` are `CREATE OR REPLACE FUNCTION`, preserving signatures and return types; `2026-05-18-a` additionally drops the `EXCEPTION` block from two helpers so the existing `PARALLEL SAFE` marker is no longer a lie. No call-site changes. - `autoMigrate.test.ts` (filename-sort regression) clean against the set. ## Test plan - `apps/api/src/jobs/alertWorker.test.ts` — 6 tests covering single-chunk fan-out, multi-chunk pagination, `ALERT_WORKER_MAX_DEVICES_PER_RUN` cap enforcement + warning, `cap=0` unlimited semantics, caller-supplied `batchSize` back-compat, and empty-fleet handling. - `apps/api/src/jobs/offlineDetector_fanout.test.ts` — 5 tests covering the same shape on `OFFLINE_DETECTOR_MAX_DEVICES_PER_RUN`. - `apps/api/src/routes/mobile.cursor.test.ts` — 6 tests on the new `encodeCursor` / `decodeCursor` helpers (round-trip, ISO string input, null/empty guards, garbage-input fail-closed, URL-safe base64url output). - `apps/api/src/db/autoMigrate.test.ts` — 27 tests, all green; includes the filename-sort regression that catches `-a-`/`-b-` ordering bugs. - Production smoke (single 78-device partner-scope tenant, 2026-05-17 → 2026-05-18 UTC): ran the full migration set + Phase 1 job changes; hit `/devices`, `/alerts`, `/audit_logs`, `/mobile` endpoints; observed the numbers above. Pre-rewrite, `/devices` 500'd with "cannot start subtransactions during a parallel operation"; post-rewrite (`2026-05-18-a`) and API restart to flush stale prepared-statement plans, 0 occurrences in subsequent 30+ min. ## Coverage against the local audit Tier 0: #1 alertWorker cap, #2 offlineDetector cap, #3 staleCommandReaper cap, #4 mobile pagination (server side only here; mobile client follow-up). Tier 1: #5 alerts indexes, #6 devices indexes. Tier 2: #17 audit_logs indexes, #20 device_software, #21 script_executions, #23 RLS helpers parallel-safe. ## Related - Builds on #747 (LATERAL+LIMIT 1 for `/devices` latest-metrics) and #748 (limit cap raise to 500). - Cursor pagination Path B: Discussion #742 (LATERAL latest-metrics + cap lift + server-side pagination plan). - Happy to split this into smaller PRs (Phase 1 jobs / Phase 2+2.2 DB / Phase 3 /mobile) if that's easier to review — say the word.
…977) ## Summary Closes launch-readiness **DR gap #6** ("no proven backup restore"). `backup.sh` and `restore.sh` already worked, but the Postgres dump never left the droplet (a region/droplet loss took it with), and nothing exercised the restore path automatically — so "is the backup restorable?" was unproven. Two thin ops scripts (they reuse the existing tested `backup.sh`/`restore.sh` rather than reimplementing dump/restore logic): - **`scripts/ops/offsite-backup.sh`** — runs `backup.sh --db`, then uploads the dump (plus a stable `db/latest.dump` pointer, and optionally the encrypted config bundle) to an off-region S3-compatible bucket. On DigitalOcean, that's a **Spaces bucket in a different region than the droplet**; enable versioning + noncurrent-version expiry so a corrupt/encrypted dump can't clobber good history. - **`scripts/ops/restore-test.sh`** — pulls `latest.dump` from the off-region bucket, restores it into a throwaway dockerized Postgres via `restore.sh`, asserts a sane `devices` row count, tears the scratch DB down, and POSTs to `RESTORE_TEST_ALERT_URL` (Slack/Alertmanager) on failure. A green weekly run is the proof-of-restorability artifact the checklist (and underwriters) ask for. - **`DISASTER_RECOVERY.md`** — documents the one-time Spaces setup, env vars, and the daily-backup + weekly-restore-test cron. ## Why scripts, not app code This gap is operational. The restore test deliberately runs against a disposable container so it can't touch prod, and routes through `restore.sh` so it tests the *real* recovery path operators would use by hand. ## Test plan - [x] Verified end-to-end locally: dumped the running `breeze` DB (1.7M, `-Fc`), spun up `postgres:16`, restored via `pg_restore --clean --if-exists`, asserted **8 devices**, torn down. - [x] `bash -n` clean on both scripts. - [x] `shellcheck` clean (one SC2329 false positive — `cleanup` is invoked via `trap ... EXIT`). - [ ] Deploy: create off-region Spaces bucket (versioning on), set `OFFSITE_S3_*` env on the droplet, install the two cron entries, confirm first weekly run goes green. ## Deploy notes Requires `docker`, `aws`, `pg_restore`, `psql` on the droplet. Cron + env are in the DR doc. Independent of PR #975 (anomaly alerting) — no shared files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
) (#997) Security-review batch 2. Each finding re-verified against source, fixed TDD, spec + quality reviewed, then run through a 5-agent PR review that caught and fixed a HIGH fail-open. - #10 agent-auth skip carve-out → exact-match allowlist (closes nested-/approve bypass) + regression test - #9 deleted dead optionalAuthMiddleware + eitherAuthMiddleware (fall-through bypass foot-gun) + docs fix - #6 drift-proof secret-key strip predicate (catches backup_s3_*) + Load read-back; strip now fails CLOSED - #8 secrets.yaml chmod-enforce failure fatal (agent.yaml stays 0644 Helper-readable) - #5 DNS-provider sync via DNS-pinning safeFetch; on-prem RFC1918 opt-in gated on explicit IS_HOSTED self-host signal (fail-closed); fixed a Critical IPv4-mapped-IPv6 hex-form metadata bypass in the shared SSRF guard (hardens webhooks/SSO/S1) - #7 access_reviews partner-axis rows → Shape-4 dual-axis RLS (DB-verified: contract test 17/17 + live cross-tenant forge rejected) - #3 accurate loud ENABLE_2FA warning (warn-only by design: no boot-refusal, no gate change) - #2 PAM actuate route gated OFF by default (PAM_ACTUATOR_ENABLED); Track-6 hardening deferred as design Excludes #1 (handled separately). Plan: docs/superpowers/plans/2026-05-29-security-review-batch2-fixes.md 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…rd controls Security review of the remote-desktop (WebRTC) pipeline found authorization was established only at connect/offer time and never re-enforced against, nor revocable from, a live session. Implements the 8 confirmed findings: - #1 Re-check remote-access policy at both WebRTC offer endpoints (JWT /offer and the viewer-token path) so disabling the policy blocks (re)starts. - #2 Send stop_desktop to the agent on session end/suspend and add agent-side idle + max-duration watchdog timers (enforces the previously-dead idleTimeoutMinutes / maxSessionDurationHours). - #3 Terminate a user's live remote sessions on deactivate/suspend and partner-abuse-suspend (new remoteSessionTeardown service). - #4 Recheck viewer-session revocation in the desktop-WS ping loop so a live legacy socket closes within one interval after revocation. - #5 Stop resurrecting ended sessions: reject disconnected/failed in validateViewerSessionAccess, drop endedAt:null resurrection from both offer sinks, revoke viewer tokens on the passive disconnect paths. - #6 Single-source the viewer-token TTL so the advertised expiry matches the real 2h signed TTL. - #7 Add a per-direction clipboard policy capability (host->viewer defaults off on hosted via IS_HOSTED); the agent enforces it since the viewer is untrusted. - #8 Audit clipboard and filedrop transfers (direction/size/filename). Tests: viewerTokenTtl.test.ts, clipboard gate_test.go, desktop policy parse test; updated existing mocks/test calls for the new signatures. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rd controls (#1020) ## Remote-desktop session security hardening Implements the 8 confirmed findings from the remote-desktop (WebRTC) pipeline security review. Root cause: authorization was established only at connect/offer time and was never re-enforced against, nor revocable from, a live session. **Findings fixed** - **#1** Policy re-checked at both WebRTC offer endpoints (JWT `/offer` + viewer-token path). - **#2** Server sends `stop_desktop` on end/suspend; agent gains idle + max-duration watchdog timers (enforces the previously-dead `idleTimeoutMinutes`/`maxSessionDurationHours`). - **#3** Live remote sessions terminated on user deactivate/suspend and partner-abuse-suspend (new `remoteSessionTeardown` service). - **#4** Viewer-revocation rechecked in the desktop-WS ping loop → live legacy socket closes within one interval. - **#5** No session resurrection: reject `disconnected`/`failed` in `validateViewerSessionAccess`, drop `endedAt:null` resurrection from both offer sinks, revoke on the passive disconnect paths. - **#6** Single-sourced viewer-token TTL (advertised == real 2h). - **#7** Per-direction clipboard policy capability; agent-enforced (channel/Watch/Receive gated). Host→viewer defaults **off** on hosted (`IS_HOSTED`). - **#8** Clipboard + filedrop transfer audit (direction/size/filename). **Tests added:** `viewerTokenTtl.test.ts`, `clipboard/gate_test.go`, `handlers_desktop_policy_test.go`; updated existing mocks/test calls for the new signatures. **Local verification:** API `tsc --noEmit` = 0 errors; targeted vitest 118 passed + `remote.test.ts` 15/15; agent `go test` clipboard/filedrop/heartbeat green (clipboard/heartbeat also under `-race`). **Pre-existing failures (not from this PR):** the full local `pnpm test` shows 12 failures across 10 files in unrelated subsystems (`oauthInteraction`, `partner_multi_org_orgid`/discovery-scan, `encryptedColumnRegistry`, …) — disjoint from this diff (which only touches remote-desktop), and all 5200 other tests pass. Relying on CI for the authoritative full-suite gate. **Decisions to confirm** - Clipboard host→viewer defaults **off on hosted** / on for self-hosted (preserve behavior); admin-overridable via policy. - #5 means a viewer that drops (tab crash / network blip) must create a **fresh** session to reconnect — flag for the web viewer UI. **Follow-ups:** route #8 audit into the central tamper-evident `audit_logs` (currently agent diagnostic logs); add a web UI toggle for the clipboard capability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t audit-list scope Follow-ups from the site-scope review's two product-judgment items: - alerts list (#7): the site narrowing used inArray(devices.siteId, allowed) over a leftJoin, which dropped org-wide alerts (deviceId null → null siteId never matches), silently hiding them from site-restricted users. Org-wide alerts are not site-bound, so narrow with or(isNull(alerts.deviceId), inArray(devices.siteId, allowed)) instead, and for a caller restricted to zero sites surface org-wide alerts (isNull) rather than short-circuiting to an empty list. TDD via PgDialect-serialized WHERE assertion. - auditLogs list (#6): confirmed org-level-by-design (compliance completeness; the details->>'rawActorId' device join is not a reliable site key). Added a rationale comment; no behavior change. alerts 24/24, auditLogs 13/13; tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t audit-list scope Follow-ups from the site-scope review's two product-judgment items: - alerts list (#7): the site narrowing used inArray(devices.siteId, allowed) over a leftJoin, which dropped org-wide alerts (deviceId null → null siteId never matches), silently hiding them from site-restricted users. Org-wide alerts are not site-bound, so narrow with or(isNull(alerts.deviceId), inArray(devices.siteId, allowed)) instead, and for a caller restricted to zero sites surface org-wide alerts (isNull) rather than short-circuiting to an empty list. TDD via PgDialect-serialized WHERE assertion. - auditLogs list (#6): confirmed org-level-by-design (compliance completeness; the details->>'rawActorId' device join is not a reliable site key). Added a rationale comment; no behavior change. alerts 24/24, auditLogs 13/13; tsc clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary - replace per-process tunnel websocket upgrade throttling with the shared Redis-backed sliding window limiter - fail closed through the existing rateLimiter helper when Redis is unavailable - add regression coverage for tunnel WS limiter wiring and denial behavior ## Security review - Covers playbook #6 remote access: WebSocket upgrade rate limiting for tunnel relay sessions. ## Tests - pnpm --dir apps/api exec vitest run src/routes/tunnelWs.test.ts src/routes/tunnels.test.ts - pnpm --dir apps/api exec tsc --noEmit --pretty false Co-authored-by: Todd Hebebrand <todd@lanternops.io>
…ope) PR #4: global env-configured PixlFlip OIDC consumer (not a per-org sso_providers row). New /api/v1/sso/pixlflip/login + /callback reuse services/sso.ts helpers; verify id_token via PixlFlip JWKS, read breeze_* claims (PR #3), provision into the breeze_org_id org as organization_users, mint org-scope tokens, hand off via the existing #ssoCode -> /sso/exchange grant. New pixlflip_sso_sessions table (no RLS, no provider FK) + migration; new PIXLFLIP_SSO_* env (disabled by default, fail-closed). Partner/system scope -> PR #5; user_sso_identities linking -> PR #6; web button + #ssoCode handoff -> PR #4b. Could not run pnpm typecheck/tests in sandbox (no node_modules) — rely on CI. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ope) (#3) PR #4: global env-configured PixlFlip OIDC consumer (not a per-org sso_providers row). New /api/v1/sso/pixlflip/login + /callback reuse services/sso.ts helpers; verify id_token via PixlFlip JWKS, read breeze_* claims (PR #3), provision into the breeze_org_id org as organization_users, mint org-scope tokens, hand off via the existing #ssoCode -> /sso/exchange grant. New pixlflip_sso_sessions table (no RLS, no provider FK) + migration; new PIXLFLIP_SSO_* env (disabled by default, fail-closed). Partner/system scope -> PR #5; user_sso_identities linking -> PR #6; web button + #ssoCode handoff -> PR #4b. Could not run pnpm typecheck/tests in sandbox (no node_modules) — rely on CI. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Hardens the agent→API trust boundary against a **compromised enrolled agent**, from a focused security review. 10 findings (5 HIGH, 5 MEDIUM) were independently verified, then fixed and re-verified. ## Findings & fixes **HIGH** - **#1 renew-cert quarantine bypass** — the route read org mTLS policy and wrote device state *after* its DB context closed, so under forced RLS as the unprivileged role those reads/writes silently returned 0 rows and a `quarantine` policy fell back to `auto_reissue`. Now reads policy + all device writes inside `withSystemDbAccessContext`, fails closed on a missing org row or any 0-row write, and only returns cert material after metadata persists (else revokes the issued cert). - **#2 previous-token self-renewal** — a superseded token (5-min grace) could mint durable new agent/watchdog/helper credentials. Now rejected (401) on both rotate-token and renew-cert; rotate-token UPDATE is a compare-and-swap bound to the authenticating token hash (409, mints nothing, on a losing race). - **#3 established WS bypass containment** — quarantine and tenant suspension/deletion didn't sever a live agent socket. Now they do; plus a lightweight per-message lifecycle recheck on the command-claim and command-result paths. - **#4 duplicate WS orphan** — a second socket replaced the tracked one without closing the first, leaving an orphan revocation couldn't reach. Now single-socket-per-agent (superseded socket closed on connect) with connection-identity-guarded ping state. - **#5 private-key redaction** — the agent regex missed PKCS#8 and left the key body intact. Now removes whole PEM blocks (PKCS#8 + RSA/EC/DSA/OPENSSH/ENCRYPTED), plus a server-side redaction layer at result ingest for pre-update agents. **MEDIUM** - **#6** CSV formula-injection — 5 web exporters now neutralize agent-controlled cells via the shared helper. - **#7** watchdog diagnostics never reached the API (wrong wire shape / status / false "completed"); now speaks the log contract and reports failure honestly. - **#8** WS command-result completions weren't audited (REST path was); now emit `agent.command.result.submit` once per real transition. - **#9** `logs.ts` ingest had no audit event; added a content-free one. - **#10** heartbeat overwrote security-relevant state with no history; now emits `agent.heartbeat.state_change` on genuine transitions only. ## PR-review follow-up (same branch) A multi-agent review verified the auth cluster clean (no bypass/RLS/silent-mint) and caught issues in the redaction layer, all fixed here: a **ReDoS** in the new server-side redactor (bounded → linear), an unredacted `error` field, truncated-key passthrough, and redaction parity (ported the agent's AWS-key/bearer/JWT/connection-string/secret-pair patterns server-side). ## Verification - `apps/api` typecheck clean; **171** unit tests pass - `apps/web` **15** tests pass - Go build + `-race` (executor / watchdog / breeze-watchdog) pass ## Pre-merge follow-ups (not done here) 1. **Real-Postgres integration test for renew-cert (#1).** The fix's premise — a contextless read returns 0 rows under forced RLS, a system-context read returns the real row — is proven only via mocks. Should be closed with one integration test against real Postgres per the repo's RLS-contract discipline. 2. **Cross-replica socket severance.** `disconnectAgent` is in-process only, so a live socket on another API replica isn't severed immediately on quarantine/tenant-suspension (mitigated by the per-message recheck; matches the existing decommission convention). Fine if prod is single-API-replica per region — worth confirming. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Todd Hebebrand <todd@lanternops.io> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Bumps github.com/pion/webrtc/v4 from 4.0.0 to 4.2.3.
Release notes
Sourced from github.com/pion/webrtc/v4's releases.
... (truncated)
Commits
0425062Update sctp to fix regression4a5fbf4Update module github.com/pion/interceptor to v0.1.434afaf3aEnsure candidate gathering promise completesb31a179SetConfiguration now updates ICEGatherer's serverscbaff19Add new repacketize example (#3350)a5962f3Fix divide by zero in IVF readerf5c73d2Upgrade to pion/transport v4e838d20Use the new HEVC depacketizerd35e49cUpgrade RTP for HEVC fixes1cf9c94Update module github.com/pion/stun/v3 to v3.1.1 (#3349)Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot mergewill merge this PR after your CI passes on it@dependabot squash and mergewill squash and merge this PR after your CI passes on it@dependabot cancel mergewill cancel a previously requested merge and block automerging@dependabot reopenwill reopen this PR if it is closed@dependabot closewill close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)