Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: fill ErrorReason and Remediation during verifierReport generation #1682

Merged
merged 14 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions pkg/executor/core/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,17 @@ func (executor Executor) verifyReferenceForJSONPolicy(ctx context.Context, subje
verifierStartTime := time.Now()
verifyResult, err := verifier.Verify(ctx, subjectRef, referenceDesc, referrerStore)
if err != nil {
verifierErr := errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace)
verifyResult = vr.VerifierResult{
IsSuccess: false,
Name: verifier.Name(),
Type: verifier.Type(),
Name: verifier.Name(), // Deprecating Name in v2, switch to VerifierName instead.
Type: verifier.Type(), // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: verifier.Name(),
VerifierType: verifier.Type(),
Message: errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace).Error()}
Message: verifierErr.GetDetail(),
ErrorReason: verifierErr.GetErrorReason(),
Remediation: verifierErr.GetRemediation(),
}
}

if len(verifier.GetNestedReferences()) > 0 {
Expand Down Expand Up @@ -229,13 +233,17 @@ func (executor Executor) verifyReferenceForRegoPolicy(ctx context.Context, subje
verifierStartTime := time.Now()
verifierResult, err := verifier.Verify(errCtx, subjectRef, referenceDesc, referrerStore)
if err != nil {
verifierErr := errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace)
verifierReport = vt.VerifierResult{
IsSuccess: false,
Name: verifier.Name(), // Deprecating Name in next release, reference to VerifierName instead.
Type: verifier.Type(), // Deprecating Type in next release, reference to VerifierType instead.
Name: verifier.Name(), // Deprecating Name in v2, switch to VerifierName instead.
binbin-li marked this conversation as resolved.
Show resolved Hide resolved
Type: verifier.Type(), // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: verifier.Name(),
VerifierType: verifier.Type(),
Message: errors.ErrorCodeVerifyReferenceFailure.NewError(errors.Verifier, verifier.Name(), errors.EmptyLink, err, nil, errors.HideStackTrace).Error()}
Message: verifierErr.GetDetail(),
ErrorReason: verifierErr.GetErrorReason(),
Remediation: verifierErr.GetRemediation(),
}
} else {
verifierReport = vt.NewVerifierResult(verifierResult)
}
Expand Down
1 change: 1 addition & 0 deletions pkg/executor/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ type VerifyResult struct {

// NestedVerifierReport describes the results of verifying an artifact and its
// nested artifacts by available verifiers.
// Note: NestedVerifierReport is used for verification results in v1.
type NestedVerifierReport struct {
Subject string `json:"subject"`
ReferenceDigest string `json:"referenceDigest"`
Expand Down
9 changes: 6 additions & 3 deletions pkg/policyprovider/configpolicy/configpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,13 @@ func (enforcer PolicyEnforcer) ContinueVerifyOnFailure(_ context.Context, _ comm

// ErrorToVerifyResult converts an error to a properly formatted verify result
func (enforcer PolicyEnforcer) ErrorToVerifyResult(_ context.Context, subjectRefString string, verifyError error) types.VerifyResult {
verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail(fmt.Sprintf("failed to verify artifact: %s", subjectRefString)).WithError(verifyError)
errorReport := verifier.VerifierResult{
Subject: subjectRefString,
IsSuccess: false,
Message: fmt.Sprintf("verification failed: %v", verifyError),
Subject: subjectRefString,
IsSuccess: false,
Message: verifierErr.GetDetail(),
ErrorReason: verifierErr.GetErrorReason(),
Remediation: verifierErr.GetRemediation(),
}
var reports []interface{}
reports = append(reports, errorReport)
Expand Down
19 changes: 11 additions & 8 deletions pkg/verifier/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,24 @@ import (
"github.com/ratify-project/ratify/pkg/referrerstore"
)

// VerifierResult describes the result of verifying a reference manifest for a subject
// VerifierResult describes the result of verifying a reference manifest for a subject.
// Note: This struct is used to represent the result of verification in v0.
type VerifierResult struct { //nolint:revive // ignore linter to have unique type name
Subject string `json:"subject,omitempty"`
IsSuccess bool `json:"isSuccess"`
Name string `json:"name,omitempty"`
VerifierName string `json:"verifierName,omitempty"`
Subject string `json:"subject,omitempty"`
IsSuccess bool `json:"isSuccess"`
// Name will be deprecated in v2, switch to VerifierName instead.
Name string `json:"name,omitempty"`
VerifierName string `json:"verifierName,omitempty"`
// Type will be deprecated in v2, switch to VerifierType instead.
Type string `json:"type,omitempty"`
VerifierType string `json:"verifierType,omitempty"`
ReferenceDigest string `json:"referenceDigest,omitempty"`
ArtifactType string `json:"artifactType,omitempty"`
Message string `json:"message,omitempty"`
ErrorReason string `json:"errorReason,omitempty"`
Remediation string `json:"remediation,omitempty"`
Extensions interface{} `json:"extensions,omitempty"`
NestedResults []VerifierResult `json:"nestedResults,omitempty"`
ArtifactType string `json:"artifactType,omitempty"`
ReferenceDigest string `json:"referenceDigest,omitempty"`
Remediation string `json:"remediation,omitempty"`
}

// ReferenceVerifier is an interface that defines methods to verify a reference
Expand Down
18 changes: 10 additions & 8 deletions pkg/verifier/cosign/cosign.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ func (v *cosignVerifier) verifyInternal(ctx context.Context, subjectReference co

if hasValidSignature {
return verifier.VerifierResult{
Name: v.name,
Type: v.verifierType,
Name: v.name, // Deprecating Name in v2, switch to VerifierName instead.
Type: v.verifierType, // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: v.name,
VerifierType: v.verifierType,
IsSuccess: true,
Expand Down Expand Up @@ -398,8 +398,8 @@ func (v *cosignVerifier) verifyLegacy(ctx context.Context, subjectReference comm

if len(signatures) > 0 {
return verifier.VerifierResult{
Name: v.name,
Type: v.verifierType,
Name: v.name, // Deprecating Name in v2, switch to VerifierName instead.
Type: v.verifierType, // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: v.name,
VerifierType: v.verifierType,
IsSuccess: true,
Expand Down Expand Up @@ -485,14 +485,16 @@ func staticLayerOpts(desc imgspec.Descriptor) ([]static.Option, error) {

// ErrorToVerifyResult returns a verifier result with the error message and isSuccess set to false
func errorToVerifyResult(name string, verifierType string, err error) verifier.VerifierResult {
verifierErr := re.ErrorCodeVerifyReferenceFailure.WithDetail("Verification failed").WithError(err)
return verifier.VerifierResult{
IsSuccess: false,
Name: name,
Type: verifierType,
Name: name, // Deprecating Name in v2, switch to VerifierName instead.
Type: verifierType, // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: name,
VerifierType: verifierType,
Message: "Verification failed",
ErrorReason: err.Error(),
Message: verifierErr.GetDetail(),
ErrorReason: verifierErr.GetErrorReason(),
Remediation: verifierErr.GetRemediation(),
}
}

Expand Down
3 changes: 3 additions & 0 deletions pkg/verifier/cosign/cosign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ func TestErrorToVerifyResult(t *testing.T) {
if verifierResult.Message != "Verification failed" {
t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.Message, "Verification failed")
}
if verifierResult.ErrorReason != "test error" {
t.Errorf("errorToVerifyResult() = %v, want %v", verifierResult.ErrorReason, "test error")
}
}

// TestDecodeASN1Signature tests the decodeASN1Signature function
Expand Down
4 changes: 2 additions & 2 deletions pkg/verifier/notation/notation.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ func (v *notationPluginVerifier) Verify(ctx context.Context,
}

return verifier.VerifierResult{
Name: v.name,
Type: v.verifierType,
Name: v.name, // Deprecating Name in v2, switch to VerifierName instead.
Type: v.verifierType, // Deprecating Type in v2, switch to VerifierType instead.
VerifierName: v.name,
VerifierType: v.verifierType,
IsSuccess: true,
Expand Down
3 changes: 3 additions & 0 deletions pkg/verifier/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type VerifierResult struct {
IsSuccess bool `json:"isSuccess"`
Message string `json:"message"`
ErrorReason string `json:"errorReason,omitempty"`
Remediation string `json:"remediation,omitempty"`
Name string `json:"name"`
VerifierName string `json:"verifierName,omitempty"`
Type string `json:"type,omitempty"`
Expand Down Expand Up @@ -90,5 +91,7 @@ func NewVerifierResult(result verifier.VerifierResult) VerifierResult {
VerifierName: result.VerifierName,
VerifierType: result.VerifierType,
Extensions: result.Extensions,
ErrorReason: result.ErrorReason,
Remediation: result.Remediation,
}
}
80 changes: 53 additions & 27 deletions plugins/verifier/sbom/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"github.com/ratify-project/ratify/plugins/verifier/sbom/utils"

// This import is required to utilize the oras built-in referrer store
re "github.com/ratify-project/ratify/errors"
_ "github.com/ratify-project/ratify/pkg/referrerstore/oras"
"github.com/ratify-project/ratify/pkg/verifier"
"github.com/ratify-project/ratify/pkg/verifier/plugin/skel"
Expand Down Expand Up @@ -82,19 +83,28 @@
ctx := context.Background()
referenceManifest, err := referrerStore.GetReferenceManifest(ctx, subjectReference, referenceDescriptor)
if err != nil {
storeErr := re.ErrorCodeGetReferenceManifestFailure.WithDetail(fmt.Sprintf("Failed to fetch reference manifest for subject: %s reference descriptor: %v", subjectReference, referenceDescriptor.Descriptor)).WithError(err)
return &verifier.VerifierResult{
Name: input.Name,
Type: verifierType,
IsSuccess: false,
Message: fmt.Sprintf("Error fetching reference manifest for subject: %s reference descriptor: %v, err: %v", subjectReference, referenceDescriptor.Descriptor, err),
Name: input.Name,
Type: verifierType,
VerifierName: input.Name,
VerifierType: verifierType,
IsSuccess: false,
Message: storeErr.GetDetail(),
ErrorReason: storeErr.GetErrorReason(),
Remediation: storeErr.GetRemediation(),
}, nil
}

if len(referenceManifest.Blobs) == 0 {
return &verifier.VerifierResult{
Name: input.Name,
IsSuccess: false,
Message: fmt.Sprintf("SBOM validation failed: no layers found in manifest for referrer %s@%s", subjectReference.Path, referenceDescriptor.Digest.String()),
Name: input.Name,
Type: verifierType,
VerifierName: input.Name,
VerifierType: verifierType,
IsSuccess: false,
Message: "SBOM validation failed",
ErrorReason: fmt.Sprintf("No layers found in manifest for referrer %s@%s", subjectReference.Path, referenceDescriptor.Digest.String()),
}, nil
}

Expand All @@ -103,11 +113,16 @@
refBlob, err := referrerStore.GetBlobContent(ctx, subjectReference, blobDesc.Digest)

if err != nil {
storeErr := re.ErrorCodeGetBlobContentFailure.WithDetail(fmt.Sprintf("Failed to fetch blob for subject: %s digest: %s", subjectReference, blobDesc.Digest)).WithError(err)
return &verifier.VerifierResult{
Name: input.Name,
Type: verifierType,
IsSuccess: false,
Message: fmt.Sprintf("Error fetching blob for subject: %s digest: %s, err: %v", subjectReference, blobDesc.Digest, err),
Name: input.Name,
Type: verifierType,
VerifierName: input.Name,
VerifierType: verifierType,
IsSuccess: false,
Message: storeErr.GetDetail(),
ErrorReason: storeErr.GetErrorReason(),
Remediation: storeErr.GetRemediation(),
}, nil
}

Expand All @@ -116,19 +131,24 @@
return processSpdxJSONMediaType(input.Name, verifierType, refBlob, input.DisallowedLicenses, input.DisallowedPackages), nil
default:
return &verifier.VerifierResult{
Name: input.Name,
Type: verifierType,
IsSuccess: false,
Message: fmt.Sprintf("Unsupported artifactType: %s", artifactType),
Name: input.Name,
Type: verifierType,
VerifierName: input.Name,
VerifierType: verifierType,
IsSuccess: false,
Message: "Failed to process SBOM blobs.",
ErrorReason: fmt.Sprintf("Unsupported artifactType: %s", artifactType),
}, nil
}
}

return &verifier.VerifierResult{
Name: input.Name,
Type: verifierType,
IsSuccess: true,
Message: "SBOM verification success. No license or package violation found.",
Name: input.Name,
Type: verifierType,
VerifierName: input.Name,
VerifierType: verifierType,
IsSuccess: true,
Message: "SBOM verification success. No license or package violation found.",

Check warning on line 151 in plugins/verifier/sbom/sbom.go

View check run for this annotation

Codecov / codecov/patch

plugins/verifier/sbom/sbom.go#L146-L151

Added lines #L146 - L151 were not covered by tests
}, nil
}

Expand Down Expand Up @@ -178,10 +198,12 @@

if len(licenseViolation) != 0 || len(packageViolation) != 0 {
return &verifier.VerifierResult{
Name: name,
IsSuccess: false,
Extensions: extensionData,
Message: "SBOM validation failed. Please review extensions data for license and package violation found.",
Name: name,
IsSuccess: false,
Extensions: extensionData,
Message: "SBOM validation failed.",
ErrorReason: "License or package violation found.",
Remediation: "Please review extensions data for license and package violation found.",
}
}
}
Expand All @@ -196,11 +218,15 @@
Message: "SBOM verification success. No license or package violation found.",
}
}
verifierErr := re.ErrorCodeVerifyPluginFailure.WithDetail(fmt.Sprintf("failed to verify artifact: %s", name)).WithError(err)
return &verifier.VerifierResult{
Name: name,
Type: verifierType,
IsSuccess: false,
Message: fmt.Sprintf("SBOM failed to parse: %v", err),
Name: name,
Type: verifierType,
VerifierName: name,
VerifierType: verifierType,
IsSuccess: false,
Message: verifierErr.GetDetail(),
ErrorReason: verifierErr.GetErrorReason(),
}
}

Expand Down
Loading
Loading