{"record":{"id":"20dfc76b322b4b94","repo":"hashicorp/packer","slug":"hash-artifact-q-w","errorCode":null,"errorMessage":"hash artifact %q: %w","messagePattern":"hash artifact %q: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/attestation/verify.go","lineNumber":386,"sourceCode":"\tbundleSignature := bundleEnvelope.Signature()\n\tfor i, envelopeSignature := range envelope.Signatures {\n\t\tsignature, err := DecodeEnvelopeSignature(envelopeSignature)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"decode attestation envelope signature %d: %w\", i, err)\n\t\t}\n\n\t\tif bytes.Equal(bundleSignature, signature) {\n\t\t\treturn nil\n\t\t}\n\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() }()","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/hashicorp/packer/blob/eb36e3c3e48a036f3e8cc94087636ee72e1303c9/internal/attestation/verify.go#L368-L404","documentation":"verifyArtifactSubject hashes the artifact file at artifactPath with sha256File before comparing it against provenance subjects. If hashing fails (file cannot be opened, read error during io.Copy), the error is wrapped with `hash artifact %q: %w` preserving the original os/io error.","triggerScenarios":"verifyPolicy calls verifyArtifactSubject with an artifactPath that does not exist, is a directory, has insufficient read permissions, or is unreadable mid-read (I/O error while streaming into the hasher).","commonSituations":"Typoed or relative artifact path resolved from a different working directory than the test/verification run; artifact deleted or not downloaded before verification; running the verifier as a user lacking read permission on the artifact.","solutions":["Check the artifact file exists at the exact path and that the process has read permission (ls -l, or os.Stat before verification)","Run the verification from the correct working directory or pass an absolute path to the artifact","Download/produce the artifact before running policy verification","Inspect the wrapped underlying error (os.PathError) for the precise open/read failure"],"exampleFix":"// before: relative path resolved from wrong cwd\nverifyPolicy(policy, \"bin/app\")\n// after: absolute path plus existence check\nif _, err := os.Stat(artifactPath); err != nil { return err }\nverifyPolicy(policy, \"/abs/path/to/bin/app\")","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(artifactPath); err != nil {\n    return fmt.Errorf(\"artifact not readable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := verifyPolicy(policy, path); err != nil {\n    if strings.HasPrefix(err.Error(), \"hash artifact\") {\n        return fmt.Errorf(\"cannot read artifact %s: %w\", path, err)\n    }\n    return err\n}","preventionTips":["Resolve artifact paths to absolute paths before verification","Stat the artifact before hashing","Run the verifier with read permission on the artifact","Ensure the artifact is produced/downloaded before verification runs"],"tags":["filesystem","artifact","hashing"],"backgroundTag":"file-open-failed","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"}