镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Add native identity backup consent hooks - #1137

Merged
jmecom merged 6 commits into
mainfrom
jm/nsec-upload-explicit-opt-in
Oct 19, 2026
Merged

jmecom merged 6 commits into
mainfrom
jm/nsec-upload-explicit-opt-in

Conversation

@jmecom

@jmecom jmecom commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Prepare the native consent API for a later explicit automatic-backup selection, without changing onboarding, settings, or identity startup.

Public getBackupChoice() / setBackupChoice(pubkey, automatic) hooks persist a choice for the current key and trusted backup destination. Missing, corrupt, mismatched or self-managed choices cannot authorize uploads. Native read leases serialize admitted uploads against choice changes. Consent replacement syncs the file and, on Unix, its parent directory before reporting success. Plain sign-out retains the choice; erase removes it through the existing resumable wipe.

No uploader or copied HPKE code is introduced here. The next PR consumes the hooks.

Stack: #1137 consent hooks → #1106 gated uploader → #1107 recovery → #1101 restore UI.

Validation: seven focused configuration/consent tests and 51 erase tests passed on Blox, including fail-then-pass directory-sync regression evidence. Required local push hooks passed; five independent reviews found no remaining blockers. No browser journeys added or removed. Hosted CI is tracked in the PR checks. Native app, crash/power-loss execution and human acceptance remain pending. No real private keys were used.

jmecom and others added 5 commits October 14, 2026 15:08
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
Co-authored-by: Codex <codex@openai.com>
Signed-off-by: Jordan Mecom <jm@squareup.com>
@jmecom jmecom changed the title Make automatic identity backup an explicit onboarding choice Add native identity backup consent hooks Oct 14, 2026
@jmecom
jmecom added this pull request to stack #1148 October 14, 2026 23:24
@jmecom jmecom mentioned this pull request Oct 14, 2026

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Carl, an automated reviewer, commenting via Wes’s GitHub account.

Verdict: one major finding in this layer (inline), no other defects found. The consent read/lease logic and the config validation hold up.

The stack-wide scope concern (consent hooks with no production caller) is filed once on #1106.

Stack reviewed at #1137 9bac2d1 → #1106 417b30a → #1107 b3109cf → #1101 f3a5728 (base main 1ede3e3), with independent native, recovery and frontend lanes plus a cross-layer pass.

Not verified: live browser sign-in, KMS, installed-app secure-store behavior and runtime race ordering. Reviewers relied on existing CI and did not rerun suites locally.

Merge criteria: make a successful consent change crash-durable before #1106 relies on it.

.write_all(&serde_json::to_vec(&record).map_err(|_| FAILED)?)
.map_err(|_| FAILED)?;
staged.as_file().sync_all().map_err(|_| FAILED)?;
staged.persist(path).map_err(|_| FAILED)?;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Major: a successful consent revocation isn't crash-durable. set syncs the staged file and then renames it over choice.json, but never fsyncs the parent directory. Suppose choice.json holds automatic: true and the user turns backup off. The command returns success. If power is lost before the rename's directory entry is durable, the old true record can come back. With #1106 on top, the next authenticated pass reads that stale authorization and uploads the sealed nsec after the user opted out.

Fix: after persist, sync the parent directory on Unix, as nsec_backup/persistence.rs already does after its own replace. Only report success after that, and cover the sync failure path with a test.

@jmecom
jmecom marked this pull request as ready for review October 15, 2026 18:21
@jmecom
jmecom requested a review from a team as a code owner October 15, 2026 18:21
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: jm <jm@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
staged
.write_all(&serde_json::to_vec(&record).map_err(|_| FAILED)?)
.map_err(|_| FAILED)?;
staged.as_file().sync_all().map_err(|_| FAILED)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [P2] Persist the directory update before acknowledging consent changes.

Replacing an existing opt-in with false syncs the temporary file but returns after rename without syncing its parent directory. Power loss can leave the old valid opt-in, allowing a later authenticated matching-key upload despite the acknowledged opt-out. Keep the exclusive lease through parent-directory sync, propagate sync failures, and cover that failure path. This corroborates the existing durability feedback; the crash scenario was source-traced, not experimentally reproduced.

exportKey: () => invoke<string>("identity_export"),
/** Public consent only; reading or saving it does not start a backup. */
getBackupChoice: () => invoke<BackupChoice>("nsec_backup_choice"),
/** Pass the key returned by getBackupChoice so a stale selection cannot affect another key. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 The complete stack still has no production caller for these consent methods, so users cannot enable backup through the supplied UI. Searches of .github, scripts, justfile* and package.json also found no backup service URL/namespace configuration; this does not rule out external build configuration. Please wire the current consent consumer and intended build configuration, or explicitly document/approve this as staged infrastructure under the repository's current-caller requirement.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord’s automated source review via Wes’s account. Follow-up at head 65e3ab75be46106ac043967624b9da9b1c8b57fd, base 1ede3e310350a27dfe29c52fb6e2956dea7df3e5.

No additional changes requested in this follow-up (9/10). The prior durability finding is addressed: after replacing choice.json, the Unix path syncs the containing directory before returning success, while retaining the exclusive lease. The regression covers directory-open failure after replacement, reports failure rather than durable success, and then retries successfully. No new defect found in the two-file repair.

The separate stack-wide consent-selection concern remains tracked on #1106; this review does not establish that end-to-end backup consent is complete. Public description, commit messages and changed source/configuration inspected; no attached images.

Source-only: no code, tests, builds or app executed; current CI not assessed. Crash/power-loss durability, installed-app storage, cross-process ordering and human acceptance remain unverified. No UI/focus transition is changed by this repair. COMMENT only, not approval.

@kalvinnchau kalvinnchau left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Approved for staged infrastructure without a current consumer. The lock-contention hypothesis is a non-blocking follow-up; native acceptance and local test-failure attribution remain outstanding.

.create(true)
.truncate(false)
.open(path.with_extension("lock"))
.map_err(|_| FAILED)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 [P3, non-blocking hypothesis] Investigate transient lock contention around process spawning.

At stack tip d031907, intermittent native tests failed at consent/persistence lock acquisition, while 20 backup-only runs passed. A possible explanation is forked children retaining a lock file description until exec; this mechanism and its production impact are not proven. If confirmed, consent saves could report busy spuriously and backup passes could defer until another event. Reproduce the interaction before choosing bounded lock retry or another fix. The related persistence lock is in src-tauri/src/nsec_backup/persistence.rs:127 at that stack tip.

@jmecom
jmecom merged commit 7acfe81 into main Oct 19, 2026
58 of 61 checks passed
@jmecom
jmecom deleted the jm/nsec-upload-explicit-opt-in branch October 19, 2026 16:35
johnmatthewtennant added a commit that referenced this pull request Oct 19, 2026
* origin/main:
  Add native Huddles with call controls and conversation panels (#489)
  fix(claude-code): keep sessions alive while Claude's background work runs (#1102)
  Rename Agent setup "Providers" to "Harness defaults" (#1348)
  feat(plugins): feature core plugins and branded catalog browsing (#1246)
  Improve AI defaults and add Goose configuration (#1266)
  feat(sidebar): filter channel sections by unread and activity (#1297)
  feat(plugins): organize settings with guides and focused controls (#1176)
  Unify Solo chat menus, rename workspaces, quieter membership notices (#1326)
  Add identity restore UI (#1101)
  Add native identity backup recovery (#1107)
  Back up desktop identities only with saved consent (#1106)
  Add native identity backup consent hooks (#1137)
  remove the Channel Usage plugin (#1335)
  fix(messages): retain image geometry across virtualized remounts (#1271)
  fix(channels): read metadata for a labeled channel whose roster came first (#1289)
  fix(channel-members): allow adding members to system channels (#1288)
  fix(unread): recover dropped thread roots for unread thread activity (#1291)
  test(voice-notes): fix the draft-card race that turned main red (#1315)
  ci: check dependency policy with cargo-deny (#1321)

Signed-off-by: jtennant <jtennant@squareup.com>

# Conflicts:
#	src/bundled/inbox/InboxDetail.test.tsx
#	src/bundled/inbox/InboxDetail.tsx
johnmatthewtennant added a commit that referenced this pull request Oct 19, 2026
…x-session-preview-live

* origin/jt/inbox-page-tabs: (25 commits)
  refactor(inbox): open conversations through conversation.ui.Tabs
  fix(inbox): retire a Huddle room's retained tabs and keep their focus
  test(inbox): stop depending on Channels having loaded a thread's channel
  fix(inbox): close an opened conversation once its room becomes a Huddle
  Add native Huddles with call controls and conversation panels (#489)
  fix(inbox): offer no Archive shortcut while Drafts is shown
  fix(inbox): keep a restored tab's row selected after leaving Inbox
  fix(claude-code): keep sessions alive while Claude's background work runs (#1102)
  Rename Agent setup "Providers" to "Harness defaults" (#1348)
  feat(plugins): feature core plugins and branded catalog browsing (#1246)
  Improve AI defaults and add Goose configuration (#1266)
  feat(sidebar): filter channel sections by unread and activity (#1297)
  feat(plugins): organize settings with guides and focused controls (#1176)
  Unify Solo chat menus, rename workspaces, quieter membership notices (#1326)
  Add identity restore UI (#1101)
  Add native identity backup recovery (#1107)
  Back up desktop identities only with saved consent (#1106)
  Add native identity backup consent hooks (#1137)
  remove the Channel Usage plugin (#1335)
  fix(messages): retain image geometry across virtualized remounts (#1271)
  ...
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.

3 participants