Skip to content

fix: show user-friendly error when GPG key is expired or invalid#1035

Merged
annejan merged 3 commits into
mainfrom
fix/247-gpg-key-expired-error-message
Apr 17, 2026
Merged

fix: show user-friendly error when GPG key is expired or invalid#1035
annejan merged 3 commits into
mainfrom
fix/247-gpg-key-expired-error-message

Conversation

@annejan
Copy link
Copy Markdown
Member

@annejan annejan commented Apr 17, 2026

This pull request improves the user experience by providing more descriptive and user-friendly error messages when GPG encryption fails.

Key changes include:

  • Enhanced GPG Error Parsing: The application now explicitly requests machine-readable status output from GPG using the --status-fd 2 flag during password insertion.
  • User-Friendly Error Translation: A new function gpgErrorMessage has been introduced to parse GPG's standard error output. It prioritizes machine-readable [GNUPG:] status tokens to identify specific issues like expired, revoked, or missing GPG keys.
  • Fallback for Older GPG Versions: For GPG versions or configurations that do not emit status tokens, the function includes case-insensitive substring matching to still provide translated error messages.
  • Improved Error Display: When an encryption error occurs during password insertion, the application now displays a clear, translated message to the user. It also cleans up the raw GPG error output by stripping internal status lines, making any additional GPG details more readable if presented.

This ensures that users receive actionable feedback when GPG keys are expired, revoked, or otherwise invalid, rather than cryptic technical messages.

Summary by CodeRabbit

  • New Features

    • Encryption now returns translated, user-friendly error messages for specific issues (expired/revoked keys, missing public keys, general encryption failures).
  • Improvements

    • Error reporting prioritizes machine-readable status when present and cleans noisy output before display.
  • Tests

    • Added comprehensive unit tests covering status-token parsing, fallback text matching, precedence, and unknown-output behavior.

When ImitatePass::Insert fails because the recipient key is expired,
revoked, or missing, GPG exits non-zero and the raw stderr was shown
verbatim in the output panel — not helpful to users who don't read GPG
output daily.

Add --status-fd 2 to the GPG invocation so machine-readable [GNUPG:]
status tokens (KEY_EXPIRED, KEY_REVOKED, NO_PUBKEY, INV_RECP, FAILURE)
are included in stderr. These are locale-independent and checked first;
case-insensitive substring fallbacks handle GPG builds or configurations
that don't emit status tokens.

In Pass::finished, when PASS_INSERT fails and a known pattern is found,
a translated friendly message is prepended and the [GNUPG:] machine
lines are stripped before emitting processErrorExit, so the output pane
shows e.g. "Encryption failed: GPG key has expired. Please renew or
replace it." followed by the human-readable GPG lines only.

The transaction mechanism in ImitatePass::finished already cancels the
queued GIT_ADD and GIT_COMMIT commands when GPG fails, so the
misleading git pathspec error is not shown.

11 new unit tests cover all status-token paths, all fallback paths,
the empty-result case, and priority ordering (token beats fallback).

Closes #247

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codeant-ai
Copy link
Copy Markdown
Contributor

codeant-ai Bot commented Apr 17, 2026

CodeAnt AI is reviewing your PR.

@kody-ai
Copy link
Copy Markdown

kody-ai Bot commented Apr 17, 2026

Kody Review Complete

Great news! 🎉
No issues were found that match your current review configurations.

Keep up the excellent work! 🚀

Kody Guide: Usage and Configuration
Interacting with Kody
  • Request a Review: Ask Kody to review your PR manually by adding a comment with the @kody start-review command at the root of your PR.

  • Validate Business Logic: Ask Kody to validate your code against business rules by adding a comment with the @kody -v business-logic command.

  • Provide Feedback: Help Kody learn and improve by reacting to its comments with a 👍 for helpful suggestions or a 👎 if improvements are needed.

Current Kody Configuration
Review Options

The following review options are enabled or disabled:

Options Enabled
Bug
Performance
Security
Cross File
Business Logic

Access your configuration settings here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2171cc78-2fb4-4426-b539-8427b1e8cb68

📥 Commits

Reviewing files that changed from the base of the PR and between aba871a and ffd4f24.

📒 Files selected for processing (1)
  • src/pass.cpp

📝 Walkthrough

Walkthrough

Redirects GPG status output to stderr for insert/encrypt operations and adds gpgErrorMessage() (declared in src/pass.h, implemented in src/pass.cpp) to convert GPG stderr/status tokens into user-friendly error messages; integrates this into Pass::finished() and adds unit tests covering token and fallback parsing.

Changes

Cohort / File(s) Summary
GPG status routing
src/imitatepass.cpp
Adds --status-fd 2 to the GPG argument list for insert/encryption so machine-readable [GNUPG:] status lines are emitted on stderr.
Error parsing & handling
src/pass.h, src/pass.cpp
Declares QString gpgErrorMessage(const QString&) in header and implements it: parses [GNUPG:] status tokens (e.g., KEYEXPIRED, KEYREVOKED, NO_PUBKEY, INV_RECP, FAILURE) and fallbacks to case-insensitive substring matches; Pass::finished() uses this to strip status lines and emit friendly messages on non-zero PASS_INSERT exits.
Unit tests
tests/auto/util/tst_util.cpp
Adds ~11 test slots validating token recognition, fallback phrase matching, unknown-case empty result, and precedence of status tokens over fallback messages.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant UI as "QtPass UI"
    participant ImitatePass as "ImitatePass"
    participant GPG as "GPG"
    participant Pass as "Pass"
    participant Display as "Error Display"

    User->>UI: request insert/encrypt
    UI->>ImitatePass: start insert (GPG args include --status-fd 2)
    ImitatePass->>GPG: run encryption process
    GPG-->>ImitatePass: exit non-zero + stderr ([GNUPG:] lines + text)
    ImitatePass->>Pass: notify finished (PASS_INSERT) with stderr
    Pass->>Pass: remove [GNUPG:] lines from stderr
    Pass->>Pass: gpgErrorMessage(stderr)
    alt token matched
        Pass->>Display: emit token-based friendly message
    else fallback matched
        Pass->>Display: emit substring-based friendly message
    else no match
        Pass->>Display: emit original stderr via processErrorExit
    end
    Display->>User: show error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • nogeenhenk

Poem

🐰 I hop where status lines appear,
I nibble tokens, make them clear,
From stderr whispers, I compose,
Friendly words where GPG woes,
A rabbit's patch for keys and fear.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately reflects the main change: introducing user-friendly error messages when GPG keys are expired or invalid.

✏️ 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/247-gpg-key-expired-error-message

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.

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Apr 17, 2026
Comment thread src/pass.cpp Outdated
@codeant-ai
Copy link
Copy Markdown
Contributor

codeant-ai Bot commented Apr 17, 2026

CodeAnt AI finished reviewing your PR.

@coveralls
Copy link
Copy Markdown

coveralls commented Apr 17, 2026

Coverage Status

coverage: 22.061% (+0.3%) from 21.778% — fix/247-gpg-key-expired-error-message into main

Copy link
Copy Markdown
Contributor

@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 `@src/pass.cpp`:
- Around line 450-467: gpgErrorMessage currently checks incorrect GnuPG tokens
and handles INV_RECP too broadly; update the token checks in gpgErrorMessage to
use the actual status-fd tokens KEYEXPIRED and KEYREVOKED (no underscores),
reorder checks so KEYEXPIRED/KEYREVOKED are matched before any INV_RECP branch,
and add specific INV_RECP reason-code checks for "INV_RECP 5" (expired) and
"INV_RECP 4" (revoked) before falling back to a generic INV_RECP message; ensure
all searches use the same QStringLiteral("[GNUPG:] ...") pattern so
expired/revoked cases return the correct localized messages.

In `@tests/auto/util/tst_util.cpp`:
- Around line 157-167: The parser in gpgErrorMessage() currently matches
nonstandard tokens; update its checks in src/pass.cpp to look for "KEYEXPIRED"
and "KEYREVOKED" (instead of "KEY_EXPIRED"/"KEY_REVOKED") and add explicit
handling of "[GNUPG:] INV_RECP" reason codes so that INV_RECP 5 maps to expired
and INV_RECP 4 maps to revoked (leave other INV_RECP codes as generic
invalid-recipient). After changing the parser logic, update the tests in
tests/auto/util/tst_util.cpp (the gpgErrorMessage* fixtures including
gpgErrorMessageKeyExpiredStatusToken, gpgErrorMessageKeyRevokedStatusToken,
gpgErrorMessageInvRecpStatusToken, etc., and the fixtures around lines
1607-1706) to use the real GnuPG status lines ("[GNUPG:] KEYEXPIRED", "[GNUPG:]
KEYREVOKED", and "[GNUPG:] INV_RECP 5" / "[GNUPG:] INV_RECP 4") so the tests
validate the corrected behavior.
🪄 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: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 722a2be5-0b56-45df-bf4f-aae6e2156d77

📥 Commits

Reviewing files that changed from the base of the PR and between 43f7bdf and feca277.

📒 Files selected for processing (4)
  • src/imitatepass.cpp
  • src/pass.cpp
  • src/pass.h
  • tests/auto/util/tst_util.cpp

Comment thread src/pass.cpp
Comment thread tests/auto/util/tst_util.cpp
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 64.70588% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 28.53%. Comparing base (43f7bdf) to head (feca277).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/pass.cpp 66.66% 11 Missing ⚠️
src/imitatepass.cpp 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1035      +/-   ##
==========================================
+ Coverage   28.16%   28.53%   +0.37%     
==========================================
  Files          39       39              
  Lines        3373     3406      +33     
==========================================
+ Hits          950      972      +22     
- Misses       2423     2434      +11     
Flag Coverage Δ
qtpass 28.53% <64.70%> (+0.37%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Replace KEY_EXPIRED/KEY_REVOKED (which are not real --status-fd tokens)
with KEYEXPIRED and KEYREVOKED. Remove REVKEYSIG (signature verification
only). Add INV_RECP 5 (expired) and INV_RECP 4 (revoked) checks before
the generic INV_RECP fallback. Update tests accordingly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@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: 1

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

Inline comments:
In `@src/pass.cpp`:
- Around line 509-525: The code that builds humanErr from err.split('\n') can
leave stray '\r' characters on CRLF output; inside the PASS_INSERT block (the
loop over for (const QString &line : err.split('\n'))), strip or remove any '\r'
from each non-[GNUPG:] line before appending to humanLines (e.g., normalize line
endings or use line = line.trimmed() / line.remove('\r') or split on CRLF-aware
delimiter) so humanErr has no embedded '\r' when passed to emit
processErrorExit(exitCode, ...).
🪄 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: Repository UI (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5974e3f0-6ec9-4b4a-9710-66c0d0928645

📥 Commits

Reviewing files that changed from the base of the PR and between feca277 and aba871a.

📒 Files selected for processing (2)
  • src/pass.cpp
  • tests/auto/util/tst_util.cpp

Comment thread src/pass.cpp
Split on '\n' leaves trailing '\r' on CRLF output (Windows/WSL).
Remove '\r' from each line before appending to humanLines so the
error passed to processErrorExit is clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@annejan annejan merged commit 0a6f5b8 into main Apr 17, 2026
22 of 24 checks passed
@annejan annejan deleted the fix/247-gpg-key-expired-error-message branch April 17, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants