Skip to content

Commit

Permalink
Add support for provenance.
Browse files Browse the repository at this point in the history
This change adds support for `/v2/provenance` endpoint, plus a small
fix on the values of `ProvenanceType`.
  • Loading branch information
blkt committed Nov 20, 2024
1 parent fd7f9d6 commit 3643fb4
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 11 deletions.
17 changes: 17 additions & 0 deletions cmd/example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func main() {
fmt.Fprintf(os.Stderr, "error calling endpoint: %s\n", err)
os.Exit(1)
}
case "provenance":
if err := provenance(ctx, client, pname); err != nil {
fmt.Fprintf(os.Stderr, "error calling endpoint: %s\n", err)
os.Exit(1)
}
case "":
fmt.Fprintf(os.Stderr, "endpoint is mandatory\n")
os.Exit(1)
Expand Down Expand Up @@ -99,3 +104,15 @@ func alternatives(ctx context.Context, client v2client.Trusty, pname string) err
fmt.Printf("%+v\n", res)
return nil
}

func provenance(ctx context.Context, client v2client.Trusty, pname string) error {
res, err := client.Provenance(ctx, &v2types.Dependency{
PackageName: pname,
})
if err != nil {
return err
}

fmt.Printf("%+v\n", res)
return nil
}
31 changes: 31 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ const (
v2SummaryPath = "v2/summary"
v2PkgPath = "v2/pkg"
v2Alternatives = "v2/alternatives"
v2Provenance = "v2/provenance"
)

// Summary fetches a summary of Security Signal information
Expand Down Expand Up @@ -419,6 +420,36 @@ func (t *Trusty) Alternatives(
return doRequest[v2types.PackageAlternatives](t.Options.HttpClient, u.String())
}

// Provenance fetches detailed provenance information of a given
// package.
func (t *Trusty) Provenance(
_ context.Context,
dep *v2types.Dependency,
) (*v2types.Provenance, error) {
if dep.PackageName == "" {
return nil, fmt.Errorf("dependency has no name defined")
}

u, err := urlFor(t.Options.BaseURL, v2Provenance)
if err != nil {
return nil, fmt.Errorf("failed to parse endpoint: %w", err)
}

// Add query parameters for package_name, package_type, and
// package_version.
q := u.Query()
q.Set("package_name", dep.PackageName)
if dep.PackageType != nil && *dep.PackageType != "" {
q.Set("package_type", strings.ToLower(*dep.PackageType))
}
if dep.PackageVersion != nil && *dep.PackageVersion != "" {
q.Set("package_version", *dep.PackageVersion)
}
u.RawQuery = q.Encode()

return doRequest[v2types.Provenance](t.Options.HttpClient, u.String())
}

// doRequest only wraps (1) an HTTP GET issued to the given URL using
// the given client, and (2) result deserialization.
func doRequest[T any](client netClient, fullurl string) (*T, error) {
Expand Down
1 change: 1 addition & 0 deletions pkg/v2/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type Trusty interface {
Summary(context.Context, *types.Dependency) (*types.PackageSummaryAnnotation, error)
PackageMetadata(context.Context, *types.Dependency) (*types.TrustyPackageData, error)
Alternatives(context.Context, *types.Dependency) (*types.PackageAlternatives, error)
Provenance(context.Context, *types.Dependency) (*types.Provenance, error)
}

// New returns a new Trusty REST client
Expand Down
49 changes: 38 additions & 11 deletions pkg/v2/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@ type SummaryDescription struct {
type ProvenanceType string

var (
// ProvenanceTypeVerifiedProvenance represents a fully
// verified provenance information.
ProvenanceTypeVerifiedProvenance ProvenanceType = "verified_provenance"
// ProvenanceTypeHistoricalProvenance represents a verified
// historical provenance information.
ProvenanceTypeHistoricalProvenance ProvenanceType = "historical_provenance_match"
// ProvenanceTypeVerified represents a fully verified
// provenance information.
ProvenanceTypeVerified ProvenanceType = "verified_provenance_match"
// ProvenanceTypeHistorical represents a verified historical
// provenance information.
ProvenanceTypeHistorical ProvenanceType = "historical_provenance_match"
// ProvenanceTypeUnknown represents no provenance information.
ProvenanceTypeUnknown ProvenanceType = "unknown"
// ProvenanceTypeMismatched represents conflicting provenance
// information.
ProvenanceTypeMismatched ProvenanceType = "mismatched"
ProvenanceTypeMismatched ProvenanceType = "historical_provenance_mismatched"
)

//nolint:revive
Expand All @@ -118,13 +118,13 @@ func (t *ProvenanceType) UnmarshalJSON(data []byte) error {
}

switch tmp {
case "verified_provenance":
*t = ProvenanceTypeVerifiedProvenance
case "verified_provenance_match":
*t = ProvenanceTypeVerified
case "historical_provenance_match":
*t = ProvenanceTypeHistoricalProvenance
*t = ProvenanceTypeHistorical
case "unknown":
*t = ProvenanceTypeUnknown
case "mismatched":
case "historical_provenance_mismatched":
*t = ProvenanceTypeMismatched
default:
return fmt.Errorf("invalid provenance type: %s", tmp)
Expand Down Expand Up @@ -318,3 +318,30 @@ type PackageBasicInfo struct {
Score *float64 `json:"score"`
IsMalicious bool `json:"is_malicious"`
}

// Provenance contains details about historical or cryptographically
// verifiable provenance.
type Provenance struct {
Historical HistoricalProvenance `json:"hp"`
Sigstore SigstoreProvenance `json:"sigstore"`
Sore *float64 `json:"score"`
}

// HistoricalProvenance contains the number of tags in the repo, the
// number of versions of the package, a count of the common tags and
// the ratio of tags to common as overlap.
type HistoricalProvenance struct {
Overlap float64 `json:"overlap"` // 92.23300970873787
Common float64 `json:"common"` // 95.0
Tags float64 `json:"tags"` // 103.0
Versions float64 `json:"versions"` // 152.0
}

// SigstoreProvenance contains details about Sigstore provenance.
type SigstoreProvenance struct {
SourceRepo string `json:"source_repo"`
Workflow string `json:"workflow"`
Issuer string `json:"issuer"`
TokenIssuer string `json:"token_issuer"`
Transparency string `json:"transparency"`
}

0 comments on commit 3643fb4

Please sign in to comment.