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

Implementing DeepCopy and DeepCopyInto interface for VEX #69

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
99 changes: 99 additions & 0 deletions pkg/vex/statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,103 @@ func (stmt *Statement) MarshalJSON() ([]byte, error) {
TimeZonedTimestamp: ts,
TimeZonedLastUpdated: lu,
})

// DeepCopyInto copies the receiver and writes its value into out.
func (stmt *Statement) DeepCopyInto(out *Statement) {
*out = *stmt

if stmt.Timestamp != nil {
*out = *stmt
out.Timestamp = new(time.Time)
*out.Timestamp = *stmt.Timestamp
}

if stmt.LastUpdated != nil {
*out = *stmt
out.LastUpdated = new(time.Time)
*out.LastUpdated = *stmt.LastUpdated
}

if stmt.Products != nil {
*out = *stmt
out.Products = make([]Product, len(stmt.Products))
copy(out.Products, stmt.Products)
}

*out = *stmt
out.Vulnerability = Vulnerability{}
stmt.Vulnerability.DeepCopyInto(&out.Vulnerability)

if stmt.Justification != "" {
*out = *stmt
out.Justification = stmt.Justification
}

if stmt.ActionStatementTimestamp != nil {
*out = *stmt
out.ActionStatementTimestamp = new(time.Time)
*out.ActionStatementTimestamp = *stmt.ActionStatementTimestamp
}

return
}

// DeepCopy copies the receiver and returns a new Statement.
func (stmt *Statement) DeepCopy() *Statement {
if stmt == nil {
return nil
}
out := new(Statement)
stmt.DeepCopyInto(out)
return out
}

// DeepCopyInto copies the receiver and writes its value into out.
func (stmt *Statement) DeepCopyInto(out *Statement) {
*out = *stmt

if stmt.Timestamp != nil {
*out = *stmt
out.Timestamp = new(time.Time)
*out.Timestamp = *stmt.Timestamp
}

if stmt.LastUpdated != nil {
*out = *stmt
out.LastUpdated = new(time.Time)
*out.LastUpdated = *stmt.LastUpdated
}

if stmt.Products != nil {
*out = *stmt
out.Products = make([]Product, len(stmt.Products))
copy(out.Products, stmt.Products)
}

*out = *stmt
out.Vulnerability = Vulnerability{}
stmt.Vulnerability.DeepCopyInto(&out.Vulnerability)

if stmt.Justification != "" {
*out = *stmt
out.Justification = stmt.Justification
}

if stmt.ActionStatementTimestamp != nil {
*out = *stmt
out.ActionStatementTimestamp = new(time.Time)
*out.ActionStatementTimestamp = *stmt.ActionStatementTimestamp
}

return
}

// DeepCopy copies the receiver and returns a new Statement.
func (stmt *Statement) DeepCopy() *Statement {
if stmt == nil {
return nil
}
out := new(Statement)
stmt.DeepCopyInto(out)
return out
}
20 changes: 20 additions & 0 deletions pkg/vex/vex.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,23 @@ func (vexDoc *VEX) StatementsByVulnerability(id string) []Statement {
SortStatements(ret, *vexDoc.Timestamp)
return ret
}

// DeepCopy returns a deep copy of the VEX document.
func (vexDoc *VEX) DeepCopy() *VEX {
if vexDoc == nil {
return nil
}
out := new(VEX)
vexDoc.DeepCopyInto(out)
return out
}

// DeepCopyInto copies the receiver and writes its value into out.
func (vexDoc *VEX) DeepCopyInto(out *VEX) {
*out = *vexDoc
out.Metadata = vexDoc.Metadata
out.Statements = []Statement{}
for _, s := range vexDoc.Statements {
out.Statements = append(out.Statements, *s.DeepCopy())
}
}
43 changes: 43 additions & 0 deletions pkg/vex/vex_struckts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
type VEX struct {
Metadata
Statements []Statement `json:"statements"`
}

// The Metadata type represents the metadata associated with a VEX document.
type Metadata struct {
// Context is the URL pointing to the jsonld context definition
Context string `json:"@context"`

// ID is the identifying string for the VEX document. This should be unique per
// document.
ID string `json:"@id"`

// Author is the identifier for the author of the VEX statement, ideally a common
// name, may be a URI. [author] is an individual or organization. [author]
// identity SHOULD be cryptographically associated with the signature of the VEX
// statement or document or transport.
Author string `json:"author"`

// AuthorRole describes the role of the document Author.
AuthorRole string `json:"role,omitempty"`

// Timestamp defines the time at which the document was issued.
Timestamp *time.Time `json:"timestamp"`

// LastUpdated marks the time when the document had its last update. When the
// document changes both version and this field should be updated.
LastUpdated *time.Time `json:"last_updated,omitempty"`

// Version is the document version. It must be incremented when any content
// within the VEX document changes, including any VEX statements included within
// the VEX document.
Version int `json:"version"`

// Tooling expresses how the VEX document and contained VEX statements were
// generated. It's optional. It may specify tools or automated processes used in
// the document or statement generation.
Tooling string `json:"tooling,omitempty"`

// Supplier is an optional field.
Supplier string `json:"supplier,omitempty"`
}
21 changes: 21 additions & 0 deletions pkg/vex/vex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,3 +371,24 @@ func TestParseContext(t *testing.T) {
require.Equal(t, res, tc.expected, tCase)
}
}

func TestDeepCopyOfVex(t *testing.T) {
vex := genTestDoc(t)

// Make a copy of the vex document
vexCopy := vex.DeepCopy()

// Compare the two documents
require.Equal(t, vex, *vexCopy)

// Change the copy
vexCopy.ID = "new ID"
require.NotEqual(t, vex, *vexCopy)

// Change the original
originalAlias := vex.Statements[0].Vulnerability.Aliases[0]
vex.Statements[0].Vulnerability.Aliases[0] = VulnerabilityID("new alias")
require.NotEqual(t, vex, *vexCopy)
require.Equal(t, originalAlias, vexCopy.Statements[0].Vulnerability.Aliases[0])

}
23 changes: 23 additions & 0 deletions pkg/vex/vulnerability.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,26 @@ func (v *Vulnerability) Matches(identifier string) bool {
}
return false
}

// DeepCopyInto for Vulnerability performs a deep copy of the Vulnerability
// struct, writing to out. in must be non-nil.
func (in *Vulnerability) DeepCopyInto(out *Vulnerability) {
*out = *in
out.Name = in.Name
out.Description = in.Description
if in.Aliases != nil {
out.Aliases = make([]VulnerabilityID, len(in.Aliases))
copy(out.Aliases, in.Aliases)
}
}

// DeepCopy for Vulnerability performs a deep copy of the Vulnerability struct,
// returning a new Vulnerability struct pointer.
func (in *Vulnerability) DeepCopy() *Vulnerability {
if in == nil {
return nil
}
out := new(Vulnerability)
in.DeepCopyInto(out)
return out
}