Lock internal local agents to approved relays - #2582
Conversation
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
brow
left a comment
There was a problem hiding this comment.
🤖 Changes are still required because agent-keyed relay I/O remains unguarded outside the newly patched create/update paths:
confirm_agent_snapshot_importmints and persists aBackendKind::Localrecord with an empty pin, then sends its profile and any memory events to the effective workspace relay.confirm_team_snapshot_importdoes the same for every member. On an internal build using a public relay, these commands create local identities and attach them without policy validation. Validate before key mint/store mutation and before profile or engram I/O, preserving OSS behavior, with individual and team import regressions.reconcile_agent_profileresolves a local record's effective relay, then queries and may publish with the agent key without policy validation. This background path runs after start and restore. Carry the backend intoProfileReconcileDataand validate before either query or write, with legacy empty-pin coverage.update_personapublishes linked local-agent profile changes to each effective relay without policy validation. Validate each affected record before mutation/save or enqueueing profile sync, while keeping provider and OSS records unrestricted.
These paths are outside the PR diff, so GitHub cannot anchor inline comments to them. They are at desktop/src-tauri/src/commands/personas/snapshot/import.rs:508-570, desktop/src-tauri/src/commands/team_snapshot.rs:756-826, desktop/src-tauri/src/commands/agents_profile.rs:79-160, and desktop/src-tauri/src/commands/personas/mod.rs:257-305 at head 93ea37c2.
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
brow
left a comment
There was a problem hiding this comment.
🤖 Re-reviewed the full diff at adbc1112dae464f3ba687ea524b242cbebf4ce48. No blocking findings. The round-5 changes close snapshot import, profile reconciliation, and linked-persona profile-sync relay paths before key mint, persistence, query, or publish while preserving OSS/provider short-circuits. Prior membership, storage-remediation, create/update, start/probe/spawn, UI cache, and normalization fixes remain intact.
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
Co-authored-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz> Signed-off-by: npub102wg7q285p64ch2fjvstmf2ntn2sz3c4u5hmwatalc76mhsuauysftjtfj <7a9c8f0147a0755c5d499320bda5535cd5014715e52fb7757dfe3dadde1cef09@buzz.block.builderlab.xyz>
wpfleger96
left a comment
There was a problem hiding this comment.
🤖 The security design here is strong and I'd be happy to see it land — requesting changes only for two mechanical items below.
What I like, having walked all the enforcement seams: the allowlist is baked at build time with a base64 round-trip so cargo's line-oriented output can't truncate it (consistent with the existing BUZZ_BUILD_AGENT_ENV pattern); internal builds fail closed on a missing, empty, or malformed allowlist; matching is exact canonical origin via normalize_relay_url (case, default ports, and paths all normalize — verified against the tests) with no wildcard or hostname-suffix trust; and OSS builds plus provider-backed agents are cleanly out of scope. Enforcement covers every path I could find that puts a local agent on a relay: create, update (pin change and rename), the final spawn_agent_child chokepoint (which catches anything upstream missed), runtime pairs, the relay probe, profile reconcile, save-time validation of changed pins only (so a legacy bad pin stays listable/fixable/deletable — good remediation story), channel member add and role change, huddle start/add, and both snapshot import flows, plus the UI preflight that disables submit with a banner. The tests are discriminating — call-counters proving OSS never touches the agent store, fail-loud on a broken store, and preflight-before-mutation ordering. CI is fully green at head.
Blocking:
- The PR is currently conflicting with its base branch.
quietly/internal-owner-onlymerged main forward after this branch diverged, and four files conflict (desktop/scripts/check-file-sizes.mjs,desktop/src-tauri/build.rs,desktop/src/testing/e2eBridge.ts,desktop/tests/helpers/bridge.ts). They all look like the usual high-churn seams, so the resolution should be mechanical — but it needs a merge-forward/rebase before this can land. - The title needs a conventional-commit prefix — we squash-merge, so the PR title becomes the commit subject. Something like
feat(desktop): lock internal local agents to approved relays.
Minor, non-blocking:
validated_snapshot_import_relay_with(personas/snapshot/import.rs) andvalidated_team_snapshot_import_relay_with(team_snapshot.rs) are identical helpers in two files — could be one shared function.local_agent_relay_allowedcan never returnOk(false)— a blocked relay is anErr, and the frontend only checksisErrorand shows a hardcoded banner. ReturningOk(false)for the policy-blocked case (or surfacing the error text in the banner) would make the command's contract less surprising to the next caller.
Happy to approve once the base conflict is resolved and the title is fixed.
|
Nudge on behalf of @doph — high-priority merge list. Two things blocking:
@brow flagging so the stack + prefix can be sorted. 🐝 |
Summary
Internal (managed) builds now lock
BackendKind::Localagents to a baked-in relay allowlist. OSS builds and provider-backed agents keep unrestricted relay configuration.Bake a newline-delimited local-agent relay-origin allowlist into managed builds through
BUZZ_BUILD_LOCAL_AGENT_RELAY_ALLOWLISTat compile time.Require exact canonical WebSocket origin matches for local agents, with exact equality instead of wildcard or hostname-suffix trust.
Fail closed in internal builds when the allowlist is missing, empty, or malformed, or when the effective relay is not allowed. OSS builds and provider-backed agents bypass this policy.
Enforce the policy at every path that can put a local agent on a relay:
The spawn check is the final backstop. The earlier checks are still needed so users get a clear error at the action they took, before data is changed or relay work begins.
Importing an agent or team from a backup file creates fresh local agent identities, so the import checks the workspace relay before creating them. The import then keeps using that checked relay for the new agent's profile and memory, and does the same for every member of an imported team. This prevents a race where the relay setting changes mid-import.
A corrupted agent store is now preserved and reported as an error, and saving no longer treats a failed read as an empty store. Previously, a later save could silently replace the corrupted store from an empty starting point.
Show a warning and disable local-agent attachment when the active community's relay is blocked, with the relay-policy query keyed to the active community.
This PR is stacked on #2537. The two build variables serve different purposes:
BUZZ_BUILD_INTERNALmarks the distribution as an internal build, whileBUZZ_BUILD_LOCAL_AGENT_RELAY_ALLOWLISTsupplies the relay origins approved for that deployment.Packaging contract
Internal packaging must set both:
Future internal or staging origins must be explicit newline-delimited entries in
buzz-releases(Block-internal packaging configuration).Screenshots
Both screenshots are cropped to the same 576 x 398 dialog canvas.
Validation
At source commit
931865f0478b25e3566637dc824f7cc3a3e387a1, whose code was reapplied aseb7354dd, the full desktop Rust suite passed with 1,582 tests and 13 ignored tests, plus 3 diagnostic integration tests. TypeScript typechecking passed, all 3,402 JavaScript unit tests passed, and 2 focused browser tests passed for the blocked internal-build case and unaffected OSS case. Formatting, static checks, file checks, and commit hooks also passed.A separate internal-build test run confirmed the relay-policy behavior. Six existing tests from #2537 still encode OSS access expectations and fail when internal mode intentionally forces owner-only access.