{"record":{"id":"69413e8f1abda729","repo":"netbirdio/netbird","slug":"failed-to-parse-signature-w","errorCode":null,"errorMessage":"failed to parse signature: %w","messagePattern":"failed to parse signature: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactsign.go","lineNumber":187,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse artifact public key: %w\", err)\n\t}\n\n\t// Read artifact data\n\tartifactData, err := os.ReadFile(artifactFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read artifact file: %w\", err)\n\t}\n\n\t// Read signature\n\tsigBytes, err := os.ReadFile(signatureFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read signature file: %w\", err)\n\t}\n\n\tsignature, err := reposign.ParseSignature(sigBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse signature: %w\", err)\n\t}\n\n\t// Validate artifact\n\tif err := reposign.ValidateArtifact([]reposign.PublicKey{publicKey}, artifactData, *signature); err != nil {\n\t\treturn fmt.Errorf(\"artifact verification failed: %w\", err)\n\t}\n\n\tcmd.Println(\"✅ Artifact signature is valid\")\n\tcmd.Printf(\"Artifact: %s\\n\", artifactFile)\n\tcmd.Printf(\"Signed by key: %s\\n\", signature.KeyID)\n\tcmd.Printf(\"Signature timestamp: %s\\n\", signature.Timestamp.Format(\"2006-01-02 15:04:05 MST\"))\n\treturn nil\n}\n\nfunc handleVerifyArtifactKey(cmd *cobra.Command, artifactKeyFile, rootKeyFile, signatureFile, revocationFile string) error {\n\tcmd.Println(\"🔍 Verifying artifact key...\")\n\n\t// Read artifact key data","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L169-L205","documentation":"reposign.ParseSignature failed: it json.Unmarshals the .sig file into {signature, timestamp, key_id, algorithm, hash_algo} (reposign/signature.go:17-24). It fails when the file is not this JSON bundle — e.g. a raw Ed25519 signature from openssl, an HTML error page saved as .sig, or a truncated download. Field-level failures include a key_id that is not exactly 16 hex chars and a timestamp that is not valid RFC3339 (KeyID.UnmarshalJSON and time parsing).","triggerScenarios":"Using `openssl dgst -sign` output as the .sig; .sig downloaded from a URL that returned a 404 page; hand-edited JSON with a shortened key_id; base64 signature containing invalid characters.","commonSituations":"Mixing external signing tooling with the NetBird signer format; partial download in CI; someone pretty-printed or re-serialized the JSON and broke a field.","solutions":["Confirm the .sig is the signer's JSON bundle: cat <file>.sig | jq . should show signature, timestamp, key_id, algorithm=ed25519, hash_algo=blake2s","If the signature came from another tool, re-sign with `signer sign-artifact` instead","Re-download the .sig and check it is not an error page or truncated (size sanity check)","Verify key_id is a 16-character hex string and timestamp parses as RFC3339"],"exampleFix":"// before (raw openssl signature passed as .sig)\nopenssl pkeyutl -sign -inkey artifact-key.pem -rawin -in netbird > netbird.sig\n\n// after (signer produces the JSON bundle the verifier parses)\n./signer sign-artifact --artifact-key-file artifact-key.pem --artifact-file netbird","handlingStrategy":"validation","validationCode":"if !json.Valid(sigBytes) {\n    log.Fatal(\"signature file is not the signer's JSON bundle\")\n}","typeGuard":"func looksLikeSignatureBundle(data []byte) bool {\n    var s struct {\n        Signature []byte  `json:\"signature\"`\n        Timestamp string  `json:\"timestamp\"`\n        KeyID     string  `json:\"key_id\"`\n    }\n    return json.Unmarshal(data, &s) == nil && len(s.Signature) > 0 && len(s.KeyID) == 16\n}","tryCatchPattern":null,"preventionTips":["Never substitute external signing tools for sign-artifact; the .sig format is a JSON bundle, not a raw signature","Sanity-check downloaded .sig files with jq before verifying"],"tags":["go","json","crypto","release-signing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}