From 127dd7c6e790114a140811ca38cbaaeea4381180 Mon Sep 17 00:00:00 2001 From: Cody Soyland Date: Mon, 5 Feb 2024 14:30:36 -0500 Subject: [PATCH] Refactor errors to use pointer receivers Signed-off-by: Cody Soyland --- metadata/errors.go | 122 ++++++++++++++---- metadata/fetcher/fetcher.go | 6 +- metadata/fetcher/fetcher_test.go | 4 +- metadata/marshal.go | 4 +- metadata/metadata.go | 58 ++++----- metadata/metadata_api_test.go | 88 ++++++------- metadata/trustedmetadata/trustedmetadata.go | 48 +++---- .../trustedmetadata/trustedmetadata_test.go | 70 +++++----- metadata/updater/updater.go | 14 +- .../updater/updater_top_level_update_test.go | 52 ++++---- testutils/simulator/repository_simulator.go | 6 +- 11 files changed, 271 insertions(+), 201 deletions(-) diff --git a/metadata/errors.go b/metadata/errors.go index 38fcc191..3bd8e5ea 100644 --- a/metadata/errors.go +++ b/metadata/errors.go @@ -34,22 +34,33 @@ type ErrRepository struct { Msg string } -func (e ErrRepository) Error() string { +func (e *ErrRepository) Error() string { return fmt.Sprintf("repository error: %s", e.Msg) } +func (e *ErrRepository) Is(target error) bool { + _, ok := target.(*ErrRepository) + return ok +} + // ErrUnsignedMetadata - An error about metadata object with insufficient threshold of signatures type ErrUnsignedMetadata struct { Msg string } -func (e ErrUnsignedMetadata) Error() string { +func (e *ErrUnsignedMetadata) Error() string { return fmt.Sprintf("unsigned metadata error: %s", e.Msg) } // ErrUnsignedMetadata is a subset of ErrRepository -func (e ErrUnsignedMetadata) Is(target error) bool { - return target == ErrRepository{} || target == ErrUnsignedMetadata{} +func (e *ErrUnsignedMetadata) Is(target error) bool { + if _, ok := target.(*ErrUnsignedMetadata); ok { + return true + } + if _, ok := target.(*ErrRepository); ok { + return true + } + return false } // ErrBadVersionNumber - An error for metadata that contains an invalid version number @@ -57,13 +68,19 @@ type ErrBadVersionNumber struct { Msg string } -func (e ErrBadVersionNumber) Error() string { +func (e *ErrBadVersionNumber) Error() string { return fmt.Sprintf("bad version number error: %s", e.Msg) } // ErrBadVersionNumber is a subset of ErrRepository -func (e ErrBadVersionNumber) Is(target error) bool { - return target == ErrRepository{} || target == ErrBadVersionNumber{} +func (e *ErrBadVersionNumber) Is(target error) bool { + if _, ok := target.(*ErrBadVersionNumber); ok { + return true + } + if _, ok := target.(*ErrRepository); ok { + return true + } + return false } // ErrEqualVersionNumber - An error for metadata containing a previously verified version number @@ -71,13 +88,22 @@ type ErrEqualVersionNumber struct { Msg string } -func (e ErrEqualVersionNumber) Error() string { +func (e *ErrEqualVersionNumber) Error() string { return fmt.Sprintf("equal version number error: %s", e.Msg) } // ErrEqualVersionNumber is a subset of both ErrRepository and ErrBadVersionNumber -func (e ErrEqualVersionNumber) Is(target error) bool { - return target == ErrRepository{} || target == ErrBadVersionNumber{} || target == ErrEqualVersionNumber{} +func (e *ErrEqualVersionNumber) Is(target error) bool { + if _, ok := target.(*ErrEqualVersionNumber); ok { + return true + } + if _, ok := target.(*ErrBadVersionNumber); ok { + return true + } + if _, ok := target.(*ErrRepository); ok { + return true + } + return false } // ErrExpiredMetadata - Indicate that a TUF Metadata file has expired @@ -85,13 +111,19 @@ type ErrExpiredMetadata struct { Msg string } -func (e ErrExpiredMetadata) Error() string { +func (e *ErrExpiredMetadata) Error() string { return fmt.Sprintf("expired metadata error: %s", e.Msg) } // ErrExpiredMetadata is a subset of ErrRepository -func (e ErrExpiredMetadata) Is(target error) bool { - return target == ErrRepository{} || target == ErrExpiredMetadata{} +func (e *ErrExpiredMetadata) Is(target error) bool { + if _, ok := target.(*ErrExpiredMetadata); ok { + return true + } + if _, ok := target.(*ErrRepository); ok { + return true + } + return false } // ErrLengthOrHashMismatch - An error while checking the length and hash values of an object @@ -99,13 +131,19 @@ type ErrLengthOrHashMismatch struct { Msg string } -func (e ErrLengthOrHashMismatch) Error() string { +func (e *ErrLengthOrHashMismatch) Error() string { return fmt.Sprintf("length/hash verification error: %s", e.Msg) } // ErrLengthOrHashMismatch is a subset of ErrRepository -func (e ErrLengthOrHashMismatch) Is(target error) bool { - return target == ErrRepository{} || target == ErrLengthOrHashMismatch{} +func (e *ErrLengthOrHashMismatch) Is(target error) bool { + if _, ok := target.(*ErrLengthOrHashMismatch); ok { + return true + } + if _, ok := target.(*ErrRepository); ok { + return true + } + return false } // Download errors @@ -115,22 +153,33 @@ type ErrDownload struct { Msg string } -func (e ErrDownload) Error() string { +func (e *ErrDownload) Error() string { return fmt.Sprintf("download error: %s", e.Msg) } +func (e *ErrDownload) Is(target error) bool { + _, ok := target.(*ErrDownload) + return ok +} + // ErrDownloadLengthMismatch - Indicate that a mismatch of lengths was seen while downloading a file type ErrDownloadLengthMismatch struct { Msg string } -func (e ErrDownloadLengthMismatch) Error() string { +func (e *ErrDownloadLengthMismatch) Error() string { return fmt.Sprintf("download length mismatch error: %s", e.Msg) } // ErrDownloadLengthMismatch is a subset of ErrDownload -func (e ErrDownloadLengthMismatch) Is(target error) bool { - return target == ErrDownload{} || target == ErrDownloadLengthMismatch{} +func (e *ErrDownloadLengthMismatch) Is(target error) bool { + if _, ok := target.(*ErrDownloadLengthMismatch); ok { + return true + } + if _, ok := target.(*ErrDownload); ok { + return true + } + return false } // ErrDownloadHTTP - Returned by Fetcher interface implementations for HTTP errors @@ -139,13 +188,19 @@ type ErrDownloadHTTP struct { URL string } -func (e ErrDownloadHTTP) Error() string { +func (e *ErrDownloadHTTP) Error() string { return fmt.Sprintf("failed to download %s, http status code: %d", e.URL, e.StatusCode) } // ErrDownloadHTTP is a subset of ErrDownload -func (e ErrDownloadHTTP) Is(target error) bool { - return target == ErrDownload{} || target == ErrDownloadHTTP{} +func (e *ErrDownloadHTTP) Is(target error) bool { + if _, ok := target.(*ErrDownloadHTTP); ok { + return true + } + if _, ok := target.(*ErrDownload); ok { + return true + } + return false } // ValueError @@ -153,24 +208,39 @@ type ErrValue struct { Msg string } -func (e ErrValue) Error() string { +func (e *ErrValue) Error() string { return fmt.Sprintf("value error: %s", e.Msg) } +func (e *ErrValue) Is(err error) bool { + _, ok := err.(*ErrValue) + return ok +} + // TypeError type ErrType struct { Msg string } -func (e ErrType) Error() string { +func (e *ErrType) Error() string { return fmt.Sprintf("type error: %s", e.Msg) } +func (e *ErrType) Is(err error) bool { + _, ok := err.(*ErrType) + return ok +} + // RuntimeError type ErrRuntime struct { Msg string } -func (e ErrRuntime) Error() string { +func (e *ErrRuntime) Error() string { return fmt.Sprintf("runtime error: %s", e.Msg) } + +func (e *ErrRuntime) Is(err error) bool { + _, ok := err.(*ErrRuntime) + return ok +} diff --git a/metadata/fetcher/fetcher.go b/metadata/fetcher/fetcher.go index c3e812bf..49234722 100644 --- a/metadata/fetcher/fetcher.go +++ b/metadata/fetcher/fetcher.go @@ -57,7 +57,7 @@ func (d *DefaultFetcher) DownloadFile(urlPath string, maxLength int64, timeout t defer res.Body.Close() // Handle HTTP status codes. if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusForbidden || res.StatusCode != http.StatusOK { - return nil, metadata.ErrDownloadHTTP{StatusCode: res.StatusCode, URL: urlPath} + return nil, &metadata.ErrDownloadHTTP{StatusCode: res.StatusCode, URL: urlPath} } var length int64 // Get content length from header (might not be accurate, -1 or not set). @@ -68,7 +68,7 @@ func (d *DefaultFetcher) DownloadFile(urlPath string, maxLength int64, timeout t } // Error if the reported size is greater than what is expected. if length > maxLength { - return nil, metadata.ErrDownloadLengthMismatch{Msg: fmt.Sprintf("download failed for %s, length %d is larger than expected %d", urlPath, length, maxLength)} + return nil, &metadata.ErrDownloadLengthMismatch{Msg: fmt.Sprintf("download failed for %s, length %d is larger than expected %d", urlPath, length, maxLength)} } } // Although the size has been checked above, use a LimitReader in case @@ -82,7 +82,7 @@ func (d *DefaultFetcher) DownloadFile(urlPath string, maxLength int64, timeout t // Error if the reported size is greater than what is expected. length = int64(len(data)) if length > maxLength { - return nil, metadata.ErrDownloadLengthMismatch{Msg: fmt.Sprintf("download failed for %s, length %d is larger than expected %d", urlPath, length, maxLength)} + return nil, &metadata.ErrDownloadLengthMismatch{Msg: fmt.Sprintf("download failed for %s, length %d is larger than expected %d", urlPath, length, maxLength)} } return data, nil diff --git a/metadata/fetcher/fetcher_test.go b/metadata/fetcher/fetcher_test.go index 484ebd0b..5bd8e6d1 100644 --- a/metadata/fetcher/fetcher_test.go +++ b/metadata/fetcher/fetcher_test.go @@ -64,7 +64,7 @@ func TestDownLoadFile(t *testing.T) { desc: "Path does not exist", url: "https://jku.github.io/tuf-demo/metadata/badPath.json", data: nil, - wantErr: metadata.ErrDownloadHTTP{}, + wantErr: &metadata.ErrDownloadHTTP{}, }, { name: "data too long", @@ -72,7 +72,7 @@ func TestDownLoadFile(t *testing.T) { url: "https://jku.github.io/tuf-demo/metadata/1.root.json", maxLength: 1, data: nil, - wantErr: metadata.ErrDownloadLengthMismatch{}, + wantErr: &metadata.ErrDownloadLengthMismatch{}, }, } { t.Run(tt.name, func(t *testing.T) { diff --git a/metadata/marshal.go b/metadata/marshal.go index 97cf351b..bd3f1e44 100644 --- a/metadata/marshal.go +++ b/metadata/marshal.go @@ -335,7 +335,7 @@ func (meta *Metadata[T]) UnmarshalJSON(data []byte) error { meta.Signed = i.(T) meta.Signatures = dict.Signatures default: - return ErrValue{Msg: "unrecognized metadata type"} + return &ErrValue{Msg: "unrecognized metadata type"} } delete(m, "signed") delete(m, "signatures") @@ -470,7 +470,7 @@ func (role DelegatedRole) MarshalJSON() ([]byte, error) { dict["terminating"] = role.Terminating // make sure we have only one of the two (per spec) if role.Paths != nil && role.PathHashPrefixes != nil { - return nil, ErrValue{Msg: "failed to marshal: not allowed to have both \"paths\" and \"path_hash_prefixes\" present"} + return nil, &ErrValue{Msg: "failed to marshal: not allowed to have both \"paths\" and \"path_hash_prefixes\" present"} } if role.Paths != nil { dict["paths"] = role.Paths diff --git a/metadata/metadata.go b/metadata/metadata.go index e7b8ce3b..8bfecbb6 100644 --- a/metadata/metadata.go +++ b/metadata/metadata.go @@ -218,7 +218,7 @@ func (meta *Metadata[T]) Sign(signer signature.Signer) (*Signature, error) { // sign the Signed part sb, err := signer.SignMessage(bytes.NewReader(payload)) if err != nil { - return nil, ErrUnsignedMetadata{Msg: "problem signing metadata"} + return nil, &ErrUnsignedMetadata{Msg: "problem signing metadata"} } // get the signer's PublicKey publ, err := signer.PublicKey() @@ -263,12 +263,12 @@ func (meta *Metadata[T]) VerifyDelegate(delegatedRole string, delegatedMetadata roleThreshold = role.Threshold } else { // the delegated role was not found, no need to proceed - return ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} + return &ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} } // Targets delegator case *Metadata[TargetsType]: if i.Signed.Delegations == nil { - return ErrValue{Msg: "no delegations found"} + return &ErrValue{Msg: "no delegations found"} } keys = i.Signed.Delegations.Keys if i.Signed.Delegations.Roles != nil { @@ -283,24 +283,24 @@ func (meta *Metadata[T]) VerifyDelegate(delegatedRole string, delegatedMetadata } // the delegated role was not found, no need to proceed if !found { - return ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} + return &ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} } } else if i.Signed.Delegations.SuccinctRoles != nil { roleKeyIDs = i.Signed.Delegations.SuccinctRoles.KeyIDs roleThreshold = i.Signed.Delegations.SuccinctRoles.Threshold } default: - return ErrType{Msg: "call is valid only on delegator metadata (should be either root or targets)"} + return &ErrType{Msg: "call is valid only on delegator metadata (should be either root or targets)"} } // if there are no keyIDs for that role it means there's no delegation found if len(roleKeyIDs) == 0 { - return ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} + return &ErrValue{Msg: fmt.Sprintf("no delegation found for %s", delegatedRole)} } // loop through each role keyID for _, keyID := range roleKeyIDs { key, ok := keys[keyID] if !ok { - return ErrValue{Msg: fmt.Sprintf("key with ID %s not found in %s keyids", keyID, delegatedRole)} + return &ErrValue{Msg: fmt.Sprintf("key with ID %s not found in %s keyids", keyID, delegatedRole)} } sign := Signature{} var payload []byte @@ -363,7 +363,7 @@ func (meta *Metadata[T]) VerifyDelegate(delegatedRole string, delegatedMetadata return err } default: - return ErrType{Msg: "unknown delegated metadata type"} + return &ErrType{Msg: "unknown delegated metadata type"} } // verify if the signature for that payload corresponds to the given key if err := verifier.VerifySignature(bytes.NewReader(sign.Signature), bytes.NewReader(payload)); err != nil { @@ -378,7 +378,7 @@ func (meta *Metadata[T]) VerifyDelegate(delegatedRole string, delegatedMetadata // check if the amount of valid signatures is enough if len(signingKeys) < roleThreshold { log.Info("Verifying failed, not enough signatures", "role", delegatedRole, "got", len(signingKeys), "want", roleThreshold) - return ErrUnsignedMetadata{Msg: fmt.Sprintf("Verifying %s failed, not enough signatures, got %d, want %d", delegatedRole, len(signingKeys), roleThreshold)} + return &ErrUnsignedMetadata{Msg: fmt.Sprintf("Verifying %s failed, not enough signatures, got %d, want %d", delegatedRole, len(signingKeys), roleThreshold)} } log.Info("Verified successfully", "role", delegatedRole) return nil @@ -490,7 +490,7 @@ func (t *TargetFiles) FromBytes(localPath string, data []byte, hashes ...string) case "sha512": hasher = sha512.New() default: - return nil, ErrValue{Msg: fmt.Sprintf("failed generating TargetFile - unsupported hashing algorithm - %s", v)} + return nil, &ErrValue{Msg: fmt.Sprintf("failed generating TargetFile - unsupported hashing algorithm - %s", v)} } _, err := hasher.Write(data) if err != nil { @@ -653,7 +653,7 @@ func (role *SuccinctRoles) IsDelegatedRole(roleName string) bool { func (signed *RootType) AddKey(key *Key, role string) error { // verify role is present if _, ok := signed.Roles[role]; !ok { - return ErrValue{Msg: fmt.Sprintf("role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("role %s doesn't exist", role)} } // add keyID to role if !slices.Contains(signed.Roles[role].KeyIDs, key.ID()) { @@ -670,11 +670,11 @@ func (signed *RootType) AddKey(key *Key, role string) error { func (signed *RootType) RevokeKey(keyID, role string) error { // verify role is present if _, ok := signed.Roles[role]; !ok { - return ErrValue{Msg: fmt.Sprintf("role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("role %s doesn't exist", role)} } // verify keyID is present for given role if !slices.Contains(signed.Roles[role].KeyIDs, keyID) { - return ErrValue{Msg: fmt.Sprintf("key with id %s is not used by %s", keyID, role)} + return &ErrValue{Msg: fmt.Sprintf("key with id %s is not used by %s", keyID, role)} } // remove keyID from role filteredKeyIDs := []string{} @@ -703,7 +703,7 @@ func (signed *RootType) RevokeKey(keyID, role string) error { func (signed *TargetsType) AddKey(key *Key, role string) error { // check if Delegations are even present if signed.Delegations == nil { - return ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} } // standard delegated roles if signed.Delegations.Roles != nil { @@ -723,7 +723,7 @@ func (signed *TargetsType) AddKey(key *Key, role string) error { } } if !isDelegatedRole { - return ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} } } else if signed.Delegations.SuccinctRoles != nil { // add key if keyID is not already part of keyIDs for the SuccinctRoles role @@ -745,7 +745,7 @@ func (signed *TargetsType) AddKey(key *Key, role string) error { func (signed *TargetsType) RevokeKey(keyID string, role string) error { // check if Delegations are even present if signed.Delegations == nil { - return ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} } // standard delegated roles if signed.Delegations.Roles != nil { @@ -755,7 +755,7 @@ func (signed *TargetsType) RevokeKey(keyID string, role string) error { if d.Name == role { // check if keyID is present in keyIDs for that role if !slices.Contains(d.KeyIDs, keyID) { - return ErrValue{Msg: fmt.Sprintf("key with id %s is not used by %s", keyID, role)} + return &ErrValue{Msg: fmt.Sprintf("key with id %s is not used by %s", keyID, role)} } // remove keyID from role filteredKeyIDs := []string{} @@ -778,11 +778,11 @@ func (signed *TargetsType) RevokeKey(keyID string, role string) error { } } // we haven't found the delegated role - return ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} } else if signed.Delegations.SuccinctRoles != nil { // check if keyID is used by SuccinctRoles role if !slices.Contains(signed.Delegations.SuccinctRoles.KeyIDs, keyID) { - return ErrValue{Msg: fmt.Sprintf("key with id %s is not used by SuccinctRoles", keyID)} + return &ErrValue{Msg: fmt.Sprintf("key with id %s is not used by SuccinctRoles", keyID)} } // remove keyID from the SuccinctRoles role filteredKeyIDs := []string{} @@ -798,7 +798,7 @@ func (signed *TargetsType) RevokeKey(keyID string, role string) error { delete(signed.Delegations.Keys, keyID) return nil } - return ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} + return &ErrValue{Msg: fmt.Sprintf("delegated role %s doesn't exist", role)} } // Equal checks whether one hash set equals another @@ -824,7 +824,7 @@ func verifyLength(data []byte, length int64) error { return err } if length != len { - return ErrLengthOrHashMismatch{Msg: fmt.Sprintf("length verification failed - expected %d, got %d", length, len)} + return &ErrLengthOrHashMismatch{Msg: fmt.Sprintf("length verification failed - expected %d, got %d", length, len)} } return nil } @@ -839,11 +839,11 @@ func verifyHashes(data []byte, hashes Hashes) error { case "sha512": hasher = sha512.New() default: - return ErrLengthOrHashMismatch{Msg: fmt.Sprintf("hash verification failed - unknown hashing algorithm - %s", k)} + return &ErrLengthOrHashMismatch{Msg: fmt.Sprintf("hash verification failed - unknown hashing algorithm - %s", k)} } hasher.Write(data) if hex.EncodeToString(v) != hex.EncodeToString(hasher.Sum(nil)) { - return ErrLengthOrHashMismatch{Msg: fmt.Sprintf("hash verification failed - mismatch for algorithm %s", k)} + return &ErrLengthOrHashMismatch{Msg: fmt.Sprintf("hash verification failed - mismatch for algorithm %s", k)} } } return nil @@ -873,7 +873,7 @@ func checkUniqueSignatures[T Roles](meta Metadata[T]) error { signatures := []string{} for _, sig := range meta.Signatures { if slices.Contains(signatures, sig.KeyID) { - return ErrValue{Msg: fmt.Sprintf("multiple signatures found for key ID %s", sig.KeyID)} + return &ErrValue{Msg: fmt.Sprintf("multiple signatures found for key ID %s", sig.KeyID)} } signatures = append(signatures, sig.KeyID) } @@ -891,22 +891,22 @@ func checkType[T Roles](data []byte) error { switch i.(type) { case *RootType: if ROOT != signedType { - return ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", ROOT, signedType)} + return &ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", ROOT, signedType)} } case *SnapshotType: if SNAPSHOT != signedType { - return ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", SNAPSHOT, signedType)} + return &ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", SNAPSHOT, signedType)} } case *TimestampType: if TIMESTAMP != signedType { - return ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", TIMESTAMP, signedType)} + return &ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", TIMESTAMP, signedType)} } case *TargetsType: if TARGETS != signedType { - return ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", TARGETS, signedType)} + return &ErrValue{Msg: fmt.Sprintf("expected metadata type %s, got - %s", TARGETS, signedType)} } default: - return ErrValue{Msg: fmt.Sprintf("unrecognized metadata type - %s", signedType)} + return &ErrValue{Msg: fmt.Sprintf("unrecognized metadata type - %s", signedType)} } // all okay return nil diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go index 38950a81..2ab6b9db 100644 --- a/metadata/metadata_api_test.go +++ b/metadata/metadata_api_test.go @@ -56,13 +56,13 @@ func TestGenericRead(t *testing.T) { // Assert that it chokes correctly on an unknown metadata type badMetadata := "{\"signed\": {\"_type\": \"bad-metadata\"}}" _, err := Root().FromBytes([]byte(badMetadata)) - assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type root, got - bad-metadata"}) _, err = Snapshot().FromBytes([]byte(badMetadata)) - assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type snapshot, got - bad-metadata"}) _, err = Targets().FromBytes([]byte(badMetadata)) - assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type targets, got - bad-metadata"}) _, err = Timestamp().FromBytes([]byte(badMetadata)) - assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type timestamp, got - bad-metadata"}) badMetadataPath := filepath.Join(testutils.RepoDir, "bad-metadata.json") err = os.WriteFile(badMetadataPath, []byte(badMetadata), 0644) @@ -70,13 +70,13 @@ func TestGenericRead(t *testing.T) { assert.FileExists(t, badMetadataPath) _, err = Root().FromFile(badMetadataPath) - assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type root, got - bad-metadata"}) _, err = Snapshot().FromFile(badMetadataPath) - assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type snapshot, got - bad-metadata"}) _, err = Targets().FromFile(badMetadataPath) - assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type targets, got - bad-metadata"}) _, err = Timestamp().FromFile(badMetadataPath) - assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - bad-metadata"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type timestamp, got - bad-metadata"}) err = os.RemoveAll(badMetadataPath) assert.NoError(t, err) @@ -86,35 +86,35 @@ func TestGenericRead(t *testing.T) { func TestGenericReadFromMismatchingRoles(t *testing.T) { // Test failing to load other roles from root metadata _, err := Snapshot().FromFile(filepath.Join(testutils.RepoDir, "root.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - root"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type snapshot, got - root"}) _, err = Timestamp().FromFile(filepath.Join(testutils.RepoDir, "root.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - root"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type timestamp, got - root"}) _, err = Targets().FromFile(filepath.Join(testutils.RepoDir, "root.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - root"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type targets, got - root"}) // Test failing to load other roles from targets metadata _, err = Snapshot().FromFile(filepath.Join(testutils.RepoDir, "targets.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - targets"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type snapshot, got - targets"}) _, err = Timestamp().FromFile(filepath.Join(testutils.RepoDir, "targets.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - targets"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type timestamp, got - targets"}) _, err = Root().FromFile(filepath.Join(testutils.RepoDir, "targets.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - targets"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type root, got - targets"}) // Test failing to load other roles from timestamp metadata _, err = Snapshot().FromFile(filepath.Join(testutils.RepoDir, "timestamp.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type snapshot, got - timestamp"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type snapshot, got - timestamp"}) _, err = Targets().FromFile(filepath.Join(testutils.RepoDir, "timestamp.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - timestamp"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type targets, got - timestamp"}) _, err = Root().FromFile(filepath.Join(testutils.RepoDir, "timestamp.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - timestamp"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type root, got - timestamp"}) // Test failing to load other roles from snapshot metadata _, err = Targets().FromFile(filepath.Join(testutils.RepoDir, "snapshot.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type targets, got - snapshot"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type targets, got - snapshot"}) _, err = Timestamp().FromFile(filepath.Join(testutils.RepoDir, "snapshot.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type timestamp, got - snapshot"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type timestamp, got - snapshot"}) _, err = Root().FromFile(filepath.Join(testutils.RepoDir, "snapshot.json")) - assert.ErrorIs(t, err, ErrValue{"expected metadata type root, got - snapshot"}) + assert.ErrorIs(t, err, &ErrValue{"expected metadata type root, got - snapshot"}) } func TestMDReadWriteFileExceptions(t *testing.T) { @@ -534,21 +534,21 @@ func TestMetadataVerifyDelegate(t *testing.T) { // Only root and targets can verify delegates err = snapshot.VerifyDelegate(SNAPSHOT, snapshot) - assert.ErrorIs(t, err, ErrType{"call is valid only on delegator metadata (should be either root or targets)"}) + assert.ErrorIs(t, err, &ErrType{"call is valid only on delegator metadata (should be either root or targets)"}) // Verify fails for roles that are not delegated by delegator err = root.VerifyDelegate("role1", role1) - assert.ErrorIs(t, err, ErrValue{"no delegation found for role1"}) + assert.ErrorIs(t, err, &ErrValue{"no delegation found for role1"}) err = targets.VerifyDelegate(TARGETS, targets) - assert.ErrorIs(t, err, ErrValue{"no delegation found for targets"}) + assert.ErrorIs(t, err, &ErrValue{"no delegation found for targets"}) // Verify fails when delegator has no delegations err = role2.VerifyDelegate("role1", role1) - assert.ErrorIs(t, err, ErrValue{"no delegations found"}) + assert.ErrorIs(t, err, &ErrValue{"no delegations found"}) // Verify fails when delegate content is modified expires := snapshot.Signed.Expires snapshot.Signed.Expires = snapshot.Signed.Expires.Add(time.Hour * 24) err = root.VerifyDelegate(SNAPSHOT, snapshot) - assert.ErrorIs(t, err, ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 0, want 1"}) snapshot.Signed.Expires = expires // Verify fails with verification error @@ -558,12 +558,12 @@ func TestMetadataVerifyDelegate(t *testing.T) { assert.NotEmpty(t, goodSig) snapshot.Signatures[idx].Signature = []byte("foo") err = root.VerifyDelegate(SNAPSHOT, snapshot) - assert.ErrorIs(t, err, ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 0, want 1"}) snapshot.Signatures[idx].Signature = goodSig // Verify fails if roles keys do not sign the metadata err = root.VerifyDelegate(TIMESTAMP, snapshot) - assert.ErrorIs(t, err, ErrUnsignedMetadata{"Verifying timestamp failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &ErrUnsignedMetadata{"Verifying timestamp failed, not enough signatures, got 0, want 1"}) // Add a key to snapshot role, make sure the new sig fails to verify tsKeyID := root.Signed.Roles[TIMESTAMP].KeyIDs[0] @@ -583,7 +583,7 @@ func TestMetadataVerifyDelegate(t *testing.T) { // Verify fails if threshold of signatures is not reached root.Signed.Roles[SNAPSHOT].Threshold = 2 err = root.VerifyDelegate(SNAPSHOT, snapshot) - assert.ErrorIs(t, err, ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 1, want 2"}) + assert.ErrorIs(t, err, &ErrUnsignedMetadata{"Verifying snapshot failed, not enough signatures, got 1, want 2"}) // Verify succeeds when we correct the new signature and reach the // threshold of 2 keys @@ -637,7 +637,7 @@ func TestRootAddKeyAndRevokeKey(t *testing.T) { // Add the same key to a nonexistent role. err = root.Signed.AddKey(rootKey2, "nosuchrole") - assert.ErrorIs(t, err, ErrValue{"role nosuchrole doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"role nosuchrole doesn't exist"}) // Remove the key from root role (targets role still uses it) err = root.Signed.RevokeKey(rootKey2.id, ROOT) @@ -652,9 +652,9 @@ func TestRootAddKeyAndRevokeKey(t *testing.T) { assert.NotContains(t, root.Signed.Keys, rootKey2.id) err = root.Signed.RevokeKey("nosuchkey", ROOT) - assert.ErrorIs(t, err, ErrValue{"key with id nosuchkey is not used by root"}) + assert.ErrorIs(t, err, &ErrValue{"key with id nosuchkey is not used by root"}) err = root.Signed.RevokeKey(rootKey2.id, "nosuchrole") - assert.ErrorIs(t, err, ErrValue{"role nosuchrole doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"role nosuchrole doesn't exist"}) } func TestTargetsKeyAPI(t *testing.T) { @@ -694,7 +694,7 @@ func TestTargetsKeyAPI(t *testing.T) { // Try adding a key to a delegated role that doesn't exists err = targets.Signed.AddKey(key, "nosuchrole") - assert.ErrorIs(t, err, ErrValue{"delegated role nosuchrole doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"delegated role nosuchrole doesn't exist"}) // Add the same key to "role2" as well err = targets.Signed.AddKey(key, "role2") @@ -717,11 +717,11 @@ func TestTargetsKeyAPI(t *testing.T) { // Try remove key not used by "role1" err = targets.Signed.RevokeKey(key.id, "role1") - assert.ErrorIs(t, err, ErrValue{fmt.Sprintf("key with id %s is not used by role1", key.id)}) + assert.ErrorIs(t, err, &ErrValue{fmt.Sprintf("key with id %s is not used by role1", key.id)}) // Try removing a key from delegated role that doesn't exists err = targets.Signed.RevokeKey(key.id, "nosuchrole") - assert.ErrorIs(t, err, ErrValue{"delegated role nosuchrole doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"delegated role nosuchrole doesn't exist"}) // Remove delegations as a whole targets.Signed.Delegations = nil @@ -729,9 +729,9 @@ func TestTargetsKeyAPI(t *testing.T) { //Test that calling add_key and revoke_key throws an error // and that delegations is still None after each of the api calls err = targets.Signed.AddKey(key, "role1") - assert.ErrorIs(t, err, ErrValue{"delegated role role1 doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"delegated role role1 doesn't exist"}) err = targets.Signed.RevokeKey(key.id, "role1") - assert.ErrorIs(t, err, ErrValue{"delegated role role1 doesn't exist"}) + assert.ErrorIs(t, err, &ErrValue{"delegated role role1 doesn't exist"}) assert.Nil(t, targets.Signed.Delegations) } @@ -781,7 +781,7 @@ func TestTargetsKeyAPIWithSuccinctRoles(t *testing.T) { // Try removing it again. err = targets.Signed.RevokeKey(key.id, "foo") - assert.ErrorIs(t, err, ErrValue{fmt.Sprintf("key with id %s is not used by SuccinctRoles", key.id)}) + assert.ErrorIs(t, err, &ErrValue{fmt.Sprintf("key with id %s is not used by SuccinctRoles", key.id)}) } func TestLengthAndHashValidation(t *testing.T) { @@ -813,18 +813,18 @@ func TestLengthAndHashValidation(t *testing.T) { originalLength := snapshotMetafile.Length snapshotMetafile.Length = 2345 err = snapshotMetafile.VerifyLengthHashes(data) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{fmt.Sprintf("length verification failed - expected %d, got %d", 2345, originalLength)}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{fmt.Sprintf("length verification failed - expected %d, got %d", 2345, originalLength)}) snapshotMetafile.Length = originalLength originalHashSHA256 := snapshotMetafile.Hashes["sha256"] snapshotMetafile.Hashes["sha256"] = []byte("incorrecthash") err = snapshotMetafile.VerifyLengthHashes(data) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) snapshotMetafile.Hashes["sha256"] = originalHashSHA256 snapshotMetafile.Hashes["unsupported-alg"] = []byte("72c5cabeb3e8079545a5f4d2b067f8e35f18a0de3c2b00d3cb8d05919c19c72d") err = snapshotMetafile.VerifyLengthHashes(data) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{"hash verification failed - unknown hashing algorithm - unsupported-alg"}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{"hash verification failed - unknown hashing algorithm - unsupported-alg"}) // test optional length and hashes snapshotMetafile.Length = 0 @@ -843,12 +843,12 @@ func TestLengthAndHashValidation(t *testing.T) { originalLength = targetFile.Length targetFile.Length = 2345 err = targetFile.VerifyLengthHashes(targetFileData) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{fmt.Sprintf("length verification failed - expected %d, got %d", 2345, originalLength)}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{fmt.Sprintf("length verification failed - expected %d, got %d", 2345, originalLength)}) targetFile.Length = originalLength targetFile.Hashes["sha256"] = []byte("incorrecthash") err = targetFile.VerifyLengthHashes(targetFileData) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) } func TestTargetFileFromFile(t *testing.T) { @@ -866,11 +866,11 @@ func TestTargetFileFromFile(t *testing.T) { mismatchingTargetFileData, err := os.ReadFile(mismatchingTargetFilePath) assert.NoError(t, err) err = targetFileFromFile.VerifyLengthHashes(mismatchingTargetFileData) - assert.ErrorIs(t, err, ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) + assert.ErrorIs(t, err, &ErrLengthOrHashMismatch{"hash verification failed - mismatch for algorithm sha256"}) // Test with an unsupported algorithm _, err = TargetFile().FromFile(targetFilePath, "123") - assert.ErrorIs(t, err, ErrValue{"failed generating TargetFile - unsupported hashing algorithm - 123"}) + assert.ErrorIs(t, err, &ErrValue{"failed generating TargetFile - unsupported hashing algorithm - 123"}) } func TestTargetFileCustom(t *testing.T) { diff --git a/metadata/trustedmetadata/trustedmetadata.go b/metadata/trustedmetadata/trustedmetadata.go index 7185fe81..0726f31f 100644 --- a/metadata/trustedmetadata/trustedmetadata.go +++ b/metadata/trustedmetadata/trustedmetadata.go @@ -58,7 +58,7 @@ func (trusted *TrustedMetadata) UpdateRoot(rootData []byte) (*metadata.Metadata[ log := metadata.GetLogger() if trusted.Timestamp != nil { - return nil, metadata.ErrRuntime{Msg: "cannot update root after timestamp"} + return nil, &metadata.ErrRuntime{Msg: "cannot update root after timestamp"} } log.Info("Updating root") // generate root metadata @@ -68,7 +68,7 @@ func (trusted *TrustedMetadata) UpdateRoot(rootData []byte) (*metadata.Metadata[ } // check metadata type matches root if newRoot.Signed.Type != metadata.ROOT { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.ROOT, newRoot.Signed.Type)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.ROOT, newRoot.Signed.Type)} } // verify that new root is signed by trusted root err = trusted.Root.VerifyDelegate(metadata.ROOT, newRoot) @@ -77,7 +77,7 @@ func (trusted *TrustedMetadata) UpdateRoot(rootData []byte) (*metadata.Metadata[ } // verify version if newRoot.Signed.Version != trusted.Root.Signed.Version+1 { - return nil, metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("bad version number, expected %d, got %d", trusted.Root.Signed.Version+1, newRoot.Signed.Version)} + return nil, &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("bad version number, expected %d, got %d", trusted.Root.Signed.Version+1, newRoot.Signed.Version)} } // verify that new root is signed by itself err = newRoot.VerifyDelegate(metadata.ROOT, newRoot) @@ -100,13 +100,13 @@ func (trusted *TrustedMetadata) UpdateTimestamp(timestampData []byte) (*metadata log := metadata.GetLogger() if trusted.Snapshot != nil { - return nil, metadata.ErrRuntime{Msg: "cannot update timestamp after snapshot"} + return nil, &metadata.ErrRuntime{Msg: "cannot update timestamp after snapshot"} } // client workflow 5.3.10: Make sure final root is not expired. if trusted.Root.Signed.IsExpired(trusted.RefTime) { // no need to check for 5.3.11 (fast forward attack recovery): // timestamp/snapshot can not yet be loaded at this point - return nil, metadata.ErrExpiredMetadata{Msg: "final root.json is expired"} + return nil, &metadata.ErrExpiredMetadata{Msg: "final root.json is expired"} } log.Info("Updating timestamp") newTimestamp, err := metadata.Timestamp().FromBytes(timestampData) @@ -115,7 +115,7 @@ func (trusted *TrustedMetadata) UpdateTimestamp(timestampData []byte) (*metadata } // check metadata type matches timestamp if newTimestamp.Signed.Type != metadata.TIMESTAMP { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.TIMESTAMP, newTimestamp.Signed.Type)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.TIMESTAMP, newTimestamp.Signed.Type)} } // verify that new timestamp is signed by trusted root err = trusted.Root.VerifyDelegate(metadata.TIMESTAMP, newTimestamp) @@ -127,18 +127,18 @@ func (trusted *TrustedMetadata) UpdateTimestamp(timestampData []byte) (*metadata if trusted.Timestamp != nil { // prevent rolling back timestamp version if newTimestamp.Signed.Version < trusted.Timestamp.Signed.Version { - return nil, metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("new timestamp version %d must be >= %d", newTimestamp.Signed.Version, trusted.Timestamp.Signed.Version)} + return nil, &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("new timestamp version %d must be >= %d", newTimestamp.Signed.Version, trusted.Timestamp.Signed.Version)} } // keep using old timestamp if versions are equal if newTimestamp.Signed.Version == trusted.Timestamp.Signed.Version { log.Info("New timestamp version equals the old one", "new", newTimestamp.Signed.Version, "old", trusted.Timestamp.Signed.Version) - return nil, metadata.ErrEqualVersionNumber{Msg: fmt.Sprintf("new timestamp version %d equals the old one %d", newTimestamp.Signed.Version, trusted.Timestamp.Signed.Version)} + return nil, &metadata.ErrEqualVersionNumber{Msg: fmt.Sprintf("new timestamp version %d equals the old one %d", newTimestamp.Signed.Version, trusted.Timestamp.Signed.Version)} } // prevent rolling back snapshot version snapshotMeta := trusted.Timestamp.Signed.Meta[fmt.Sprintf("%s.json", metadata.SNAPSHOT)] newSnapshotMeta := newTimestamp.Signed.Meta[fmt.Sprintf("%s.json", metadata.SNAPSHOT)] if newSnapshotMeta.Version < snapshotMeta.Version { - return nil, metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("new snapshot version %d must be >= %d", newSnapshotMeta.Version, snapshotMeta.Version)} + return nil, &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("new snapshot version %d must be >= %d", newSnapshotMeta.Version, snapshotMeta.Version)} } } // expiry not checked to allow old timestamp to be used for rollback @@ -159,7 +159,7 @@ func (trusted *TrustedMetadata) UpdateTimestamp(timestampData []byte) (*metadata // checkFinalTimestamp verifies if trusted timestamp is not expired func (trusted *TrustedMetadata) checkFinalTimestamp() error { if trusted.Timestamp.Signed.IsExpired(trusted.RefTime) { - return metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"} + return &metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"} } return nil } @@ -176,10 +176,10 @@ func (trusted *TrustedMetadata) UpdateSnapshot(snapshotData []byte, isTrusted bo log := metadata.GetLogger() if trusted.Timestamp == nil { - return nil, metadata.ErrRuntime{Msg: "cannot update snapshot before timestamp"} + return nil, &metadata.ErrRuntime{Msg: "cannot update snapshot before timestamp"} } if trusted.Targets[metadata.TARGETS] != nil { - return nil, metadata.ErrRuntime{Msg: "cannot update snapshot after targets"} + return nil, &metadata.ErrRuntime{Msg: "cannot update snapshot after targets"} } log.Info("Updating snapshot") @@ -203,7 +203,7 @@ func (trusted *TrustedMetadata) UpdateSnapshot(snapshotData []byte, isTrusted bo } // check metadata type matches snapshot if newSnapshot.Signed.Type != metadata.SNAPSHOT { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.SNAPSHOT, newSnapshot.Signed.Type)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.SNAPSHOT, newSnapshot.Signed.Type)} } // verify that new snapshot is signed by trusted root err = trusted.Root.VerifyDelegate(metadata.SNAPSHOT, newSnapshot) @@ -220,11 +220,11 @@ func (trusted *TrustedMetadata) UpdateSnapshot(snapshotData []byte, isTrusted bo newFileInfo, ok := newSnapshot.Signed.Meta[name] // prevent removal of any metadata in meta if !ok { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("new snapshot is missing info for %s", name)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("new snapshot is missing info for %s", name)} } // prevent rollback of any metadata versions if newFileInfo.Version < info.Version { - return nil, metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %s version %d, got %d", name, newFileInfo.Version, info.Version)} + return nil, &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %s version %d, got %d", name, newFileInfo.Version, info.Version)} } } } @@ -246,11 +246,11 @@ func (trusted *TrustedMetadata) UpdateSnapshot(snapshotData []byte, isTrusted bo // checkFinalSnapshot verifies if it's not expired and snapshot version matches timestamp meta version func (trusted *TrustedMetadata) checkFinalSnapshot() error { if trusted.Snapshot.Signed.IsExpired(trusted.RefTime) { - return metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"} + return &metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"} } snapshotMeta := trusted.Timestamp.Signed.Meta[fmt.Sprintf("%s.json", metadata.SNAPSHOT)] if trusted.Snapshot.Signed.Version != snapshotMeta.Version { - return metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %d, got %d", snapshotMeta.Version, trusted.Snapshot.Signed.Version)} + return &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %d, got %d", snapshotMeta.Version, trusted.Snapshot.Signed.Version)} } return nil } @@ -266,7 +266,7 @@ func (trusted *TrustedMetadata) UpdateDelegatedTargets(targetsData []byte, roleN var ok bool if trusted.Snapshot == nil { - return nil, metadata.ErrRuntime{Msg: "cannot load targets before snapshot"} + return nil, &metadata.ErrRuntime{Msg: "cannot load targets before snapshot"} } // targets cannot be loaded if final snapshot is expired or its version // does not match meta version in timestamp @@ -285,13 +285,13 @@ func (trusted *TrustedMetadata) UpdateDelegatedTargets(targetsData []byte, roleN _, ok = trusted.Targets[delegatorName] } if !ok { - return nil, metadata.ErrRuntime{Msg: "cannot load targets before delegator"} + return nil, &metadata.ErrRuntime{Msg: "cannot load targets before delegator"} } log.Info("Updating delegated role", "role", roleName, "delegator", delegatorName) // Verify against the hashes in snapshot, if any meta, ok := trusted.Snapshot.Signed.Meta[fmt.Sprintf("%s.json", roleName)] if !ok { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("snapshot does not contain information for %s", roleName)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("snapshot does not contain information for %s", roleName)} } err = meta.VerifyLengthHashes(targetsData) if err != nil { @@ -303,7 +303,7 @@ func (trusted *TrustedMetadata) UpdateDelegatedTargets(targetsData []byte, roleN } // check metadata type matches targets if newDelegate.Signed.Type != metadata.TARGETS { - return nil, metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.TARGETS, newDelegate.Signed.Type)} + return nil, &metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.TARGETS, newDelegate.Signed.Type)} } // get delegator metadata and verify the new delegatee if delegatorName == metadata.ROOT { @@ -319,11 +319,11 @@ func (trusted *TrustedMetadata) UpdateDelegatedTargets(targetsData []byte, roleN } // check versions if newDelegate.Signed.Version != meta.Version { - return nil, metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %s version %d, got %d", roleName, meta.Version, newDelegate.Signed.Version)} + return nil, &metadata.ErrBadVersionNumber{Msg: fmt.Sprintf("expected %s version %d, got %d", roleName, meta.Version, newDelegate.Signed.Version)} } // check expiration if newDelegate.Signed.IsExpired(trusted.RefTime) { - return nil, metadata.ErrExpiredMetadata{Msg: fmt.Sprintf("new %s is expired", roleName)} + return nil, &metadata.ErrExpiredMetadata{Msg: fmt.Sprintf("new %s is expired", roleName)} } trusted.Targets[roleName] = newDelegate log.Info("Updated role", "role", roleName, "version", trusted.Targets[roleName].Signed.Version) @@ -343,7 +343,7 @@ func (trusted *TrustedMetadata) loadTrustedRoot(rootData []byte) error { } // check metadata type matches root if newRoot.Signed.Type != metadata.ROOT { - return metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.ROOT, newRoot.Signed.Type)} + return &metadata.ErrRepository{Msg: fmt.Sprintf("expected %s, got %s", metadata.ROOT, newRoot.Signed.Type)} } // verify root by itself err = newRoot.VerifyDelegate(metadata.ROOT, newRoot) diff --git a/metadata/trustedmetadata/trustedmetadata_test.go b/metadata/trustedmetadata/trustedmetadata_test.go index aeb21e14..75d7d3b2 100644 --- a/metadata/trustedmetadata/trustedmetadata_test.go +++ b/metadata/trustedmetadata/trustedmetadata_test.go @@ -223,36 +223,36 @@ func TestOutOfOrderOps(t *testing.T) { // Update snapshot before timestamp _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot update snapshot before timestamp"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot update snapshot before timestamp"}) _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) assert.NoError(t, err) // Update root after timestamp _, err = trustedSet.UpdateRoot(allRoles[metadata.ROOT]) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot update root after timestamp"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot update root after timestamp"}) // Update targets before snapshot _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot load targets before snapshot"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot load targets before snapshot"}) _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) assert.NoError(t, err) // Update timestamp after snapshot _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot update timestamp after snapshot"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot update timestamp after snapshot"}) // Update delegated targets before targets _, err = trustedSet.UpdateDelegatedTargets(allRoles["role1"], "role1", metadata.TARGETS) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot load targets before delegator"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot load targets before delegator"}) _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) assert.NoError(t, err) // Update snapshot after sucessful targets update _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrRuntime{Msg: "cannot update snapshot after targets"}) + assert.ErrorIs(t, err, &metadata.ErrRuntime{Msg: "cannot update snapshot after targets"}) _, err = trustedSet.UpdateDelegatedTargets(allRoles["role1"], "role1", metadata.TARGETS) assert.NoError(t, err) @@ -275,11 +275,11 @@ func TestRootWithInvalidJson(t *testing.T) { rootBytes, err := root.ToBytes(true) assert.NoError(t, err) _, err = trustedSet.UpdateRoot(rootBytes) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) // metadata is of wrong type _, err = trustedSet.UpdateRoot(allRoles[metadata.SNAPSHOT]) - assert.ErrorIs(t, err, metadata.ErrValue{Msg: "expected metadata type root, got - snapshot"}) + assert.ErrorIs(t, err, &metadata.ErrValue{Msg: "expected metadata type root, got - snapshot"}) } func TestTopLevelMetadataWithInvalidJSON(t *testing.T) { @@ -300,11 +300,11 @@ func TestTopLevelMetadataWithInvalidJSON(t *testing.T) { timestampBytes, err := timestamp.ToBytes(true) assert.NoError(t, err) _, err = trustedSet.UpdateTimestamp(timestampBytes) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying timestamp failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying timestamp failed, not enough signatures, got 0, want 1"}) // timestamp is of wrong type _, err = trustedSet.UpdateTimestamp(allRoles[metadata.ROOT]) - assert.ErrorIs(t, err, metadata.ErrValue{Msg: "expected metadata type timestamp, got - root"}) + assert.ErrorIs(t, err, &metadata.ErrValue{Msg: "expected metadata type timestamp, got - root"}) // SNAPSHOT _, err = trustedSet.UpdateTimestamp(properTimestampBytes) @@ -322,11 +322,11 @@ func TestTopLevelMetadataWithInvalidJSON(t *testing.T) { snapshotBytes, err := snapshot.ToBytes(true) assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(snapshotBytes, false) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) // snapshot is of wrong type _, err = trustedSet.UpdateSnapshot(allRoles[metadata.ROOT], false) - assert.ErrorIs(t, err, metadata.ErrValue{Msg: "expected metadata type snapshot, got - root"}) + assert.ErrorIs(t, err, &metadata.ErrValue{Msg: "expected metadata type snapshot, got - root"}) // TARGETS _, err = trustedSet.UpdateSnapshot(properSnapshotBytes, false) @@ -342,11 +342,11 @@ func TestTopLevelMetadataWithInvalidJSON(t *testing.T) { targetsBytes, err := targets.ToBytes(true) assert.NoError(t, err) _, err = trustedSet.UpdateTargets(targetsBytes) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying targets failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying targets failed, not enough signatures, got 0, want 1"}) // targets is of wrong type _, err = trustedSet.UpdateTargets(allRoles[metadata.ROOT]) - assert.ErrorIs(t, err, metadata.ErrValue{Msg: "expected metadata type targets, got - root"}) + assert.ErrorIs(t, err, &metadata.ErrValue{Msg: "expected metadata type targets, got - root"}) } func TestUpdateRootNewRoot(t *testing.T) { @@ -376,7 +376,7 @@ func TestUpdateRootNewRootFailTreshholdVerification(t *testing.T) { trustedSet, err := New(allRoles[metadata.ROOT]) assert.NoError(t, err) _, err = trustedSet.UpdateRoot(root) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 1, want 2"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 1, want 2"}) } func TestUpdateRootNewRootVerSameAsTrustedRootVer(t *testing.T) { @@ -384,7 +384,7 @@ func TestUpdateRootNewRootVerSameAsTrustedRootVer(t *testing.T) { assert.NoError(t, err) _, err = trustedSet.UpdateRoot(allRoles[metadata.ROOT]) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 1"}) } func TestRootExpiredFinalRoot(t *testing.T) { @@ -401,7 +401,7 @@ func TestRootExpiredFinalRoot(t *testing.T) { // Update timestamp to trigger final root expiry check _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) } func TestUpdateTimestampNewTimestampVerBelowTrustedVer(t *testing.T) { @@ -417,7 +417,7 @@ func TestUpdateTimestampNewTimestampVerBelowTrustedVer(t *testing.T) { _, err = trustedSet.UpdateTimestamp(timestamp) assert.NoError(t, err) _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 3"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 3"}) } func TestUpdateTimestampWithSameTimestamp(t *testing.T) { @@ -432,7 +432,7 @@ func TestUpdateTimestampWithSameTimestamp(t *testing.T) { // Update timestamp with the same version. _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) // EqualVersionNumberError - assert.ErrorIs(t, err, metadata.ErrEqualVersionNumber{Msg: "new timestamp version 1 equals the old one 1"}) + assert.ErrorIs(t, err, &metadata.ErrEqualVersionNumber{Msg: "new timestamp version 1 equals the old one 1"}) // Verify that the timestamp object was not updated. assert.Equal(t, initialTimestamp, trustedSet.Timestamp) @@ -454,7 +454,7 @@ func TestUpdateTimestampSnapshotCerBellowCurrent(t *testing.T) { // new timestamp meta version < trusted timestamp meta version _, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP]) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) } func TestUpdateTimestampExpired(t *testing.T) { @@ -468,9 +468,9 @@ func TestUpdateTimestampExpired(t *testing.T) { trustedSet, err := New(allRoles[metadata.ROOT]) assert.NoError(t, err) _, err = trustedSet.UpdateTimestamp(timestamp) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) } func TestUpdateSnapshotLengthOrHashMismatch(t *testing.T) { @@ -485,7 +485,7 @@ func TestUpdateSnapshotLengthOrHashMismatch(t *testing.T) { _, err = trustedSet.UpdateTimestamp(timestamp) assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrLengthOrHashMismatch{Msg: "length verification failed - expected 1, got 652"}) + assert.ErrorIs(t, err, &metadata.ErrLengthOrHashMismatch{Msg: "length verification failed - expected 1, got 652"}) } func TestUpdateSnapshotFailThreshholdVerification(t *testing.T) { @@ -500,7 +500,7 @@ func TestUpdateSnapshotFailThreshholdVerification(t *testing.T) { snapshotBytes, err := snapshot.ToBytes(true) assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(snapshotBytes, false) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) } func TestUpdateSnapshotVersionDivergeTimestampSnapshotVersion(t *testing.T) { @@ -516,11 +516,11 @@ func TestUpdateSnapshotVersionDivergeTimestampSnapshotVersion(t *testing.T) { // If intermediate snapshot version is incorrect, load it but also raise _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) // Targets update starts but fails if snapshot version does not match _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) } // Update all metadata roles besides targets. @@ -554,7 +554,7 @@ func TestUpdateSnapshotFileRemovedFromMeta(t *testing.T) { snapshot, err := modifySnapshotMetadata(removeFileFromMeta) assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(snapshot, false) - assert.ErrorIs(t, err, metadata.ErrRepository{Msg: "new snapshot is missing info for targets.json"}) + assert.ErrorIs(t, err, &metadata.ErrRepository{Msg: "new snapshot is missing info for targets.json"}) } func TestUpdateSnapshotMetaVersionDecreases(t *testing.T) { @@ -572,7 +572,7 @@ func TestUpdateSnapshotMetaVersionDecreases(t *testing.T) { assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected targets.json version 1, got 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected targets.json version 1, got 2"}) } func TestUpdateSnapshotExpiredNewSnapshot(t *testing.T) { @@ -589,11 +589,11 @@ func TestUpdateSnapshotExpiredNewSnapshot(t *testing.T) { assert.NoError(t, err) _, err = trustedSet.UpdateSnapshot(snapshot, false) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) // Targets update does start but fails because snapshot is expired _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) } @@ -617,7 +617,7 @@ func TestUpdateSnapshotSuccessfulRollbackChecks(t *testing.T) { // Load a "local" snapshot with mismatching version (loading happens but // ErrBadVersionNumber is raised), then update to newer one: _, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected 2, got 1"}) bumpVersion := func(snapahot *metadata.Metadata[metadata.SnapshotType]) { snapahot.Signed.Version += 1 @@ -647,7 +647,7 @@ func TestUpdateTargetsMoMetaInSnapshot(t *testing.T) { // Remove meta information with information about targets from snapshot _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrRepository{Msg: "snapshot does not contain information for targets"}) + assert.ErrorIs(t, err, &metadata.ErrRepository{Msg: "snapshot does not contain information for targets"}) } @@ -669,7 +669,7 @@ func TestUpdateTargetsHashDiverfeFromSnapshotMetaHash(t *testing.T) { // Observed hash != stored hash in snapshot meta for targets _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrLengthOrHashMismatch{Msg: "length verification failed - expected 1, got 1266"}) + assert.ErrorIs(t, err, &metadata.ErrLengthOrHashMismatch{Msg: "length verification failed - expected 1, got 1266"}) } func TestUpdateTargetsVersionDivergeSnapshotMetaVersion(t *testing.T) { @@ -687,7 +687,7 @@ func TestUpdateTargetsVersionDivergeSnapshotMetaVersion(t *testing.T) { // New delegate sigfned version != meta version stored in snapshot _, err = trustedSet.UpdateTargets(allRoles[metadata.TARGETS]) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected targets version 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected targets version 2, got 1"}) } func TestUpdateTargetsExpiredMewTarget(t *testing.T) { @@ -703,5 +703,5 @@ func TestUpdateTargetsExpiredMewTarget(t *testing.T) { targets, err := modifyTargetsMetadata(modifyTargetExpiry) assert.NoError(t, err) _, err = trustedSet.UpdateTargets(targets) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "new targets is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "new targets is expired"}) } diff --git a/metadata/updater/updater.go b/metadata/updater/updater.go index 63169af5..2ce43162 100644 --- a/metadata/updater/updater.go +++ b/metadata/updater/updater.go @@ -218,7 +218,7 @@ func (update *Updater) DownloadTarget(targetFile *metadata.TargetFiles, filePath } if targetBaseURL == "" { if update.cfg.RemoteTargetsURL == "" { - return "", nil, metadata.ErrValue{Msg: "targetBaseURL must be set in either DownloadTarget() or the Updater struct"} + return "", nil, &metadata.ErrValue{Msg: "targetBaseURL must be set in either DownloadTarget() or the Updater struct"} } targetBaseURL = ensureTrailingSlash(update.cfg.RemoteTargetsURL) } else { @@ -308,7 +308,7 @@ func (update *Updater) loadTimestamp() error { // local timestamp exists, let's try to verify it and load it to the trusted metadata set _, err := update.trusted.UpdateTimestamp(data) if err != nil { - if errors.Is(err, metadata.ErrRepository{}) { + if errors.Is(err, &metadata.ErrRepository{}) { // local timestamp is not valid, proceed downloading from remote; note that this error type includes several other subset errors log.Info("Local timestamp is not valid") } else { @@ -327,7 +327,7 @@ func (update *Updater) loadTimestamp() error { // try to verify and load the newly downloaded timestamp _, err = update.trusted.UpdateTimestamp(data) if err != nil { - if errors.Is(err, metadata.ErrEqualVersionNumber{}) { + if errors.Is(err, &metadata.ErrEqualVersionNumber{}) { // if the new timestamp version is the same as current, discard the // new timestamp; this is normal and it shouldn't raise any error return nil @@ -357,7 +357,7 @@ func (update *Updater) loadSnapshot() error { _, err = update.trusted.UpdateSnapshot(data, true) if err != nil { // this means snapshot verification/loading failed - if errors.Is(err, metadata.ErrRepository{}) { + if errors.Is(err, &metadata.ErrRepository{}) { // local snapshot is not valid, proceed downloading from remote; note that this error type includes several other subset errors log.Info("Local snapshot is not valid") } else { @@ -423,7 +423,7 @@ func (update *Updater) loadTargets(roleName, parentName string) (*metadata.Metad delegatedTargets, err := update.trusted.UpdateDelegatedTargets(data, roleName, parentName) if err != nil { // this means targets verification/loading failed - if errors.Is(err, metadata.ErrRepository{}) { + if errors.Is(err, &metadata.ErrRepository{}) { // local target file is not valid, proceed downloading from remote; note that this error type includes several other subset errors log.Info("Local role is not valid", "role", roleName) } else { @@ -484,7 +484,7 @@ func (update *Updater) loadRoot() error { data, err := update.downloadMetadata(metadata.ROOT, update.cfg.RootMaxLength, strconv.FormatInt(nextVersion, 10)) if err != nil { // downloading the root metadata failed for some reason - var tmpErr metadata.ErrDownloadHTTP + var tmpErr *metadata.ErrDownloadHTTP if errors.As(err, &tmpErr) { if tmpErr.StatusCode != http.StatusNotFound && tmpErr.StatusCode != http.StatusForbidden { // unexpected HTTP status code @@ -674,7 +674,7 @@ func (update *Updater) downloadMetadata(roleName string, length int64, version s func (update *Updater) generateTargetFilePath(tf *metadata.TargetFiles) (string, error) { // LocalTargetsDir can be omitted if caching is disabled if update.cfg.LocalTargetsDir == "" && !update.cfg.DisableLocalCache { - return "", metadata.ErrValue{Msg: "LocalTargetsDir must be set if filepath is not given"} + return "", &metadata.ErrValue{Msg: "LocalTargetsDir must be set if filepath is not given"} } // Use URL encoded target path as filename return url.JoinPath(update.cfg.LocalTargetsDir, url.QueryEscape(tf.Path)) diff --git a/metadata/updater/updater_top_level_update_test.go b/metadata/updater/updater_top_level_update_test.go index 598630ba..e1dde93b 100644 --- a/metadata/updater/updater_top_level_update_test.go +++ b/metadata/updater/updater_top_level_update_test.go @@ -329,7 +329,7 @@ func TestTrustedRootExpired(t *testing.T) { assert.NoError(t, err) updater := initUpdater(updaterConfig) err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) assertFilesExist(t, []string{metadata.ROOT}) version := 2 @@ -368,7 +368,7 @@ func TestTrustedRootUnsigned(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) assertFilesExist(t, []string{metadata.ROOT}) mdRootAfter, err := simulator.Sim.MDRoot.FromFile(rootPath) @@ -423,7 +423,7 @@ func TestIntermediateRootInclorrectlySigned(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 0, want 1"}) assertFilesExist(t, []string{metadata.ROOT}) version := 1 @@ -469,7 +469,7 @@ func TestNewRootSameVersion(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 1"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 1"}) // The update failed, latest root version is v1 assertFilesExist(t, []string{metadata.ROOT}) @@ -488,7 +488,7 @@ func TestNewRootNonconsecutiveVersion(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 3"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 3"}) // The update failed, latest root version is v1 assertFilesExist(t, []string{metadata.ROOT}) @@ -509,7 +509,7 @@ func TestFinalRootExpired(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "final root.json is expired"}) // The update failed but final root is persisted on the file system assertFilesExist(t, []string{metadata.ROOT}) @@ -527,7 +527,7 @@ func TestNewTimestampUnsigned(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying timestamp failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying timestamp failed, not enough signatures, got 0, want 1"}) assertFilesExist(t, []string{metadata.ROOT}) } @@ -563,7 +563,7 @@ func TestExpiredTimestampVersionRollback(t *testing.T) { // local timestamp has expired moveInTime := time.Now().Add(time.Hour * 18 * 24) _, err = runRefresh(updaterConfig, moveInTime) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) assertVersionEquals(t, metadata.TIMESTAMP, 2) } @@ -580,7 +580,7 @@ func TestNewTimestampVersionRollback(t *testing.T) { simulator.Sim.MDTimestamp.Signed.Version = 1 _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new timestamp version 1 must be >= 2"}) assertVersionEquals(t, metadata.TIMESTAMP, 2) } @@ -600,7 +600,7 @@ func TestNewTimestampSnapshotRollback(t *testing.T) { simulator.Sim.MDTimestamp.Signed.Meta["snapshot.json"].Version = 1 simulator.Sim.MDTimestamp.Signed.Version += 1 // timestamp v3 _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new snapshot version 1 must be >= 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new snapshot version 1 must be >= 2"}) assertVersionEquals(t, metadata.TIMESTAMP, 2) } @@ -614,7 +614,7 @@ func TestNewTimestampExpired(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"}) assertFilesExist(t, []string{metadata.ROOT}) } @@ -675,7 +675,7 @@ func TestNewSnapshotHashMismatch(t *testing.T) { // Hash mismatch error _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrLengthOrHashMismatch{Msg: "hash verification failed - mismatch for algorithm sha256"}) + assert.ErrorIs(t, err, &metadata.ErrLengthOrHashMismatch{Msg: "hash verification failed - mismatch for algorithm sha256"}) assertVersionEquals(t, metadata.TIMESTAMP, 3) assertVersionEquals(t, metadata.SNAPSHOT, 1) } @@ -689,7 +689,7 @@ func TestNewSnapshotUnsigned(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying snapshot failed, not enough signatures, got 0, want 1"}) assertFilesExist(t, []string{metadata.ROOT, metadata.TIMESTAMP}) } @@ -706,7 +706,7 @@ func TestNewSnapshotVersionMismatch(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected 1, got 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected 1, got 2"}) assertFilesExist(t, []string{metadata.ROOT, metadata.TIMESTAMP}) } @@ -726,7 +726,7 @@ func TestNewSnapshotVersionRollback(t *testing.T) { simulator.Sim.MDSnapshot.Signed.Version = 1 simulator.Sim.UpdateTimestamp() _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "new snapshot version 1 must be >= 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "new snapshot version 1 must be >= 2"}) assertVersionEquals(t, metadata.SNAPSHOT, 2) } @@ -782,7 +782,7 @@ func TestNewSnapshotExpired(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "snapshot.json is expired"}) assertFilesExist(t, []string{metadata.ROOT}) } @@ -807,7 +807,7 @@ func TestNewTargetsHashMismatch(t *testing.T) { simulator.Sim.UpdateTimestamp() _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrLengthOrHashMismatch{Msg: "hash verification failed - mismatch for algorithm sha256"}) + assert.ErrorIs(t, err, &metadata.ErrLengthOrHashMismatch{Msg: "hash verification failed - mismatch for algorithm sha256"}) assertVersionEquals(t, metadata.SNAPSHOT, 3) assertVersionEquals(t, metadata.TARGETS, 1) @@ -823,7 +823,7 @@ func TestNewTargetsUnsigned(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrUnsignedMetadata{Msg: "Verifying targets failed, not enough signatures, got 0, want 1"}) + assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying targets failed, not enough signatures, got 0, want 1"}) assertFilesExist(t, []string{metadata.ROOT, metadata.TIMESTAMP, metadata.SNAPSHOT}) } @@ -839,7 +839,7 @@ func TestNewTargetsVersionMismatch(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected targets version 1, got 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected targets version 1, got 2"}) assertFilesExist(t, []string{metadata.ROOT, metadata.TIMESTAMP, metadata.SNAPSHOT}) } @@ -855,7 +855,7 @@ func TestNewTargetsExpired(t *testing.T) { updaterConfig, err := loadUpdaterConfig() assert.NoError(t, err) _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrExpiredMetadata{Msg: "new targets is expired"}) + assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "new targets is expired"}) assertFilesExist(t, []string{metadata.ROOT, metadata.TIMESTAMP, metadata.SNAPSHOT}) } @@ -957,7 +957,7 @@ func TestSnapshotRollbackWithLocalSnapshotHashMismatch(t *testing.T) { // Should fail as a new version of snapshot will be fetched which lowers // the snapshot meta "targets.json" version by 1 and throws an error. _, err = runRefresh(updaterConfig, time.Now()) - assert.ErrorIs(t, err, metadata.ErrBadVersionNumber{Msg: "expected targets.json version 1, got 2"}) + assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "expected targets.json version 1, got 2"}) } func TestExpiredMetadata(t *testing.T) { @@ -1027,27 +1027,27 @@ func TestMaxMetadataLengths(t *testing.T) { updater := initUpdater(updaterConfig) updater.cfg.RootMaxLength = 100 err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) + assert.ErrorIs(t, err, &metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) updater = initUpdater(updaterConfig) updater.cfg.TimestampMaxLength = 100 err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) + assert.ErrorIs(t, err, &metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) updater = initUpdater(updaterConfig) updater.cfg.SnapshotMaxLength = 100 err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) + assert.ErrorIs(t, err, &metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) updater = initUpdater(updaterConfig) updater.cfg.TargetsMaxLength = 100 err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) + assert.ErrorIs(t, err, &metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) // All good with normal length limits updater = initUpdater(updaterConfig) err = updater.Refresh() - assert.ErrorIs(t, err, metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) + assert.ErrorIs(t, err, &metadata.ErrDownloadLengthMismatch{Msg: "Downloaded 1567 bytes exceeding the maximum allowed length of 100"}) } func TestTimestampEqVersionsCheck(t *testing.T) { diff --git a/testutils/simulator/repository_simulator.go b/testutils/simulator/repository_simulator.go index 926b8741..76654e5e 100644 --- a/testutils/simulator/repository_simulator.go +++ b/testutils/simulator/repository_simulator.go @@ -308,7 +308,7 @@ func (rs *RepositorySimulator) DownloadFile(urlPath string, maxLength int64, tim return data, err } if len(data) > int(maxLength) { - err = metadata.ErrDownloadLengthMismatch{ + err = &metadata.ErrDownloadLengthMismatch{ Msg: fmt.Sprintf("Downloaded %d bytes exceeding the maximum allowed length of %d", len(data), maxLength), } } @@ -418,7 +418,7 @@ func (rs *RepositorySimulator) FetchMetadata(role string, version *int) ([]byte, // Return a version previously serialized in PublishRoot() if version == nil || *version > len(rs.SignedRoots) && *version > 0 { log.Printf("unknown root version %d", *version) - return []byte{}, metadata.ErrDownloadHTTP{StatusCode: 404} + return []byte{}, &metadata.ErrDownloadHTTP{StatusCode: 404} } log.Printf("fetched root version %d", version) return rs.SignedRoots[*version-1], nil @@ -435,7 +435,7 @@ func (rs *RepositorySimulator) FetchMetadata(role string, version *int) ([]byte, md, ok := rs.MDDelegates[role] if !ok { log.Printf("unknown role %s", role) - return []byte{}, metadata.ErrDownloadHTTP{StatusCode: 404} + return []byte{}, &metadata.ErrDownloadHTTP{StatusCode: 404} } return signMetadata(role, &md, rs) }