Skip to content

Commit

Permalink
oval: add+use custom Date type
Browse files Browse the repository at this point in the history
Signed-off-by: Hank Donnay <[email protected]>
  • Loading branch information
hdonnay committed Apr 27, 2020
1 parent cf64532 commit f0d8695
Show file tree
Hide file tree
Showing 6 changed files with 934,407 additions and 11 deletions.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/quay/goval-parser

go 1.13

require golang.org/x/tools v0.0.0-20190924052046-3ac2a5bbd98a
require (
github.com/google/go-cmp v0.4.0
golang.org/x/tools v0.0.0-20190924052046-3ac2a5bbd98a
)
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -6,3 +8,4 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190924052046-3ac2a5bbd98a h1:DJzZ1GRmbjp7ihxzAN6UTVpVMi6k4CXZEr7A3wi2kRA=
golang.org/x/tools v0.0.0-20190924052046-3ac2a5bbd98a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
126 changes: 126 additions & 0 deletions oval/date_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package oval

import (
"encoding/xml"
"os"
"testing"
"time"

"github.com/google/go-cmp/cmp"
)

func TestAdvisoryDates(t *testing.T) {
var tt = []struct{ Updated, Issued time.Time }{
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 7, 0, 0, 0, 0, time.UTC)},
//
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
{time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 13, 0, 0, 0, 0, time.UTC)},
//
{time.Date(2019, time.Month(5), 14, 0, 0, 0, 0, time.UTC), time.Date(2019, time.Month(5), 14, 0, 0, 0, 0, time.UTC)},
}

f, err := os.Open("../testdata/com.redhat.rhsa-RHEL8.xml")
if err != nil {
t.Fatal(err)
}
defer f.Close()

var root Root
if err := xml.NewDecoder(f).Decode(&root); err != nil {
t.Fatal(err)
}
for i, tc := range tt {
def := &root.Definitions.Definitions[i]
a := def.Advisory
if got, want := a.Updated.Date, tc.Updated; !cmp.Equal(got, want) {
t.Errorf("def #%d: %s: Updated\n%v", i, def.Title, cmp.Diff(got, want))
}
if got, want := a.Issued.Date, tc.Issued; !cmp.Equal(got, want) {
t.Errorf("def #%d: %s: Issued\n%v", i, def.Title, cmp.Diff(got, want))
}
}
}

func TestDebianDates(t *testing.T) {
var tt = []time.Time{
time.Date(2004, time.Month(10), 29, 0, 0, 0, 0, time.UTC),
time.Date(2003, time.Month(6), 6, 0, 0, 0, 0, time.UTC),
time.Date(2005, time.Month(2), 2, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2020, time.Month(4), 24, 0, 0, 0, 0, time.UTC),
time.Date(2001, time.Month(7), 11, 0, 0, 0, 0, time.UTC),
time.Date(2001, time.Month(8), 9, 0, 0, 0, 0, time.UTC),
}

f, err := os.Open("../testdata/oval-definitions-buster.xml")
if err != nil {
t.Fatal(err)
}
defer f.Close()

var root Root
if err := xml.NewDecoder(f).Decode(&root); err != nil {
t.Fatal(err)
}
for i, tc := range tt {
def := &root.Definitions.Definitions[i]
a := def.Debian
if got, want := a.Date.Date, tc; !cmp.Equal(got, want) {
t.Errorf("def #%d: %s:\n%v", i, def.Title, cmp.Diff(got, want))
}
}
}

