Skip to content

fix(secrets): explain Linux basic_text storage fallback#2651

Open
rasitakyol wants to merge 2 commits into
generalaction:mainfrom
rasitakyol:fix/linux-basic-text-secret-storage-message
Open

fix(secrets): explain Linux basic_text storage fallback#2651
rasitakyol wants to merge 2 commits into
generalaction:mainfrom
rasitakyol:fix/linux-basic-text-secret-storage-message

Conversation

@rasitakyol

Copy link
Copy Markdown
Contributor

Summary

  • make the Linux basic_text secure-storage failure actionable by pointing users to GNOME libsecret / --password-store=gnome-libsecret
  • document the Linux secure keyring requirement in the README installation section
  • add a focused regression test for the basic_text failure path

Refs #1875

Test Plan

  • pnpm --dir apps/emdash-desktop exec vitest run --project node src/main/core/secrets/encrypted-app-secrets-store.test.ts
  • pnpm --filter @emdash/emdash-desktop run format:check
  • pnpm --filter @emdash/emdash-desktop run typecheck

@greptile-apps

greptile-apps Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR improves the Linux basic_text secure-storage failure by replacing a bare diagnostic message with an actionable one that tells users to install GNOME libsecret or pass --password-store=gnome-libsecret, and mirrors that guidance in the README installation section.

  • encrypted-app-secrets-store.ts: Error string in assertSecureStorageAvailable extended with concrete remediation steps; no logic changes.
  • encrypted-app-secrets-store.test.ts: New test verifies the basic_text path rejects with the flag hint and that encryptString is never reached; getSecret on the same path is not yet covered.
  • README.md: Short Linux keyring prerequisite paragraph added below the download table.

Confidence Score: 4/5

Safe to merge — the only code change is an extended error message with no logic alterations.

The source change is minimal and entirely contained to the error string. The new test exercises setSecret under the basic_text condition but leaves the getSecret read path without a corresponding assertion, so a regression on that path could go unnoticed.

apps/emdash-desktop/src/main/core/secrets/encrypted-app-secrets-store.test.ts — the getSecret basic_text path is untested.

Important Files Changed

Filename Overview
apps/emdash-desktop/src/main/core/secrets/encrypted-app-secrets-store.ts Error message for Linux basic_text backend extended with actionable fix instructions; logic is unchanged.
apps/emdash-desktop/src/main/core/secrets/encrypted-app-secrets-store.test.ts New test file covering the basic_text rejection path for setSecret; getSecret on the same failure path is not covered.
README.md Adds Linux keyring prerequisite note pointing users to GNOME libsecret and the --password-store flag.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[setSecret / getSecret called] --> B{isEncryptionAvailable?}
    B -- No --> C[throw: Secure secret storage is unavailable]
    B -- Yes --> D{platform === 'linux'?}
    D -- No --> E[proceed with encrypt/decrypt]
    D -- Yes --> F{getSelectedStorageBackend?}
    F -- 'basic_text' --> G["throw: Install GNOME libsecret\nor use --password-store=gnome-libsecret"]
    F -- other e.g. 'os_crypt' --> E
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[setSecret / getSecret called] --> B{isEncryptionAvailable?}
    B -- No --> C[throw: Secure secret storage is unavailable]
    B -- Yes --> D{platform === 'linux'?}
    D -- No --> E[proceed with encrypt/decrypt]
    D -- Yes --> F{getSelectedStorageBackend?}
    F -- 'basic_text' --> G["throw: Install GNOME libsecret\nor use --password-store=gnome-libsecret"]
    F -- other e.g. 'os_crypt' --> E
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/emdash-desktop/src/main/core/secrets/encrypted-app-secrets-store.test.ts:25-39
**`getSecret` `basic_text` path not exercised**

The test verifies that `setSecret` rejects before calling `encryptString` when the backend is `basic_text`, but `getSecret` also calls `assertSecureStorageAvailable` and would likewise throw on a `basic_text` Linux system. A user retrieving a previously-stored credential on an affected machine hits exactly this path. Adding a parallel assertion for `getSecret` (with a mocked DB row) would give the same safety net as the `setSecret` case and ensure both read and write paths are guarded by the improved error message.

Reviews (1): Last reviewed commit: "fix(secrets): explain Linux basic_text s..." | Re-trigger Greptile

Comment on lines +25 to +39
describe('EncryptedAppSecretsStore', () => {
it('explains how to fix Linux basic_text secure storage fallback', async () => {
const safeStorageApi = {
isEncryptionAvailable: () => true,
encryptString: vi.fn((value: string) => Buffer.from(value)),
decryptString: vi.fn((value: Buffer) => value.toString('utf8')),
getSelectedStorageBackend: () => 'basic_text',
};
const store = new EncryptedAppSecretsStore({} as never, safeStorageApi as never, 'linux');

await expect(store.setSecret('token', 'secret')).rejects.toThrow(
'--password-store=gnome-libsecret'
);
expect(safeStorageApi.encryptString).not.toHaveBeenCalled();
});

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 getSecret basic_text path not exercised

The test verifies that setSecret rejects before calling encryptString when the backend is basic_text, but getSecret also calls assertSecureStorageAvailable and would likewise throw on a basic_text Linux system. A user retrieving a previously-stored credential on an affected machine hits exactly this path. Adding a parallel assertion for getSecret (with a mocked DB row) would give the same safety net as the setSecret case and ensure both read and write paths are guarded by the improved error message.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/emdash-desktop/src/main/core/secrets/encrypted-app-secrets-store.test.ts
Line: 25-39

Comment:
**`getSecret` `basic_text` path not exercised**

The test verifies that `setSecret` rejects before calling `encryptString` when the backend is `basic_text`, but `getSecret` also calls `assertSecureStorageAvailable` and would likewise throw on a `basic_text` Linux system. A user retrieving a previously-stored credential on an affected machine hits exactly this path. Adding a parallel assertion for `getSecret` (with a mocked DB row) would give the same safety net as the `setSecret` case and ensure both read and write paths are guarded by the improved error message.

How can I resolve this? If you propose a fix, please make it concise.

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