Skip to content

Fix/factory reset scope - #369

Open
Nuri1977 wants to merge 3 commits into
devfrom
fix/factory-reset-scope
Open

Fix/factory reset scope#369
Nuri1977 wants to merge 3 commits into
devfrom
fix/factory-reset-scope

Conversation

@Nuri1977

@Nuri1977 Nuri1977 commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Expanded factory reset safeguards with more reliable teardown of in-progress activity and queued work.
    • Improved reset reliability by adding clearer, more detailed cleanup/disconnect messaging and stricter modal protections.
  • Bug Fixes

    • Prevents database/components from starting while a reset is running.
    • Improved shutdown resilience using bounded timeouts, better failure guidance, and verified cancellation behavior.
    • Reset flow no longer triggers extra refetch/invalidation before relaunch.
  • Tests

    • Added/updated unit tests covering reset IPC delegation, modal loading/escape handling, credential cleanup, and task cancellation behavior.

Nuri1977 added 2 commits July 30, 2026 13:21
- clear browser storage, caches, databases, notebooks, and DuckLake state
- remove AI settings, MCP configuration, Agent Skills, and managed runtimes
- stop active agents, tasks, Flowfile, MCP, DuckDB, and database connections
- safely validate project and managed Rosetta paths before deletion
- delete and verify DBT Studio credentials without repeated macOS prompts
- prevent late database writes from recreating state during reset
- restart the app only after successful cleanup and verification
- update reset warnings, tests, Plan 54, and factory reset documentation
@Nuri1977 Nuri1977 self-assigned this Jul 30, 2026
@Nuri1977 Nuri1977 added bug Something isn't working enhancement New feature or request labels Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Factory reset now receives the Electron session, cancels active work, shuts down databases, clears credentials and application data with verification, relaunches after success, and prevents reset-dialog dismissal or renderer refetches during completion.

Changes

Factory reset lifecycle

Layer / File(s) Summary
Reset orchestration and IPC entry
src/main/ipcHandlers/settings.ipcHandlers.ts, src/main/services/settings.service.ts, tests/unit/main/...
The reset request passes the Electron session, deduplicates concurrent runs, applies bounded teardown timeouts, reports staged failures, and validates reset behavior through updated tests.
Active resource cancellation and database lifecycle
src/main/services/agent.service.ts, src/main/services/ai/agentEditorBridge.service.ts, src/main/services/taskManager.service.ts, src/main/services/duckdb.service.ts, src/main/services/mainDatabase.service.ts
Active agents, tasks, bridge requests, database connections, and initialization state are cancelled or cleared during factory reset.
Cross-platform credential cleanup
src/main/services/secureStorage.service.ts, tests/unit/main/services/secureStorage.service.test.ts
Credential cleanup adds serialized deletion and verification on non-macOS platforms, plus native macOS keychain deletion with not-found handling.
Reset dialog and renderer behavior
src/renderer/components/modals/resetFactoryModal/index.tsx, src/renderer/controllers/settings.controller.ts, src/renderer/components/settings/AboutSettings.tsx, tests/unit/renderer/components/ResetFactoryModal.test.tsx
The dialog blocks closing while reset is loading, documents the expanded cleanup scope, and renderer success handling no longer restarts or refetches before relaunch.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: jasir99

Sequence Diagram(s)

sequenceDiagram
  participant Renderer
  participant SettingsIPCHandler
  participant SettingsService
  participant AgentService
  participant DuckDBBootstrap
  participant MainDatabaseService
  participant SecureStorageService
  participant ElectronApp
  Renderer->>SettingsIPCHandler: invoke factory reset with session
  SettingsIPCHandler->>SettingsService: resetFactorySettings(session)
  SettingsService->>AgentService: cancel active agents and bridge requests
  SettingsService->>DuckDBBootstrap: beginFactoryReset()
  SettingsService->>MainDatabaseService: beginFactoryReset()
  SettingsService->>SecureStorageService: clearAllCredentials()
  SettingsService->>ElectronApp: relaunch and exit
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change: it points to a factory reset scope fix, which matches the PR’s broader factory reset handling updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/factory-reset-scope

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/services/duckdb.service.ts (1)

242-247: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reject DuckDB reinitialization while factory reset is active.

reinitialize() unconditionally clears DuckDBBootstrap.factoryResetInProgress, while beginFactoryReset() sets the same flag and waits for shutdown. A settings:duckdb:reinitialize call mid-reset can make the reset stop rejecting initialize(), allowing DuckDB to be reopened while reset cleanup is still in progress.

🔒 Possible guard
   static async reinitialize(options?: {
     dropExisting?: boolean;
   }): Promise<DuckDBMetadataPayload> {
+    if (this.factoryResetInProgress) {
+      throw new Error('DuckDB is unavailable during factory reset');
+    }
     // Close all connections
     await this.shutdown();
-    this.factoryResetInProgress = false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/services/duckdb.service.ts` around lines 242 - 247, Update
DuckDBBootstrap.reinitialize to reject immediately when factoryResetInProgress
is already true, before calling shutdown or modifying the flag. Preserve the
existing reinitialization flow for non-reset calls, and ensure beginFactoryReset
remains the owner of clearing the reset state after cleanup completes.
🧹 Nitpick comments (3)
tests/unit/main/services/secureStorage.service.test.ts (1)

36-139: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the untested failure branches.

The suite covers success, per-account failure, serialization, and macOS not-found handling, but doesn't exercise the non-macOS "remaining credentials after deletion" verification throw or the macOS generic-deletion-error throw. Since this code runs during an irreversible factory reset, covering these paths would increase confidence in the failure messaging.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/main/services/secureStorage.service.test.ts` around lines 36 -
139, Add tests for the uncovered failure branches of
SecureStorageService.clearAllCredentials: verify that on non-macOS it throws
when credentials remain after deletion, and that on macOS it throws when generic
service deletion fails with an error other than the handled not-found case.
Assert the expected failure messages while preserving the existing success and
handled-error coverage.
src/main/services/secureStorage.service.ts (1)

65-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Original error context is discarded when re-throwing.

Both the non-macOS aggregate-failure throw (Line 90-92) and the macOS catch (Line 118) replace the real underlying error with a generic message, losing the original message/stack. Since this only runs during factory reset — a destructive, hard-to-retry operation — the generic message surfaced to performFactoryReset's getSanitizedResetDetail makes production failures much harder to diagnose.

♻️ Preserve original error as `cause`
       } catch (error) {
         if (isMacKeychainItemNotFound(error)) return;
-        throw new Error('Failed to delete secure credential accounts');
+        throw new Error('Failed to delete secure credential accounts', {
+          cause: error,
+        });
       }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/services/secureStorage.service.ts` around lines 65 - 124, Preserve
underlying error context in both failure paths: update the aggregate failure
thrown by clearAllCredentials and the non-not-found error rethrown by
clearMacKeychainCredentials to include the original error as its cause. Track or
retain the relevant deletion error while preserving the existing failure counts
and generic messages, and keep isMacKeychainItemNotFound handling unchanged.
tests/unit/main/services/settings.service.test.ts (1)

144-188: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the full cleanup fan-out, not just DuckDB/session/credentials/fs.

The success test mocks TaskManagerService.cancelAll, AgentEditorBridgeService.resetForFactoryReset, FlowfileService.stop, MCPClientManager.disconnectAll, ConnectorsService.cleanupBigQueryKeyFiles, and the duckLake connection/adapter disconnects, but never asserts they were invoked. As currently written, a regression that silently drops one of these cleanup calls from resetFactorySettings would not be caught by this suite.

✅ Example additions to the success-path test
       expect(SecureStorageService.clearAllCredentials).toHaveBeenCalled();
+      expect(TaskManagerService.cancelAll).toHaveBeenCalled();
+      expect(AgentEditorBridgeService.resetForFactoryReset).toHaveBeenCalled();
+      expect(FlowfileService.stop).toHaveBeenCalled();
+      expect(MCPClientManager.disconnectAll).toHaveBeenCalled();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/main/services/settings.service.test.ts` around lines 144 - 188,
Expand the success-path test for SettingsService.resetFactorySettings to assert
every mocked cleanup dependency is invoked, including
TaskManagerService.cancelAll, AgentEditorBridgeService.resetForFactoryReset,
FlowfileService.stop, MCPClientManager.disconnectAll,
ConnectorsService.cleanupBigQueryKeyFiles, and the duckLake connection and
adapter disconnect methods. Keep the existing assertions and verify each call
with the expected arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/services/settings.service.ts`:
- Around line 606-610: Update the factory-reset failure handling in the catch
block around resumeAfterFailedFactoryReset() so the thrown error explicitly
tells the user that the application must be restarted after teardown has begun.
Preserve the sanitized stage detail and existing cleanup call, and ensure the
UI-facing message includes a clear restart-required instruction.
- Around line 752-762: The shutdown operations in performFactoryReset are
unbounded and can leave the reset modal stuck indefinitely. Add or reuse a
shared withTimeout/Promise.race helper to bound FlowfileService.stop,
MCPClientManager.disconnectAll, DuckLakeConnectionManager.disconnectAll,
CatalogAdapterFactory.disconnectAll, DuckDBBootstrap.beginFactoryReset, and
MainDatabaseService.beginFactoryReset, propagating a descriptive timeout failure
through the existing reset error handling.
- Around line 625-639: Update getSanitizedResetDetail to allow the macOS
secure-storage verification message prefix “Failed to verify secure credential
account removal” in its safe-prefix list, preserving the existing sanitization
behavior and the current “Failed to delete ” match.

In `@src/main/services/taskManager.service.ts`:
- Around line 110-132: Update TaskManager.cancelAll() to avoid marking or
discarding running tasks that have no registered canceller; preserve those tasks
for completion tracking and surface the inability to cancel so the factory-reset
flow can wait or fail. Keep cancellation, status updates, broadcasts, and
cleanup for tasks with a registered canceller, and align the behavior with
cancel(id).

In `@tests/unit/main/services/secureStorage.service.test.ts`:
- Around line 1-22: Move the SecureStorageService import above all jest.mock
declarations in this test file to satisfy the import/first ESLint rule. Keep the
existing mock definitions and test behavior unchanged.

In `@tests/unit/main/services/settings.service.test.ts`:
- Around line 98-102: Move the SecureStorageService, DuckDBBootstrap, and
MainDatabaseService imports to the top import block in
tests/unit/main/services/settings.service.test.ts, before all non-import
statements, preserving their existing paths and usage.

---

Outside diff comments:
In `@src/main/services/duckdb.service.ts`:
- Around line 242-247: Update DuckDBBootstrap.reinitialize to reject immediately
when factoryResetInProgress is already true, before calling shutdown or
modifying the flag. Preserve the existing reinitialization flow for non-reset
calls, and ensure beginFactoryReset remains the owner of clearing the reset
state after cleanup completes.

---

Nitpick comments:
In `@src/main/services/secureStorage.service.ts`:
- Around line 65-124: Preserve underlying error context in both failure paths:
update the aggregate failure thrown by clearAllCredentials and the non-not-found
error rethrown by clearMacKeychainCredentials to include the original error as
its cause. Track or retain the relevant deletion error while preserving the
existing failure counts and generic messages, and keep isMacKeychainItemNotFound
handling unchanged.

In `@tests/unit/main/services/secureStorage.service.test.ts`:
- Around line 36-139: Add tests for the uncovered failure branches of
SecureStorageService.clearAllCredentials: verify that on non-macOS it throws
when credentials remain after deletion, and that on macOS it throws when generic
service deletion fails with an error other than the handled not-found case.
Assert the expected failure messages while preserving the existing success and
handled-error coverage.

In `@tests/unit/main/services/settings.service.test.ts`:
- Around line 144-188: Expand the success-path test for
SettingsService.resetFactorySettings to assert every mocked cleanup dependency
is invoked, including TaskManagerService.cancelAll,
AgentEditorBridgeService.resetForFactoryReset, FlowfileService.stop,
MCPClientManager.disconnectAll, ConnectorsService.cleanupBigQueryKeyFiles, and
the duckLake connection and adapter disconnect methods. Keep the existing
assertions and verify each call with the expected arguments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0440fd45-51e8-42a3-85e7-3f3a360b4065

📥 Commits

Reviewing files that changed from the base of the PR and between f60f946 and 52465ce.

📒 Files selected for processing (15)
  • src/main/ipcHandlers/settings.ipcHandlers.ts
  • src/main/services/agent.service.ts
  • src/main/services/ai/agentEditorBridge.service.ts
  • src/main/services/duckdb.service.ts
  • src/main/services/mainDatabase.service.ts
  • src/main/services/secureStorage.service.ts
  • src/main/services/settings.service.ts
  • src/main/services/taskManager.service.ts
  • src/renderer/components/modals/resetFactoryModal/index.tsx
  • src/renderer/components/settings/AboutSettings.tsx
  • src/renderer/controllers/settings.controller.ts
  • tests/unit/main/ipcHandlers/settings.ipcHandlers.test.ts
  • tests/unit/main/services/secureStorage.service.test.ts
  • tests/unit/main/services/settings.service.test.ts
  • tests/unit/renderer/components/ResetFactoryModal.test.tsx

Comment thread src/main/services/settings.service.ts
Comment thread src/main/services/settings.service.ts
Comment thread src/main/services/settings.service.ts Outdated
Comment thread src/main/services/taskManager.service.ts Outdated
Comment thread tests/unit/main/services/secureStorage.service.test.ts Outdated
Comment thread tests/unit/main/services/settings.service.test.ts Outdated
- require an app restart after partial teardown failures
- sanitize macOS credential verification failure details
- add timeouts for factory-reset shutdown operations
- preserve running tasks without registered cancellers
- fail reset safely when background tasks cannot be cancelled
- fix import-first lint violations in service tests
- add regression tests for timeout and cancellation behavior

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/unit/main/services/taskManager.service.test.ts (1)

1-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider covering the "canceller throws" branch too.

The new test covers the no-canceller case but not the case where a registered canceller throws (Lines 123-128 in taskManager.service.ts), which also increments uncancelledTaskCount and is relied on by the factory-reset abort path.

➕ Suggested addition
it('counts a task whose canceller throws as uncancelled', () => {
  TaskManagerService.create({
    id: 'throwing',
    type: 'test',
    label: 'Throwing task',
    cancellable: true,
  });
  TaskManagerService.registerCanceller('throwing', () => {
    throw new Error('boom');
  });

  expect(TaskManagerService.cancelAll()).toBe(1);
  expect(
    TaskManagerService.list().find(({ id }) => id === 'throwing')?.status,
  ).toBe('running');
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/main/services/taskManager.service.test.ts` around lines 1 - 46,
Add a test alongside the existing TaskManagerService.cancelAll coverage that
registers a canceller which throws, then assert cancelAll returns 1 and the task
remains in running status. Use the existing create, registerCanceller,
cancelAll, and list APIs, and retain the current cleanup behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unit/main/services/taskManager.service.test.ts`:
- Around line 1-46: Add a test alongside the existing
TaskManagerService.cancelAll coverage that registers a canceller which throws,
then assert cancelAll returns 1 and the task remains in running status. Use the
existing create, registerCanceller, cancelAll, and list APIs, and retain the
current cleanup behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 847201ae-a5e7-4f25-b808-423ce09d3fc8

📥 Commits

Reviewing files that changed from the base of the PR and between 52465ce and f5bafc3.

📒 Files selected for processing (5)
  • src/main/services/settings.service.ts
  • src/main/services/taskManager.service.ts
  • tests/unit/main/services/secureStorage.service.test.ts
  • tests/unit/main/services/settings.service.test.ts
  • tests/unit/main/services/taskManager.service.test.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant