Skip to content

fix(desktop): restrict shared-agent sync to dev data dirs#1597

Merged
wpfleger96 merged 1 commit into
mainfrom
wpfleger/fix-shared-sync-prod-guard
Jul 7, 2026
Merged

fix(desktop): restrict shared-agent sync to dev data dirs#1597
wpfleger96 merged 1 commit into
mainfrom
wpfleger/fix-shared-sync-prod-guard

Conversation

@wpfleger96

@wpfleger96 wpfleger96 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

this bit me on 2026-07-07: with BUZZ_SHARE_IDENTITY=1 and a valid BUZZ_PRIVATE_KEY in my shell, i ran open on a just desktop-release-build artifact. macOS open inherits the caller's environment, so the release build's sync_shared_agent_data saw the dev-share env vars and happily synced against xyz.block.buzz.app — the prod data dir. it deleted the real managed-agents.json, personas.json, and teams.json with no backup and replaced them with symlinks into the dev store.

two-part fix, now fully landed:

  1. dev-dir guard — extracted is_dev_data_dir_name(name: &str) -> bool and added it as an early-return guard in sync_shared_agent_data. it now returns immediately if the data dir name is not the canonical dev identifier (xyz.block.buzz.app.dev) or a dot-separated worktree variant (xyz.block.buzz.app.dev.my-branch). prefix collisions like xyz.block.buzz.app.developer correctly fail the check. the same predicate is now shared by run_boot_migrations and reconcile_target_dir, replacing their inline starts_with checks.

  2. backup-before-replace — introduced replace_with_symlink (moved into the shared util.rs module so other features can use it). when the destination is a real file or real directory, it renames it to <full-filename>.bak.<yyyymmdd-HHMMSS.ms> before creating the symlink. timestamps are millisecond-precision with a collision-safe -2-100 suffix probe. if the backup succeeds but the symlink creation fails, the helper attempts to rename the backup back and logs an actionable error if that rollback also fails. wrong or broken symlinks are still just removed — they carry no data worth backing up. the first-time sibling-dir seed block now goes through the same safe helper. stale-symlink removal logs on failure instead of silently discarding the error.

the shared util.rs module also exposes create_symlink (the unix/non-unix cfg wrapper) and symlink_points_to (raw link-value comparison without canonicalization, needed for relative symlink targets). repos.rs and nest.rs adopt these where the refactor is behavior-preserving; ensure_repos_symlink's "refuse non-empty real dir" policy stays unchanged since it has different semantics from backup-and-replace.

tempfile stays in [dependencies]nest.rs uses tempfile::NamedTempFile in production code for atomic writes to AGENTS.md and SKILL.md.

tests: 9 new tests in total — 4 predicate tests for is_dev_data_dir_name (including the prefix-collision case) and 5 helper-behavior tests for replace_with_symlink (file backup, dir backup, correct-symlink no-op, wrong-symlink replace, broken-symlink replace). full suite: 1011 passed, 0 failed.

sync_shared_agent_data's only guards were environmental
(BUZZ_SHARE_IDENTITY=1 + a parseable BUZZ_PRIVATE_KEY), so a release
build with the prod bundle identifier launched from an env-armed shell
(macOS `open` passes the caller's env) ran the dev shared-roster sync
against the prod data dir — deleting the real agent stores with no
backup.

- Gate the sync on the data-dir name: is_dev_data_dir_name (exact
  canonical dev identifier or dot-separated worktree suffix), shared by
  run_boot_migrations, sync_shared_agent_data, and reconcile_target_dir.
- Back up real files/dirs to timestamped .bak.* names (ms precision,
  collision-probed) instead of deleting; roll the backup back if the
  symlink fails; route the sibling seed path through the same helper.
- Extract create_symlink/symlink_points_to/backup_path/
  replace_with_symlink into util.rs and adopt them in repos.rs and
  nest.rs where behavior-preserving.
@wpfleger96 wpfleger96 force-pushed the wpfleger/fix-shared-sync-prod-guard branch from 2bd823f to 4ef8350 Compare July 7, 2026 21:15
@wpfleger96 wpfleger96 merged commit e5f831d into main Jul 7, 2026
41 of 47 checks passed
@wpfleger96 wpfleger96 deleted the wpfleger/fix-shared-sync-prod-guard branch July 7, 2026 21:35
tlongwell-block pushed a commit that referenced this pull request Jul 7, 2026
* origin/main:
  docs(readme): add Getting started section routing install paths (#1606)
  fix(desktop): restrict shared-agent sync to dev data dirs (#1597)
  feat(desktop): restart-required badge from spawn-time config hash (#1602)
  feat(desktop): boot-time reconcile of managed agents to relay events (#1601)
  feat(desktop): canonical <PubKey> component — hover to view/copy full keys, owner "you" labels (#1589)
  fix(desktop): hydrate reactions for Inbox context messages (#1596)
  fix: cleanup old screenshots that my agents committed (#1598)
  chore(release): release Buzz Desktop version 0.3.46 (#1585)
  fix(desktop): preserve agent model/provider when persona snapshot fields are blank (#1583)
  feat(acp,desktop): identify and reap stale agent harness processes (#1582)
  feat(desktop): active-draft badge, send-from-drafts confirm dialog, thread-deleted state (#1581)
  fix(desktop): treat baked build env vars as satisfying required agent config (#1580)
  feat(desktop): add "Copy image" to image right-click context menu (#1579)
  fix(nest): use buzz-dev symlink name for dev builds (#1587)
  fix(composer): address image-editor follow-up nits on #1491 (#1565)
  fix(desktop): render black static boot screen (#1570)
  feat(agents): group activity tool bursts (#1571)
  feat(desktop): aggregated overview rail, commit detail page, and full breadcrumbs (#1573)
  fix(desktop): fetch profiles for reaction actors and thread-reply authors (#1550)
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