Skip to content

keys-sync reports GPG execution failures as missing keys #1633

Closed

Description

@MakerFlyFly

What's broken

keys-sync Step 1 can report key_found: false and helper exit 0 when GPG failed to import or list a public key. Unreadable inputs and unusable temporary keyrings can therefore be reported as a missing key.

This report requests correct error propagation. Repairing Windows/MSYS path compatibility and changing signing-key policies are separate work.

Which layer

list_key_file() on upstream main at 0a1f044e ignores both GPG return codes and stderr.
The Step 1 contract requires helper errors to be surfaced and its JSON to be returned unchanged.

How to reproduce

Check out upstream commit 0a1f044e493e753fc42ed68b6eac1121c5a63ebc. Save the synthetic public-key fixture below as public.asc; its primary fingerprint is 038B5CD314A54039993E7625DA31D2B4B27784E4.
The fixture is public information; no keyserver, account or private key is needed.

Windows, native Python with Git for Windows' MSYS GPG:

$env:PATH = 'C:\Program Files\Git\usr\bin;' + $env:PATH
python plugins/magpie-release-management/skills/keys-sync/scripts/check_key.py `
  --key-file public.asc `
  --fingerprint 038B5CD314A54039993E7625DA31D2B4B27784E4
$LASTEXITCODE

With Git/MSYS GPG 2.4.8, the helper's native temporary --homedir path is unusable in the tested environment. Direct import and listing commands return 2, with diagnostics including no writable keyring found. The helper suppresses this and reports a missing key with exit 0.
The same public fixture imports successfully in a compatible isolated keyring.

Linux, unreadable input, executed as a non-root user:

chmod 000 public.asc
helper_exit=0
python3 plugins/magpie-release-management/skills/keys-sync/scripts/check_key.py \
  --key-file public.asc \
  --fingerprint 038B5CD314A54039993E7625DA31D2B4B27784E4 || helper_exit=$?
chmod 600 public.asc
printf 'helper exit: %s\n' "$helper_exit"

Import returns 2, but listing the fresh empty keyring succeeds. The helper still exits 0 with key_found: false. Checking only the listing return code would miss this case.

Malformed declared public-key input:

python3 -c "from pathlib import Path; Path('truncated.asc').write_bytes(Path('public.asc').read_bytes()[:160])"
python3 plugins/magpie-release-management/skills/keys-sync/scripts/check_key.py \
  --key-file truncated.asc \
  --fingerprint 038B5CD314A54039993E7625DA31D2B4B27784E4

The truncated block is also reported as missing with exit 0. Real GPG 2.2.40 and 2.4.8 can emit the same NODATA and zero import statistics for this malformed armor as for ordinary text. Those statuses and an empty listing alone do not distinguish the inputs.
A directory is another input error currently reported as missing; a zero-size Windows directory can hit the empty-file shortcut before GPG starts.

Expected vs actual

For the failure reproductions, the unpatched helper emits the normal ten-field result with verdict: "blocked", key_found: false and helper exit 0.

Expected:

  • Unreadable or non-regular input produces an input error JSON and helper exit 2.
  • Failed GPG import or listing produces {"error": "..."} and helper exit 2, including the stage, GPG return code and available diagnostics. Failed listing stdout must not be assessed even if it contains key records.
  • A declared public-key block that fails to import is an error, including the truncated armor above.
  • Readable empty files, ordinary text with no key, and a successful check whose fingerprint does not match retain key_found: false and exit 0. Normal business blocked also remains exit 0.

Input read errors may be detected before GPG starts; these report the input stage and reason, rather than a GPG return code.
The ordinary no-data compatibility exception needs evidence from the input, GPG machine statuses and successful empty listing. In the tested GPG 2.4.8, pure no-data also carries FAILURE gpg-exit 33554433; other execution failures and partial imports must remain errors. Classification must not depend on English stderr.

Surface area (optional)

  • Keep the CLI, normal ten-field JSON, key-assessment policy and disposable-keyring cleanup.
  • No Windows/MSYS path conversion, signing-subkey admission, signer selection, signing or verification changes. This is independent of issue #1628, including Option 2.
  • Suggested labels: bug, family:release-management, capability:fix.
  • Migration coordination: PR #1625, currently unmerged at 2f20bb62, removes the old helper and tests and delegates GPG reading to release-verify list-keys. Source inspection of that proposed list_keys() also shows import/listing return codes are ignored. It is not a fix for this report. If this repair merges first, the migration needs to retain its behavior and regressions; if the migration merges first, the repair needs adapting to the replacement entry point.
  • The reviewed reference repair and local audit are in fork Draft PR #12 and fork issue #11. Those remain audit references.

Environment (optional)

  • Windows 11 build 10.0.26100; native Python 3.12.13; Git/MSYS GPG 2.4.8.
  • Linux container; Python 3.12.12; GPG 2.2.40; permission probes executed as UID 65534.
  • Both use disposable keyrings and the same synthetic public fixture.
  • A Windows control using a compatible MSYS --homedir confirms the input key is valid. This directly establishes the tested homedir compatibility problem; it does not establish that every drive-letter argument is unusable.
  • Acceptance on the affected production Windows/MSYS backend is an accurate error/exit 2. Successful import there requires a separate path-compatibility repair. Native Windows GPG was unavailable for separate testing.
Synthetic public-key fixture

The armor is 2517 bytes with LF line endings and a final newline.
SHA-256: a73ff1760b8a7354baf67e1855989744c0c7d4f146888661ec470965d7ae29de.

-----BEGIN PGP PUBLIC KEY BLOCK-----

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
+P8JcWgqidc2b1O/jl++tHgTt8SqqtM=
=cHCJ
-----END PGP PUBLIC KEY BLOCK-----

Gen-AI disclosure: OpenAI Codex (GPT-6) assisted with the reproduction, repair, tests and report. The contributor approved the reviewed repair and upstream submission. This report is AI-assisted.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions