Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
37 changes: 36 additions & 1 deletion evidence.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

package swid

import "time"
import (
"errors"
"fmt"
"time"
)

// Evidence models a evidence-entry
type Evidence struct {
Expand Down Expand Up @@ -53,3 +57,34 @@ func (e *Evidence) AddProcess(p Process) error {

return nil
}

// Valid validates the Evidence receiver to ensure it has valid required fields
func (e Evidence) Valid() error {
if e.DeviceID == "" {
return errors.New("evidence device-id is empty")
}

if e.Date.IsZero() {
return errors.New("evidence date is zero")
}

// Validate Files if present
Copy link
Contributor

@yogeshbdeshpande yogeshbdeshpande Sep 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The correct implementation is to invoke Method Valid() on the File Object and let File Object, in the file file.go to implement the Valid Method that can be invoked from line 71. In the Valid for file, check for validity of Mandatory (like FsName) and check for presence of optional elements in the file object. If Optional Elements are present, then please check their validity!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure sir checking it @yogeshbdeshpande

if e.Files != nil {
for i, file := range *e.Files {
if err := file.Valid(); err != nil {
return fmt.Errorf("evidence file[%d] invalid: %w", i, err)
}
}
}

// Validate Processes if present
if e.Processes != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for process, may be we are ok to check here as there is not much to check for validity of the process elements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok sir

for i, process := range *e.Processes {
if process.ProcessName == "" {
return fmt.Errorf("evidence process[%d] process-name is empty", i)
}
}
}

return nil
}
168 changes: 168 additions & 0 deletions evidence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,171 @@ func TestEvidence_Roundtrip(t *testing.T) {
assert.Equal(t, tv.Date.UTC(), actual.Date.UTC()) // compare as UTC
assert.Equal(t, tv.DeviceID, actual.DeviceID)
}

func TestEvidence_Valid_empty_device_id(t *testing.T) {
evidence := Evidence{
DeviceID: "",
Date: time.Now(),
}

err := evidence.Valid()

assert.EqualError(t, err, "evidence device-id is empty")
}

func TestEvidence_Valid_zero_date(t *testing.T) {
evidence := Evidence{
DeviceID: "test-device",
Date: time.Time{},
}

err := evidence.Valid()

assert.EqualError(t, err, "evidence date is zero")
}

func TestEvidence_Valid_simple_valid(t *testing.T) {
evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
}

err := evidence.Valid()

assert.NoError(t, err)
}

func TestEvidence_Valid_with_valid_files(t *testing.T) {
files := Files{
File{
FileSystemItem: FileSystemItem{
FsName: "test.exe",
},
},
File{
FileSystemItem: FileSystemItem{
FsName: "config.ini",
},
},
}

evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
ResourceCollection: ResourceCollection{
PathElements: PathElements{
Files: &files,
},
},
}

err := evidence.Valid()

assert.NoError(t, err)
}

func TestEvidence_Valid_with_invalid_files(t *testing.T) {
files := Files{
File{
FileSystemItem: FileSystemItem{
FsName: "test.exe",
},
},
File{
FileSystemItem: FileSystemItem{
FsName: "", // empty fs-name
},
},
}

evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
ResourceCollection: ResourceCollection{
PathElements: PathElements{
Files: &files,
},
},
}

err := evidence.Valid()

assert.EqualError(t, err, "evidence file[1] invalid: file fs-name is empty")
}

func TestEvidence_Valid_with_valid_processes(t *testing.T) {
processes := Processes{
Process{
ProcessName: "test.exe",
},
Process{
ProcessName: "service.exe",
},
}

evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
ResourceCollection: ResourceCollection{
Processes: &processes,
},
}

err := evidence.Valid()

assert.NoError(t, err)
}

func TestEvidence_Valid_with_invalid_processes(t *testing.T) {
processes := Processes{
Process{
ProcessName: "test.exe",
},
Process{
ProcessName: "", // empty process name
},
}

evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
ResourceCollection: ResourceCollection{
Processes: &processes,
},
}

err := evidence.Valid()

assert.EqualError(t, err, "evidence process[1] process-name is empty")
}

func TestEvidence_Valid_with_mixed_valid_resources(t *testing.T) {
files := Files{
File{
FileSystemItem: FileSystemItem{
FsName: "test.exe",
},
},
}

processes := Processes{
Process{
ProcessName: "service.exe",
},
}

evidence := Evidence{
DeviceID: "test-device",
Date: time.Now(),
ResourceCollection: ResourceCollection{
PathElements: PathElements{
Files: &files,
},
Processes: &processes,
},
}

err := evidence.Valid()

assert.NoError(t, err)
}
83 changes: 83 additions & 0 deletions example_validation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2020 Contributors to the Veraison project.
Copy link
Contributor

@yogeshbdeshpande yogeshbdeshpande Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Copyright 2020 Contributors to the Veraison project.
// Copyright 2020-2025 Contributors to the Veraison project.

// SPDX-License-Identifier: Apache-2.0

package swid

import (
"fmt"
"time"

"github.com/google/uuid"
)

func ExampleTagID_Valid() {
// Valid string TagID
validStringTagID := TagID{val: "com.acme.product-v1.0.0"}
if err := validStringTagID.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println("String TagID is valid")
}

// Valid UUID TagID
validUUIDTagID := TagID{val: uuid.MustParse("550e8400-e29b-41d4-a716-446655440000")}
if err := validUUIDTagID.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println("UUID TagID is valid")
}

// Invalid empty string TagID
emptyStringTagID := TagID{val: ""}
if err := emptyStringTagID.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
}

// Invalid nil TagID
nilTagID := TagID{val: nil}
if err := nilTagID.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
}

// Output:
// String TagID is valid
// UUID TagID is valid
// Error: tag-id string value is empty
// Error: tag-id value is nil
}

func ExampleEvidence_Valid() {
// Valid Evidence
validEvidence := Evidence{
DeviceID: "device-001",
Date: time.Now(),
}
if err := validEvidence.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
} else {
fmt.Println("Evidence is valid")
}

// Invalid Evidence - empty DeviceID
invalidEvidence1 := Evidence{
DeviceID: "",
Date: time.Now(),
}
if err := invalidEvidence1.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
}

// Invalid Evidence - zero Date
invalidEvidence2 := Evidence{
DeviceID: "device-001",
Date: time.Time{},
}
if err := invalidEvidence2.Valid(); err != nil {
fmt.Printf("Error: %v\n", err)
}

// Output:
// Evidence is valid
// Error: evidence device-id is empty
// Error: evidence date is zero
}
24 changes: 24 additions & 0 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

package swid

import "errors"

// File models CoSWID file-entry
type File struct {
GlobalAttributes
Expand All @@ -23,3 +25,25 @@ type File struct {
// match, the the file has not been modified in any fashion.
Hash *HashEntry `cbor:"7,keyasint,omitempty" json:"hash,omitempty" xml:"hash,attr,omitempty"`
}

// Valid validates the File receiver to ensure it has valid required and optional fields
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks very good to me! Thanks for incorporating feedback!

func (f File) Valid() error {
// Check mandatory fields
if f.FsName == "" {
return errors.New("file fs-name is empty")
}

// Validate optional elements if present
if f.Hash != nil {
if err := ValidHashEntry(f.Hash.HashAlgID, f.Hash.HashValue); err != nil {
return err
}
}

// Size validation - if present, should be non-negative
if f.Size != nil && *f.Size < 0 {
return errors.New("file size cannot be negative")
}

return nil
}
Loading