94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
package verification
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/cli/cli/v2/pkg/cmd/attestation/api"
|
|
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact"
|
|
"github.com/cli/cli/v2/pkg/cmd/attestation/artifact/oci"
|
|
protobundle "github.com/sigstore/protobuf-specs/gen/pb-go/bundle/v1"
|
|
"github.com/sigstore/sigstore-go/pkg/bundle"
|
|
)
|
|
|
|
const SLSAPredicateV1 = "https://slsa.dev/provenance/v1"
|
|
|
|
var ErrUnrecognisedBundleExtension = errors.New("bundle file extension not supported, must be json or jsonl")
|
|
var ErrEmptyBundleFile = errors.New("provided bundle file is empty")
|
|
|
|
// GetLocalAttestations returns a slice of attestations read from a local bundle file.
|
|
func GetLocalAttestations(path string) ([]*api.Attestation, error) {
|
|
var attestations []*api.Attestation
|
|
var err error
|
|
fileExt := filepath.Ext(path)
|
|
if fileExt == ".json" {
|
|
attestations, err = loadBundleFromJSONFile(path)
|
|
} else if fileExt == ".jsonl" {
|
|
attestations, err = loadBundlesFromJSONLinesFile(path)
|
|
} else {
|
|
return nil, ErrUnrecognisedBundleExtension
|
|
}
|
|
|
|
if err != nil {
|
|
var pathErr *os.PathError
|
|
if errors.As(err, &pathErr) {
|
|
return nil, fmt.Errorf("could not load content from file path %s: %w", path, err)
|
|
} else if errors.Is(err, bundle.ErrValidation) {
|
|
return nil, err
|
|
}
|
|
return nil, fmt.Errorf("bundle content could not be parsed: %w", err)
|
|
}
|
|
|
|
return attestations, nil
|
|
}
|
|
|
|
func loadBundleFromJSONFile(path string) ([]*api.Attestation, error) {
|
|
b, err := bundle.LoadJSONFromPath(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []*api.Attestation{{Bundle: b}}, nil
|
|
}
|
|
|
|
func loadBundlesFromJSONLinesFile(path string) ([]*api.Attestation, error) {
|
|
fileContent, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
attestations := []*api.Attestation{}
|
|
|
|
decoder := json.NewDecoder(bytes.NewReader(fileContent))
|
|
|
|
for decoder.More() {
|
|
var b bundle.Bundle
|
|
b.Bundle = new(protobundle.Bundle)
|
|
if err := decoder.Decode(&b); err != nil {
|
|
return nil, err
|
|
}
|
|
a := api.Attestation{Bundle: &b}
|
|
attestations = append(attestations, &a)
|
|
}
|
|
|
|
if len(attestations) == 0 {
|
|
return nil, ErrEmptyBundleFile
|
|
}
|
|
|
|
return attestations, nil
|
|
}
|
|
|
|
func GetOCIAttestations(client oci.Client, artifact artifact.DigestedArtifact) ([]*api.Attestation, error) {
|
|
attestations, err := client.GetAttestations(artifact.NameRef(), artifact.DigestWithAlg())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch OCI attestations: %w", err)
|
|
}
|
|
if len(attestations) == 0 {
|
|
return nil, fmt.Errorf("no attestations found in the OCI registry. Retry the command without the --bundle-from-oci flag to check GitHub for the attestation")
|
|
}
|
|
return attestations, nil
|
|
}
|