{"record":{"id":"412afeb8d4adc786","repo":"dotnet/efcore","slug":"signature-verification-failed-result-stderr-deco","errorCode":null,"errorMessage":"Signature verification failed: {result.stderr.decode('utf-8')}","messagePattern":"Signature verification failed: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"eng/common/cross/install-debs.py","lineNumber":135,"sourceCode":"    release_gpg_url = f\"{mirror}/dists/{suite}/Release.gpg\"\n\n    with tempfile.NamedTemporaryFile() as release_file, tempfile.NamedTemporaryFile() as release_gpg_file:\n        await download_file(session, release_url, release_file.name)\n        await download_file(session, release_gpg_url, release_gpg_file.name)\n\n        print(\"Verifying signature of Release with Release.gpg.\")\n        # Use gpgv rather than gpg for verification. gpgv verifies a detached\n        # signature against a fixed keyring without involving gpg-agent or\n        # keyboxd, which makes it robust on hosts running GnuPG 2.4+ (e.g. Azure\n        # Linux) where \"gpg --keyring\" routes through keyboxd and can fail.\n        verify_command = [\"gpgv\"]\n        if keyring:\n            verify_command += [\"--keyring\", keyring]\n        verify_command += [release_gpg_file.name, release_file.name]\n        result = subprocess.run(verify_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n\n        if result.returncode != 0:\n            raise Exception(f\"Signature verification failed: {result.stderr.decode('utf-8')}\")\n\n        print(\"Signature verified successfully.\")\n\n        with open(release_file.name) as f:\n            return f.read()\n\ndef parse_release_file(content, path):\n    \"\"\"Parses the Release file and returns sha256 checksum of the specified path.\"\"\"\n\n    # data looks like this:\n    # <checksum>  <size>  <path>\n    matches = re.findall(r'^ (\\S*) +(\\S*) +(\\S*)$', content, re.MULTILINE)\n\n    for entry in matches:\n        # the file has both md5 and sha256 checksums, we want sha256 which has a length of 64\n        if entry[2] == path and len(entry[0]) == 64:\n            return entry[0]\n","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/eng/common/cross/install-debs.py#L117-L153","documentation":"Raised by fetch_release_file when gpgv exits non-zero verifying Release.gpg against Release using the supplied --keyring. The error string is gpgv's decoded stderr. It means the Release file's detached signature does not validate against the keys present in the keyring, i.e. an authentication failure of the archive metadata.","triggerScenarios":"--force-check-gpg and --keyring are both set; gpgv --keyring <keyring> Release.gpg Release returns a non-zero exit code.","commonSituations":"The signing key is missing from the keyring (key rotated, new release signed by a key you do not have), the keyring package (debian-ports-archive-keyring / ubuntu-archive-keyring) is outdated or expired, Release or Release.gpg was corrupted in transit, a MITM, or the wrong keyring was chosen for the suite/distro.","solutions":["Install or update the matching archive-keyring package (e.g. debian-ports-archive-keyring for Debian ports, ubuntu-archive-keyring for Ubuntu).","Confirm --keyring points to the keyring that actually signed the chosen suite (Debian vs Ubuntu vs ports).","Reproduce manually: gpgv --keyring <keyring> Release.gpg Release and read the full stderr (the script only surfaces it as an Exception message).","Re-fetch Release/Release.gpg in case of a truncated download.","As a last resort, drop --force-check-gpg (the script prints guidance pointing to --skipsigcheck)."],"exampleFix":"// before\n--force-check-gpg --keyring /usr/share/keyrings/old-archive-keyring.gpg\n\n// after\nsudo apt-get install -y debian-ports-archive-keyring\n--force-check-gpg --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg","handlingStrategy":"validation","validationCode":"# preflight: ensure the Release signing key is present in the keyring\nimport subprocess\nr = subprocess.run([\"gpgv\", \"--keyring\", keyring, release_gpg, release], capture_output=True)\nif r.returncode != 0:\n    sys.exit(f\"keyring cannot verify Release; install/update the archive-keyring package: {r.stderr.decode()}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install and keep updated the archive-keyring package matching your distro (debian-ports-archive-keyring, ubuntu-archive-keyring).","Pin --keyring to the keyring that signs the chosen suite; do not mix Debian and Ubuntu keyrings.","Verify signatures manually with gpgv when a new release/key rotation happens."],"tags":["security","gpg","signature","keyring"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}