fix(desktop): keep machine onboarding for unrecognized identities after reset#2244
Merged
Conversation
…er reset After a dev-build sign-out+reset the Rust webview wipe targets the .app-bundle WebKit directory, which does not exist for `tauri dev` builds. The frontend's localStorage survived, including the active community entry. On relaunch the #1936 migration heuristic (migrateMachineOnboardingCompletion) counted that stale community as proof of prior completion, auto-marking the freshly generated key as onboarded and skipping machine onboarding entirely — landing the user in a half-onboarded relay-profile flow with no 'Use an existing key' option. Fix A (the regression): the hasConfiguredCommunity arm now checks Community.pubkey against the current pubkey. A community whose recorded pubkey doesn't match the live key is not a valid voucher. Absent pubkey (legacy entries predating the field) still vouches, so the veteran-upgrade path is preserved. Fix B (defence-in-depth): the sign-out confirm handler clears localStorage and sessionStorage on the resolve path only, covering the dev-build gap where the Rust wipe misses the process-keyed WebKit directory. The clear is a no-op in production (Rust already handles it) and intentionally does not run on the reject path (a failed sign-out must not wipe a still-running app). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
…oucher Thufir pass 1: addCommunity() in App.tsx's first-community flow and AppShell.tsx's add-community dialog both created records without stamping Community.pubkey. Any such record — including a current-format entry created in the session before a dev reset — lands in localStorage with pubkey absent. The previous migration treated absent-pubkey as a legacy signal and granted completion to every pubkey, so the regression was still reachable. This pass: - Stamps pubkey at both addCommunity call sites (App.tsx and AppShell.tsx) using the active identity pubkey at create time. - Removes the null-vouching arm from migrateMachineOnboardingCompletion: absent pubkey no longer vouches. A stale community without a stamp (legacy or pre-fix build) cannot trigger machine-onboarding bypass. - Adds the required regression case: absent-pubkey community + fresh identity → machine onboarding remains incomplete. - Updates currentPubkey in the useCallback deps array (biome lint). Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
seedDefaultCommunity() created the community without a pubkey field. With the strict migrateMachineOnboardingCompletion voucher (absent pubkey no longer grants), any test that seeds this community but skips the v1 onboarding-completion seed would be routed to machine onboarding — breaking six smoke E2E tests that use a Tyler identity. Pass the active identity pubkey into seedDefaultCommunity and stamp it on the fixture community, matching what production creation paths now do. Uses identity?.pubkey ?? DEFAULT_MOCK_PUBKEY so mock-mode tests (where the Tauri mock drives a deadbeef identity) also get a matched record. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
The previous stamp used identity?.pubkey ?? DEFAULT_MOCK_PUBKEY, which is always DEFAULT_MOCK_PUBKEY in mock mode regardless of seedActiveIdentity overrides. Tests that call seedActiveIdentity(BLANK_TYLER_IDENTITY) before installMockBridge() end up with a community stamped deadbeef... while the app identity is Tyler — strict matching rejects the voucher. Read buzz:e2e-identity-override.v1 from localStorage inside the init script (addInitScript runs in registration order, so the seedActiveIdentity write always precedes this read). Fall back to the passed pubkey (bridge identity in relay mode, DEFAULT_MOCK_PUBKEY for mock) only when no valid override exists. Mirror the storage key as a const in the init-script args so the script closure doesn't capture module-scope imports. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Mirror readStoredIdentityOverride()'s shape validation exactly: wrap the parse in try/catch and only set overridePubkey when privateKey, pubkey, and username are all strings. Malformed JSON, stored null, and partial objects (e.g. missing privateKey/username) now fall through to the fallback pubkey instead of throwing or accepting a shape that runtime readStoredIdentityOverride() would reject. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wesbillman
approved these changes
Jul 21, 2026
wpfleger96
enabled auto-merge (squash)
July 21, 2026 19:00
wpfleger96
disabled auto-merge
July 21, 2026 19:01
loganj
added a commit
that referenced
this pull request
Jul 21, 2026
…cache * origin/main: feat(desktop): fuzzy emoji shortcode autocomplete (#1945) Revert "feat(relay): inventory unreachable Git objects" (#2275) feat(relay): inventory unreachable Git objects (#2264) Keep avatar preview visible during upload (#2237) fix(desktop): keep machine onboarding for unrecognized identities after reset (#2244) fix(managed-agents): stale harness pin shadows runtime edits; add Restart quick action (#2252) fix(desktop): surface model discovery failures in agent config UI (#2246) Hide bundled harnesses from onboarding (#2233) relay: add author_type label to buzz_events_stored_total (#2243) fix(justfile): use Hermit-pinned lefthook in hooks recipe (#2241) Refresh README screenshots (#2236) fix(acp): pace relay observer frames (6/s + 90/min, zero burst) (#2217) Restore npub copy option for private community joins (#2232) fix(desktop): align onboarding runtime auth (#2229) fix(desktop): survive degraded networks with rate-limit-aware relay client (#2197) fix(cli): retry transient relay failures and raise timeouts (#2196) feat(desktop): browse immutable repository tags (#2231) Update built-in agent avatars (#2215) cleanup old AI doc (#2227) chore(release): release Buzz Mobile version 0.4.11 (#2225)
loganj
added a commit
to loganj/buzz
that referenced
this pull request
Jul 22, 2026
* origin/main: (24 commits) feat(relay): log NIP-98 pubkey attribution on HTTP bridge requests (block#2206) fix(ci): don't rebuild relay tests on every run (block#2203) fix(desktop): refresh cached channel member names (block#2258) chore(release): release Buzz Desktop version 0.4.22 (block#2220) feat(desktop): fuzzy emoji shortcode autocomplete (block#1945) Revert "feat(relay): inventory unreachable Git objects" (block#2275) feat(relay): inventory unreachable Git objects (block#2264) Keep avatar preview visible during upload (block#2237) fix(desktop): keep machine onboarding for unrecognized identities after reset (block#2244) fix(managed-agents): stale harness pin shadows runtime edits; add Restart quick action (block#2252) fix(desktop): surface model discovery failures in agent config UI (block#2246) Hide bundled harnesses from onboarding (block#2233) relay: add author_type label to buzz_events_stored_total (block#2243) fix(justfile): use Hermit-pinned lefthook in hooks recipe (block#2241) Refresh README screenshots (block#2236) fix(acp): pace relay observer frames (6/s + 90/min, zero burst) (block#2217) Restore npub copy option for private community joins (block#2232) fix(desktop): align onboarding runtime auth (block#2229) fix(desktop): survive degraded networks with rate-limit-aware relay client (block#2197) fix(cli): retry transient relay failures and raise timeouts (block#2196) ...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
After a dev-build sign-out+reset, the Rust webview wipe renames
~/Library/WebKit/<bundle_id>— the correct path for installed .app builds. Intauri devbuilds WebKit keys storage by process name (buzz-desktop/), so this wipe is a no-op and the frontend'slocalStoragesurvives the reset. ThemigrateMachineOnboardingCompletionheuristic added in #1936 then sees the stale active-community entry and auto-marks the freshly generated key as onboarded, skipping the machine-onboarding screen entirely — including the "Use an existing key" button.Fix A — pubkey-sound completion heuristic
migrateMachineOnboardingCompletioninmachineOnboarding.tsnow acceptsactiveCommunityPubkey: string | null | undefinedinstead of a barehasConfiguredCommunity: boolean. The community arm grants only when the recorded pubkey exactly matches the current pubkey — both absent pubkey (null) and no community (undefined) do not vouch.Community-creation paths now stamp
pubkeyat write time so that absent means genuinely pre-stamp:App.tsxfirst-community flow (handleCommunityOnboardingConnect): stampspubkey: currentPubkey ?? undefined, wherecurrentPubkeyis threaded down fromMachineBootstrap.AppShell.tsxonAddCommunitycallback: stampscommunity.pubkey ?? identityQuery.data?.pubkey. Note:AddCommunityDialognever calls itsonSubmitprop — it routes all submissions throughcommunityOnboarding.start— so this callback is currently unreachable. The stamp is correct if the dead prop is ever wired up; it costs nothing now.The other two migration arms (
completedLegacyOnboarding— already pubkey-scoped — andisSharedIdentity) are unchanged. Sprout-era veterans are safe:legacyCommunityStorage.tsmigratessprout-onboarding-complete.v1:<pubkey>→buzz-onboarding-complete.v1:<pubkey>on first Buzz launch, and the v1 key predates community storage (#386 vs #409), so every legacy community's creator already holds a pubkey-scoped v1 entry.Files:
machineOnboarding.ts,App.tsx,AppShell.tsxFix B — sign-out clears origin web storage on success
The confirm handler for "Delete My Data" in
ProfileSettingsCard.tsxnow callswindow.localStorage.clear()+window.sessionStorage.clear()immediately aftersignOut()resolves. This closes the dev-build gap directly at the sign-out call site.Files:
ProfileSettingsCard.tsxE2E fixture fix — seedDefaultCommunity pubkey stamp
seedDefaultCommunityindesktop/tests/helpers/bridge.tsnow stampspubkeyon the fixture community. The init script readsbuzz:e2e-identity-override.v1from localStorage (written byseedActiveIdentity, which always runs beforeinstallMockBridgeacross all affected specs), validates its shape against the same three-field check asreadStoredIdentityOverride()(privateKey,pubkey, andusernamemust all be strings), and uses the override pubkey when valid. Malformed JSON, storednull, and partial objects fall through to the fallback pubkey (identity?.pubkey ?? DEFAULT_MOCK_PUBKEY). This ensures the fixture community's provenance matches the active identity the strict voucher checks.Six previously-failing smoke specs now pass:
onboarding-avatar-skip.spec.ts(×5) andonboarding-docked-cta-screenshots.spec.ts(×1). These specs seedBLANK_TYLER_IDENTITYviaseedActiveIdentity+skipOnboardingSeed: true, so the default community was their only voucher.Files:
desktop/tests/helpers/bridge.tsTests
Seven unit tests in
machineOnboarding.test.mjs:null) → NOT vouched (stale current-format community + no stamp + fresh identity)undefined) → NOT vouchedv1completion key → grantedPlaywright coverage:
onboarding-avatar-skip.spec.ts(5/5),onboarding-docked-cta-screenshots.spec.ts(3/3),onboarding.spec.ts(57/57),deep-link-invite.spec.ts(included in combined run above, no regressions).import.meta.envguardforceMachineOnboarding()readsimport.meta.env.DEV— Vite inlines this at bundle time, but the Node test runner has noimport.meta.env. Added?.DEVoptional chain so the function returnsfalsein test context. No behavior change in any built artifact.