Skip to content

fix(config): surface secret decryption failures#65

Merged
AmintaCCCP merged 1 commit intomainfrom
fix/config-secret-decrypt-status
Mar 25, 2026
Merged

fix(config): surface secret decryption failures#65
AmintaCCCP merged 1 commit intomainfrom
fix/config-secret-decrypt-status

Conversation

@AmintaCCCP
Copy link
Copy Markdown
Owner

@AmintaCCCP AmintaCCCP commented Mar 25, 2026

Summary

  • add observable secret decryption failure handling for AI configs, WebDAV configs, and GitHub token settings
  • keep config APIs responsive instead of failing the entire response when one stored secret cannot be decrypted
  • expose per-config secret status to the frontend and show a clear re-enter/save warning in Settings

What changed

  • Added backend logging when decrypting stored AI API keys, WebDAV passwords, or GitHub tokens fails.
  • Returned secret status metadata (ok, empty, decrypt_failed) for config reads.
  • Preserved graceful degradation: config lists still load even if one stored secret is invalid.
  • Added frontend warnings telling users to re-enter and save configs whose stored secret can no longer be decrypted.

Why

Issue #64 correctly pointed out that decryption errors were previously swallowed, which could make secrets appear empty without any explanation.

This PR fixes that without making the whole settings page fail just because one stored secret is broken.

Validation

  • npm run build

Closes #64

Summary by CodeRabbit

  • New Features
    • Configuration responses now include credential status indicators for AI keys and WebDAV passwords
    • Settings panel displays warning alerts when stored credentials fail to decrypt
    • Users are prompted to re-enter and save affected configurations

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

Centralized decryption error handling across config endpoints by introducing a shared SecretStatus type and getMaskedSecretResult() helper function. Updated API responses for AI configs, WebDAV configs, and GitHub token settings to include status fields indicating successful decryption, empty values, or decryption failures. Added frontend warnings to alert users when credentials fail to decrypt.

Changes

