{"record":{"id":"6e467433daf68f5a","repo":"hashicorp/packer","slug":"attestation-subject-does-not-match-artifact-q","errorCode":null,"errorMessage":"attestation subject does not match artifact %q","messagePattern":"attestation subject does not match artifact %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/verify.go","lineNumber":396,"sourceCode":"\t}\n\n\treturn fmt.Errorf(\"sigstore bundle signature does not match any attestation signature\")\n}\n\nfunc verifyArtifactSubject(subjects []internalprovenance.Subject, artifactPath string) error {\n\tdigest, err := sha256File(artifactPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"hash artifact %q: %w\", artifactPath, err)\n\t}\n\n\tartifactName := filepath.Base(artifactPath)\n\tfor _, subject := range subjects {\n\t\tif subject.Name == artifactName && strings.EqualFold(subject.Digest[\"sha256\"], digest) {\n\t\t\treturn nil\n\t\t}\n\t}\n\n\treturn fmt.Errorf(\"attestation subject does not match artifact %q\", artifactPath)\n}\n\nfunc sha256File(path string) (string, error) {\n\tfile, err := os.Open(path)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer func() { _ = file.Close() }()\n\n\thasher := sha256.New()\n\tif _, err := io.Copy(hasher, file); err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn hex.EncodeToString(hasher.Sum(nil)), nil\n}\n","sourceCodeStart":378,"sourceCodeEnd":413,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/verify.go#L378-L413","documentation":"After hashing the artifact, verifyArtifactSubject searches the provenance subjects for one whose Name equals the artifact's base filename and whose sha256 digest matches (case-insensitively) the computed hash. If none matches, the attestation's subject does not describe this artifact — i.e. the provenance was generated for a different build/output.","triggerScenarios":"verifyPolicy compares a provenance attestation whose subjects list contains no entry with name == filepath.Base(artifactPath) and a matching sha256 — wrong artifact passed to verification, or attestation from a different build (hash differs) or different artifact name (rename).","commonSituations":"Artifact rebuilt after attestation generation (hash changed); artifact renamed after signing (basename mismatch); verifying against the wrong attestation file in a directory of many attestations; subject name includes a path/prefix that does not equal the bare filename.","solutions":["Verify you are using the attestation produced by the same build that produced the artifact","Ensure the artifact file name exactly equals the subject Name in the provenance (it compares filepath.Base of the path)","Recompute sha256 of the artifact and diff against the subject digest to confirm which field mismatches","Re-generate the attestation after renaming or rebuilding the artifact"],"exampleFix":"// before: artifact rebuilt after attestation, hash mismatch\nverifyPolicy(attestationFromOldBuild, \"/out/app-linux-amd64\")\n// after: regenerate attestation for the current artifact\natt := generateProvenance(\"/out/app-linux-amd64\")\nverifyPolicy(att, \"/out/app-linux-amd64\")","handlingStrategy":"validation","validationCode":"digest, err := sha256File(artifactPath)\nif err != nil { return err }\nname := filepath.Base(artifactPath)\nfor _, s := range subjects {\n    if s.Name == name && strings.EqualFold(s.Digest[\"sha256\"], digest) { return nil }\n}\nreturn fmt.Errorf(\"artifact %s (sha256 %s) not covered by attestation subjects\", name, digest)","typeGuard":null,"tryCatchPattern":"if err := verifyArtifactSubject(subjects, path); err != nil {\n    return fmt.Errorf(\"attestation does not describe %s — regenerate attestation for this build: %w\", path, err)\n}","preventionTips":["Regenerate attestations whenever the artifact is rebuilt or renamed","Keep artifact filenames stable across builds (subject Name is the base filename)","Pair each artifact with its attestation by build ID, not by directory convention","Recompute sha256 locally and compare with the subject before invoking verification"],"tags":["attestation","provenance","artifact"],"backgroundTag":"artifact-digest-mismatch","analyzedSha":"eb36e3c3e48a036f3e8cc94087636ee72e1303c9","analyzedAt":"2026-09-05T13:20:43.127Z","contentChangedAt":"2026-09-05T13:20:43.127Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}