func TestUbuntuDates(t *testing.T) {
var tt = []time.Time{
time.Time{}, // First entry has no date attached.
time.Date(2015, time.Month(2), 23, 0, 0, 0, 0, time.UTC),
time.Date(2007, time.Month(1), 16, 23, 28, 0, 0, time.UTC),
time.Date(2007, time.Month(9), 26, 23, 17, 0, 0, time.UTC),
time.Date(2008, time.Month(11), 18, 16, 0, 0, 0, time.UTC),
time.Date(2008, time.Month(11), 18, 16, 0, 0, 0, time.UTC),
time.Date(2008, time.Month(11), 18, 16, 0, 0, 0, time.UTC),
time.Date(2008, time.Month(11), 18, 16, 0, 0, 0, time.UTC),
time.Date(2018, time.Month(11), 18, 19, 29, 0, 0, time.UTC),
time.Date(2009, time.Month(4), 23, 19, 30, 0, 0, time.UTC),
}

f, err := os.Open("../testdata/com.ubuntu.bionic.cve.oval.xml")
if err != nil {
t.Fatal(err)
}
defer f.Close()

var root Root
if err := xml.NewDecoder(f).Decode(&root); err != nil {
t.Fatal(err)
}
for i, tc := range tt {
def := &root.Definitions.Definitions[i]
a := def.Advisory
if got, want := a.PublicDate.Date, tc; !cmp.Equal(got, want) {
t.Errorf("def #%d: %s:\n%v", i, def.Title, cmp.Diff(got, want))
}
}
}
81 changes: 71 additions & 10 deletions oval/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/xml"
"fmt"
"sync"
"time"
)

// ErrNotFound is returned by Lookup methods when the specified identifier is
Expand Down Expand Up @@ -92,15 +93,75 @@ type Advisory struct {
Cves []Cve `xml:"cve"`
Bugzillas []Bugzilla `xml:"bugzilla"`
AffectedCPEList []string `xml:"affected_cpe_list>cpe"`
Refs []Ref `xml:"ref"` // Ubuntu Only
Bugs []Bug `xml:"bug"` // Ubuntu Only
PublicDate string `xml:"public_date"` // Ubuntu Only
Issued struct {
Date string `xml:"date,attr"`
} `xml:"issued"`
Updated struct {
Date string `xml:"date,attr"`
} `xml:"updated"`
Refs []Ref `xml:"ref"` // Ubuntu Only
Bugs []Bug `xml:"bug"` // Ubuntu Only
PublicDate Date `xml:"public_date"`
Issued Date `xml:"issued"`
Updated Date `xml:"updated"`
}

// Date is a wrapper type for decoding a range of date, datestamp, and timestamp
// strings seen in the wild.
//
// Currently, it will only examine attributes with the key "date".
type Date struct {
Date time.Time
}

var (
_ xml.Unmarshaler = (*Date)(nil)
_ xml.UnmarshalerAttr = (*Date)(nil)
)

// UnmarshalXML implements xml.Unmarshaler.
func (d *Date) UnmarshalXML(dec *xml.Decoder, start xml.StartElement) error {
// Attempt attrs first:
for _, a := range start.Attr {
if err := d.UnmarshalXMLAttr(a); err == nil {
break
}
}
// Attempt the inner node:
var s string
if err := dec.DecodeElement(&s, &start); err != nil {
return err
}
// If the date is set but an empty string is the inner element, then the
// date was set by an attr.
if s == "" && !d.Date.IsZero() {
return nil
}
var err error
// Try a variety of formats, because everything is terrible.
for _, f := range []string{
"2006-01-02", // Debian-style YYYY-MM-DD
"2006-01-02 15:04:05 MST", // Ubuntu style YYYY-MM-DD time zone
time.RFC1123, // The rest of these seem like someone might use them.
time.RFC1123Z,
time.RFC3339,
time.RFC3339Nano,
} {
d.Date, err = time.Parse(f, s)
if err == nil {
return nil
}
}
return fmt.Errorf("unable to decode string as datestamp: %q", s)
}

// UnmarshalXMLAttr implements xml.UnmarshalerAttr.
func (d *Date) UnmarshalXMLAttr(attr xml.Attr) error {
const dsfmt = `2006-01-02`
var name = xml.Name{Local: `date`}
if attr.Name.Local != name.Local {
return xml.UnmarshalError(fmt.Sprintf("unexpected attr : %v", attr))
}
var err error
d.Date, err = time.Parse(dsfmt, attr.Value)
if err != nil {
return err
}
return nil
}

// Ref : >definitions>definition>metadata>advisory>ref
Expand Down Expand Up @@ -143,7 +204,7 @@ type Bugzilla struct {
type Debian struct {
XMLName xml.Name `xml:"debian"`
MoreInfo string `xml:"moreinfo"`
Date string `xml:"date"`
Date Date `xml:"date"`
}

// Tests : >tests
Expand Down
Loading

0 comments on commit f0d8695

Please sign in to comment.