Skip to content

Commit

Permalink
Implemented OpenVEX (guacsec#1241)
Browse files Browse the repository at this point in the history
* Implemented OpenVEX

- Implemented the parser for OpenVEX
- Implemented the tests for the parser

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Fixed conflicts

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included Processor

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included Part for Each Product to Have a Package

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included OpenVEX as a Supported Input Format

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Fixed lint

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included Copyright

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included tests for Affected Case

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Updated based on code review

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Removed TODO for vex version

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Appending to identifierStrings, and updated tests

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Removed unnessesary error

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Updated based on code review

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Moved code from GetPredicates to Parse so it can return an error

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Updated vex Statuses and Justifications to use enums

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

* Included Enums for Justifications and Statuses

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>

---------

Signed-off-by: nathannaveen <42319948+nathannaveen@users.noreply.github.com>
  • Loading branch information
nathannaveen authored Sep 19, 2023
1 parent dc2f4d2 commit 861288d
Show file tree
Hide file tree
Showing 11 changed files with 767 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ refer to [how GUAC works](https://docs.guac.sh/how-guac-works/).
- [SLSA](https://github.com/slsa-framework/slsa)
- [SPDX](https://spdx.dev/specifications/)
- [CSAF/CSAF VEX](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html)
- [OpenVEX](https://github.com/openvex)

Note that GUAC uses software identifiers standards to help link metadata
together. However, these identifiers are not always available and heuristics
Expand Down
19 changes: 19 additions & 0 deletions internal/testing/testdata/exampledata/open-vex-affected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"@context": "",
"@id": "merged-vex-67124ea942ef30e1f42f3f2bf405fbbc4f5a56e6e87684fc5cd957212fa3e025",
"author": "Unknown Author",
"role": "Document Creator",
"timestamp": "2023-01-19T02:36:03.290252574-06:00",
"version": "",
"statements": [
{
"vulnerability": "CVE-1234-5678",
"timestamp": "2022-12-22T20:56:05-05:00",
"products": [
"pkg:apk/wolfi/bash@1.0.0"
],
"status": "affected",
"action_statement": "This is a test action statement"
}
]
}
23 changes: 23 additions & 0 deletions internal/testing/testdata/exampledata/open-vex-not-affected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"@context": "https://openvex.dev/ns",
"@id": "https://openvex.dev/docs/public/vex-a06f9de1ad1b1e555a33b2d0c1e7e6ecc4dc1800ff457c61ea09d8e97670d2a3",
"author": "Wolfi J. Inkinson",
"role": "Senior VEXing Engineer",
"timestamp": "2023-01-09T21:23:03.579712389-06:00",
"version": "1",
"statements": [
{
"vulnerability": "CVE-2023-12345",
"products": [
"pkg:oci/git@sha256:23a264e6e429852221a963e9f17338ba3f5796dc7086e46439a6f4482cf6e0cb"
],
"subcomponents": [
"pkg:apk/alpine/git@2.38.1-r0?arch=x86_64",
"pkg:apk/alpine/git@2.38.1-r0?arch=ppc64le"
],
"status": "not_affected",
"justification": "inline_mitigations_already_exist",
"impact_statement": "Included git is mitigated against CVE-2023-12345 !"
}
]
}
74 changes: 74 additions & 0 deletions internal/testing/testdata/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -2143,6 +2143,80 @@ var (
"UpdateTime":"2022-11-21T17:45:50.52Z"
}`

// OpenVEX

//go:embed exampledata/open-vex-not-affected.json
NotAffectedOpenVEXExample []byte

NotAffectedOpenVexIngest = []assembler.VexIngest{
{
Pkg: &generated.PkgInputSpec{
Name: "git",
Version: strP("sha256:23a264e6e429852221a963e9f17338ba3f5796dc7086e46439a6f4482cf6e0cb"),
Namespace: strP(""),
Type: "oci",
Subpath: strP(""),
},
Artifact: nil,
Vulnerability: &generated.VulnerabilityInputSpec{
Type: "cve",
VulnerabilityID: "cve-2023-12345",
},
VexData: &generated.VexStatementInputSpec{
KnownSince: parseRfc3339("2023-01-09T21:23:03.579712389-06:00"),
Origin: "https://openvex.dev/docs/public/vex-a06f9de1ad1b1e555a33b2d0c1e7e6ecc4dc1800ff457c61ea09d8e97670d2a3",
VexJustification: generated.VexJustificationInlineMitigationsAlreadyExist,
Status: generated.VexStatusNotAffected,
Statement: "Included git is mitigated against CVE-2023-12345 !",
},
},
}

//go:embed exampledata/open-vex-affected.json
AffectedOpenVex []byte

AffectedOpenVexIngest = []assembler.VexIngest{
{
Pkg: &generated.PkgInputSpec{
Name: "bash",
Version: strP("1.0.0"),
Namespace: strP("wolfi"),
Type: "apk",
Subpath: strP(""),
},
Artifact: nil,
Vulnerability: &generated.VulnerabilityInputSpec{
Type: "cve",
VulnerabilityID: "cve-1234-5678",
},
VexData: &generated.VexStatementInputSpec{
KnownSince: parseRfc3339("2023-01-19T02:36:03.290252574-06:00"),
Origin: "merged-vex-67124ea942ef30e1f42f3f2bf405fbbc4f5a56e6e87684fc5cd957212fa3e025",
Status: generated.VexStatusAffected,
Statement: "This is a test action statement",
},
},
}

AffectedOpenVEXCertifyVulnIngest = []assembler.CertifyVulnIngest{
{
Pkg: &generated.PkgInputSpec{
Name: "bash",
Version: strP("1.0.0"),
Namespace: strP("wolfi"),
Type: "apk",
Subpath: strP(""),
},
Vulnerability: &generated.VulnerabilityInputSpec{
Type: "cve",
VulnerabilityID: "cve-1234-5678",
},
VulnData: &generated.ScanMetadataInput{
TimeScanned: parseRfc3339("2023-01-19T02:36:03.290252574-06:00"),
},
},
}

// CSAF
//go:embed exampledata/rhsa-csaf.json
CsafExampleRedHat []byte
Expand Down
37 changes: 37 additions & 0 deletions pkg/handler/processor/guesser/type_open_vex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright 2023 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package guesser

import (
"github.com/openvex/go-vex/pkg/vex"

"github.com/guacsec/guac/pkg/handler/processor"
)

type openVexTypeGuesser struct{}

func (_ *openVexTypeGuesser) GuessDocumentType(blob []byte, format processor.FormatType) processor.DocumentType {
switch format {
case processor.FormatJSON:
// Decode the BOM
var decoded vex.VEX
err := json.Unmarshal(blob, &decoded)
if err == nil && decoded.Metadata.ID != "" {
return processor.DocumentOpenVEX
}
}
return processor.DocumentUnknown
}
62 changes: 62 additions & 0 deletions pkg/handler/processor/guesser/type_open_vex_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Copyright 2023 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package guesser

import (
"testing"

"github.com/guacsec/guac/internal/testing/testdata"
"github.com/guacsec/guac/pkg/handler/processor"
)

func Test_openVexTypeGuesser_GuessDocumentType(t *testing.T) {
type args struct {
blob []byte
format processor.FormatType
}
tests := []struct {
name string
args args
want processor.DocumentType
}{
{
name: "invalid openvex Document",
args: args{
blob: []byte(`{
"abc": "def"
}`),
format: processor.FormatJSON,
},
want: processor.DocumentUnknown,
},
{
name: "valid openvex Document",
args: args{
blob: testdata.NotAffectedOpenVEXExample,
format: processor.FormatJSON,
},
want: processor.DocumentOpenVEX,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
op := &openVexTypeGuesser{}
if got := op.GuessDocumentType(tt.args.blob, tt.args.format); got != tt.want {
t.Errorf("GuessDocumentType() = %v, want %v", got, tt.want)
}
})
}
}
57 changes: 57 additions & 0 deletions pkg/handler/processor/open_vex/open_vex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// Copyright 2023 The GUAC Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package open_vex

import (
"fmt"

json "github.com/json-iterator/go"

"github.com/guacsec/guac/pkg/handler/processor"
"github.com/openvex/go-vex/pkg/vex"
)

// OpenVEXProcessor processes OpenVEX documents.
// Currently only supports OpenVEX JSON documents.
type OpenVEXProcessor struct{}

func (p *OpenVEXProcessor) ValidateSchema(d *processor.Document) error {
if d.Type != processor.DocumentOpenVEX {
return fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentOpenVEX, d.Type)
}

switch d.Format {
case processor.FormatJSON:
var decoded vex.VEX
err := json.Unmarshal(d.Blob, &decoded)
return err
}

return fmt.Errorf("unable to support parsing of OpenVEX document format: %v", d.Format)
}

// Unpack takes in the document and tries to unpack it
// if there is a valid decomposition of sub-documents.
//
// Returns empty list and nil error if nothing to unpack
// Returns unpacked list and nil error if successfully unpacked
func (p *OpenVEXProcessor) Unpack(d *processor.Document) ([]*processor.Document, error) {
if d.Type != processor.DocumentOpenVEX {
return nil, fmt.Errorf("expected document type: %v, actual document type: %v", processor.DocumentOpenVEX, d.Type)
}

return []*processor.Document{}, nil
}
Loading

0 comments on commit 861288d

Please sign in to comment.