Skip to content

chore(deps): bump github.com/pion/webrtc/v4 from 4.0.0 to 4.2.3 in /apps/agent - #6

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/go_modules/apps/agent/github.com/pion/webrtc/v4-4.2.3
Closed

chore(deps): bump github.com/pion/webrtc/v4 from 4.0.0 to 4.2.3 in /apps/agent#6
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/go_modules/apps/agent/github.com/pion/webrtc/v4-4.2.3

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jan 14, 2026

Copy link
Copy Markdown
Contributor

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.

v4.2.3

Changelog

  • 0425062b2a86a3377a3f149e6bb50f5526179272 Update sctp to fix regression

v4.2.2

What's Changed

Special thanks to @​AkshayJainG for reporting and diagnosing several panic conditions in the IVF and OGG readers caused by malformed inputs. these fixes improve robustness when handling untrusted or malformed media inputs using ogg reader or ivf reader.

New Contributors

Full Changelog: pion/webrtc@v4.2.1...v4.2.2

v4.2.1

Changelog

  • a5ce25266ea8ca336f04dc9775d0809024b531f6 Assert no repair after stop
  • 48f7ac7c64851ad80cdbffcbc587fdb5651b23c1 Check for closed receiver before setting up rid

v4.2.0

We are pleased to announce our final and largest release of 2025. This release includes contributions from 69 contributors.

This release also marks a new era for Pion. Going forward, we will publish releases on a regular schedule.

Major new features

RACK

... (truncated)

Commits
  • 0425062 Update sctp to fix regression
  • 4a5fbf4 Update module github.com/pion/interceptor to v0.1.43
  • 4afaf3a Ensure candidate gathering promise completes
  • b31a179 SetConfiguration now updates ICEGatherer's servers
  • cbaff19 Add new repacketize example (#3350)
  • a5962f3 Fix divide by zero in IVF reader
  • f5c73d2 Upgrade to pion/transport v4
  • e838d20 Use the new HEVC depacketizer
  • d35e49c Upgrade RTP for HEVC fixes
  • 1cf9c94 Update module github.com/pion/stun/v3 to v3.1.1 (#3349)
  • Additional commits viewable in compare view

Dependabot compatibility score

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 rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot merge will merge this PR after your CI passes on it
  • @dependabot squash and merge will squash and merge this PR after your CI passes on it
  • @dependabot cancel merge will cancel a previously requested merge and block automerging
  • @dependabot reopen will reopen this PR if it is closed
  • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will 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 version will 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 dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

@dependabot @github

dependabot Bot commented on behalf of github Jan 14, 2026

Copy link
Copy Markdown
Contributor Author

Labels

The following labels could not be found: dependencies, go. Please create them before Dependabot can add them to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

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>
@dependabot
dependabot Bot force-pushed the dependabot/go_modules/apps/agent/github.com/pion/webrtc/v4-4.2.3 branch from 408f15c to eb22e2c Compare January 26, 2026 15:36
@ToddHebebrand

Copy link
Copy Markdown
Collaborator

@dependabot rebase

@dependabot @github

dependabot Bot commented on behalf of github Feb 8, 2026

Copy link
Copy Markdown
Contributor Author

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.

@ToddHebebrand

Copy link
Copy Markdown
Collaborator

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).

@dependabot @github

dependabot Bot commented on behalf of github Feb 8, 2026

Copy link
Copy Markdown
Contributor Author

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 @dependabot ignore this major version or @dependabot ignore this minor version. You can also ignore all major, minor, or patch releases for a dependency by adding an ignore condition with the desired update_types to your config file.

If you change your mind, just re-open this PR and I'll resolve any conflicts on it.

@dependabot
dependabot Bot deleted the dependabot/go_modules/apps/agent/github.com/pion/webrtc/v4-4.2.3 branch February 8, 2026 18:11
ToddHebebrand added a commit that referenced this pull request Apr 11, 2026
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>
ToddHebebrand added a commit that referenced this pull request Apr 11, 2026
…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>
ToddHebebrand added a commit that referenced this pull request Apr 11, 2026
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>
ToddHebebrand added a commit that referenced this pull request Apr 22, 2026
…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>
ToddHebebrand pushed a commit that referenced this pull request May 21, 2026
… 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.
ToddHebebrand added a commit that referenced this pull request May 29, 2026
…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>
ToddHebebrand added a commit that referenced this pull request May 29, 2026
) (#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)
ToddHebebrand added a commit that referenced this pull request May 31, 2026
…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>
ToddHebebrand added a commit that referenced this pull request May 31, 2026
…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>
ToddHebebrand added a commit that referenced this pull request Jun 1, 2026
…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>
ToddHebebrand added a commit that referenced this pull request Jun 1, 2026
…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>
ToddHebebrand added a commit that referenced this pull request Jun 20, 2026
## 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>
pixlflip referenced this pull request in PixlFlip-Enterprises/remuda-rmm Jun 20, 2026
…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>
pixlflip referenced this pull request in PixlFlip-Enterprises/remuda-rmm Jun 20, 2026
…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>
ToddHebebrand added a commit that referenced this pull request Jul 12, 2026
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant