{"record":{"id":"866baab36f1bb7e9","repo":"helm/helm","slug":"plugin-verification-failed-w","errorCode":null,"errorMessage":"plugin verification failed: %w","messagePattern":"plugin verification failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/plugin/installer/installer.go","lineNumber":107,"sourceCode":"\t\tif !ok || !verifier.SupportsVerification() {\n\t\t\treturn nil, errors.New(\"--verify is only supported for plugin tarballs (.tgz files)\")\n\t\t}\n\n\t\t// Get verification data (works for both memory and file-based installers)\n\t\tarchiveData, provData, filename, err := verifier.GetVerificationData()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to get verification data: %w\", err)\n\t\t}\n\n\t\t// Check if provenance data exists\n\t\tif len(provData) == 0 {\n\t\t\treturn nil, errors.New(\"plugin verification failed: no provenance file (.prov) found\")\n\t\t}\n\n\t\t// Provenance data exists - verify the plugin\n\t\tverification, err := plugin.VerifyPlugin(archiveData, provData, filename, opts.Keyring)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"plugin verification failed: %w\", err)\n\t\t}\n\n\t\t// Collect verification info\n\t\tresult = &VerificationResult{\n\t\t\tSignedBy:    make([]string, 0),\n\t\t\tFingerprint: fmt.Sprintf(\"%X\", verification.SignedBy.PrimaryKey.Fingerprint),\n\t\t\tFileHash:    verification.FileHash,\n\t\t}\n\t\tfor name := range verification.SignedBy.Identities {\n\t\t\tresult.SignedBy = append(result.SignedBy, name)\n\t\t}\n\t}\n\n\tif err := i.Install(); err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn result, nil","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/helm/helm/blob/2a29f1770b62844b27197d2507377361d45ad7c0/internal/plugin/installer/installer.go#L89-L125","documentation":"The provenance file existed and was loaded, but plugin.VerifyPlugin failed: the clearsigned OpenPGP .prov could not be verified against the archive using the keyring in opts.Keyring. Typical inner failures: keyring path missing or empty, the signer's public key not present in the keyring, a malformed (not clearsigned) .prov file, or the SHA256 file hash in .prov not matching the archive bytes.","triggerScenarios":"helm plugin install --verify --keyring ~/.gnupg/pubring.gpg myplugin-1.0.0.tgz where the tarball was rebuilt after the .prov was generated (hash mismatch), the signer key was never imported, the .prov is corrupt/truncated, or --keyring points at a nonexistent file.","commonSituations":"Plugin authors re-packaging the tarball without regenerating provenance; users passing a fresh keyring that lacks the author's key; cross-machine gpg setups where pubring differs; man-in-the-middle or accidentally corrupted downloads (verification is doing its job).","solutions":["Import the plugin signer's public key and pass a keyring that contains it (gpg --import key.asc, then --keyring ~/.gnupg/pubring.gpg)","If you publish the plugin: regenerate the provenance file from the exact tarball being shipped (clearsigned SHA256 message over the final .tgz), never re-tar after signing","Re-download both the .tgz and .prov together from the authoritative source to rule out truncation or partial mirror sync","Only if the source is fully trusted and you accept the risk, install without --verify (defeats the purpose; last resort)"],"exampleFix":"# before: keyring lacks the signer\ngpg --list-keys | grep -c 'plugin-signer' || true\nhelm plugin install --verify --keyring ~/.gnupg/pubring.gpg myplugin-1.0.0.tgz\n# after: import signer key into the keyring used for verification\ngpg --import plugin-signer.asc\nhelm plugin install --verify --keyring ~/.gnupg/pubring.gpg myplugin-1.0.0.tgz","handlingStrategy":"validation","validationCode":"func keyringReady(keyringPath string) error {\n\tfi, err := os.Stat(keyringPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"keyring %s not accessible: %w\", keyringPath, err)\n\t}\n\tif fi.Size() == 0 {\n\t\treturn fmt.Errorf(\"keyring %s is empty — import the signer's public key first\", keyringPath)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := installer.InstallWithOptions(inst, installer.Options{Verify: true, Keyring: kr}); err != nil {\n\tif strings.Contains(err.Error(), \"plugin verification failed\") {\n\t\t// Do NOT retry or bypass: either the keyring lacks the signer, or the artifact/prov pair is mismatched.\n\t\t// Fetch the authoritative .tgz+.prov pair and a keyring containing the signer, then retry once.\n\t}\n}","preventionTips":["Import the plugin author's public key into a dedicated keyring before scripted --verify installs","Never rebuild/re-tar a signed tarball; regenerate provenance whenever the artifact changes","Ship .tgz and .prov from the same release pipeline so hashes always match","Treat persistent verification failure on a trusted mirror as a possible compromise indicator"],"tags":["go","helm","plugin","verification","security","pgp","provenance"],"backgroundTag":null,"analyzedSha":"2a29f1770b62844b27197d2507377361d45ad7c0","analyzedAt":"2026-08-15T22:02:47.490Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}