Cohort / File(s) Summary
Backend Type System & Helpers
src/types/index.ts, server/src/routes/configs.ts
Introduced SecretStatus type and getMaskedSecretResult() helper to standardize decryption validation and error handling. Updated /api/configs/ai, /api/configs/webdav, and /api/settings endpoints to return status fields (apiKeyStatus, passwordStatus, github_token_status) alongside masked secret values. Added structured warning logs for decryption failures.
Frontend Warnings
src/components/SettingsPanel.tsx
Added conditional amber warning messages in AI and WebDAV configuration lists that display when decryption fails (decrypt_failed status), prompting users to re-enter and save credentials.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client (Frontend)
    participant API as Backend API
    participant Crypto as Crypto Handler
    
    Client->>API: GET /api/configs/ai?decrypt=true
    API->>Crypto: getMaskedSecretResult(encryptedKey)
    
    alt Decryption Succeeds
        Crypto-->>API: {decryptedValue: "actual_key", status: "ok"}
        API->>API: Include apiKeyStatus: "ok"
        API-->>Client: {...config, apiKey: "actual_key", apiKeyStatus: "ok"}
    else Decryption Fails
        Crypto-->>API: {decryptedValue: "", status: "decrypt_failed"}
        API->>API: Log warning, include status
        API-->>Client: {...config, apiKey: "****", apiKeyStatus: "decrypt_failed"}
        Client->>Client: Display warning to user
    else Value is Empty
        Crypto-->>API: {decryptedValue: "", status: "empty"}
        API-->>Client: {...config, apiKey: "", apiKeyStatus: "empty"}
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A helper born to guard the keys,
With status flags to set hearts at ease—
When secrets fail to decrypt and rise,
We warn the user with amber eyes!
No more silent falls in the dark,
Just clarity and a helpful spark ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: addressing secret decryption failures by surfacing them to users.
Linked Issues check ✅ Passed All requirements from issue #64 are met: logging added for decryption failures, descriptive status values returned instead of masked values.
Out of Scope Changes check ✅ Passed All changes are directly related to addressing secret decryption failures for AI configs, WebDAV configs, and GitHub token settings as specified in issue #64.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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/config-secret-decrypt-status

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/src/routes/configs.ts`:
- Around line 402-410: The github_token branch currently only runs
getMaskedSecretResult when value is truthy, so settings.github_token_status is
left undefined for empty tokens; always call getMaskedSecretResult for key ===
'github_token' (passing encryptedValue: value and encryptionKey:
config.encryptionKey), set settings.github_token_status = status
unconditionally, and then set value = status === 'empty' ? '' :
maskApiKey(decryptedValue) so consumers can distinguish an explicit empty token
from a missing status (update logic around getMaskedSecretResult, maskApiKey,
and settings.github_token_status accordingly).

In `@src/components/SettingsPanel.tsx`:
- Around line 946-953: Add the same visible warning flow for GitHub token
decrypt failures by rendering a warning paragraph when
config.github_token_status === 'decrypt_failed' next to the existing API key
block in SettingsPanel (where config.apiKeyStatus is checked); mirror the
styling and translation usage (className "mt-1 text-sm text-amber-600
dark:text-amber-400" and t(...) pattern) and provide a bilingual message
analogous to the API key one (e.g., "存储的 GitHub Token 无法解密,请重新输入并保存该配置。" / "The
stored GitHub token could not be decrypted. Please re-enter and save this
configuration.") so users see the same warning for github_token_status decrypt
failures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 94475848-56a5-400a-9b24-3dabd10436f3

📥 Commits

Reviewing files that changed from the base of the PR and between 7622b98 and 62ceb54.

📒 Files selected for processing (3)
  • server/src/routes/configs.ts
  • src/components/SettingsPanel.tsx
  • src/types/index.ts

Comment on lines 402 to 410
if (key === 'github_token' && value) {
try {
const decrypted = decrypt(value, config.encryptionKey);
value = maskApiKey(decrypted);
} catch {
value = '****';
}
const { decryptedValue, status } = getMaskedSecretResult({
encryptedValue: value,
encryptionKey: config.encryptionKey,
kind: 'GitHub token',
});
value = status === 'empty' ? '' : maskApiKey(decryptedValue);
settings.github_token_status = status;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Return github_token_status even when token is empty.

Line 402 currently skips status assignment when value is empty/null, so consumers can’t distinguish “missing status” vs explicit empty state. Please run the helper for every github_token row and let it return 'empty'.

💡 Suggested fix
-      if (key === 'github_token' && value) {
+      if (key === 'github_token') {
         const { decryptedValue, status } = getMaskedSecretResult({
           encryptedValue: value,
           encryptionKey: config.encryptionKey,
           kind: 'GitHub token',
         });
         value = status === 'empty' ? '' : maskApiKey(decryptedValue);
         settings.github_token_status = status;
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/src/routes/configs.ts` around lines 402 - 410, The github_token branch
currently only runs getMaskedSecretResult when value is truthy, so
settings.github_token_status is left undefined for empty tokens; always call
getMaskedSecretResult for key === 'github_token' (passing encryptedValue: value
and encryptionKey: config.encryptionKey), set settings.github_token_status =
status unconditionally, and then set value = status === 'empty' ? '' :
maskApiKey(decryptedValue) so consumers can distinguish an explicit empty token
from a missing status (update logic around getMaskedSecretResult, maskApiKey,
and settings.github_token_status accordingly).

Comment on lines +946 to +953
{config.apiKeyStatus === 'decrypt_failed' && (
<p className="mt-1 text-sm text-amber-600 dark:text-amber-400">
{t(
'存储的 API Key 无法解密,请重新输入并保存该配置。',
'The stored API key could not be decrypted. Please re-enter and save this configuration.'
)}
</p>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add equivalent warning flow for github_token_status.

You now surface AI/WebDAV decrypt failures, but GitHub token decrypt failures still have no visible warning in the settings UI. That leaves one credential type silent from the user perspective.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/SettingsPanel.tsx` around lines 946 - 953, Add the same
visible warning flow for GitHub token decrypt failures by rendering a warning
paragraph when config.github_token_status === 'decrypt_failed' next to the
existing API key block in SettingsPanel (where config.apiKeyStatus is checked);
mirror the styling and translation usage (className "mt-1 text-sm text-amber-600
dark:text-amber-400" and t(...) pattern) and provide a bilingual message
analogous to the API key one (e.g., "存储的 GitHub Token 无法解密,请重新输入并保存该配置。" / "The
stored GitHub token could not be decrypted. Please re-enter and save this
configuration.") so users see the same warning for github_token_status decrypt
failures.

@AmintaCCCP AmintaCCCP merged commit f954361 into main Mar 25, 2026
5 checks passed
@AmintaCCCP AmintaCCCP deleted the fix/config-secret-decrypt-status branch March 25, 2026 10:03
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.

Missing Error Handling for Invalid Decryption in maskApiKey and maskPassword

1 participant