Create grafeas project before writing vulnerabilities.

This commit is contained in:
Tobias Furuholm 2018-01-17 13:10:34 +01:00
parent 8397359296
commit 7a2ae81363

View File

@ -1,6 +1,7 @@
package grafeas package grafeas
import ( import (
"context"
"fmt" "fmt"
"reflect" "reflect"
"regexp" "regexp"
@ -8,8 +9,10 @@ import (
"strings" "strings"
"github.com/coreos/clair/database" "github.com/coreos/clair/database"
"github.com/grafeas/client-go/v1alpha1" "github.com/grafeas/grafeas/samples/server/go-server/api/server/name"
pb "github.com/grafeas/grafeas/v1alpha1/proto"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
) )
type Config struct { type Config struct {
@ -45,15 +48,39 @@ func (g *Grafeas) Export(datastore database.Datastore) error {
} }
pID := g.Config.ProjectId pID := g.Config.ProjectId
client := v1alpha1.NewGrafeasApiWithBasePath(g.Config.Addr) conn, err := grpc.Dial(g.Config.Addr, grpc.WithInsecure())
defer conn.Close()
context := context.Background()
pClient := pb.NewGrafeasProjectsClient(conn)
_, err = pClient.GetProject(context,
&pb.GetProjectRequest{
Name: fmt.Sprintf("projects/%s", pID),
})
if err != nil {
// Project does not exist Create project
log.Println("CreateProject")
_, err = pClient.CreateProject(context,
&pb.CreateProjectRequest{
Name: fmt.Sprintf("projects/%s", pID),
})
if err != nil {
// Failed to access API
return err
}
}
client := pb.NewGrafeasClient(conn)
for _, vuln := range vulnerabilities { for _, vuln := range vulnerabilities {
nID := vuln.Name nID := vuln.Name
score, nistVectors := extractMetadata(vuln.Metadata) score, nistVectors := extractMetadata(vuln.Metadata)
note, _, err := client.GetNote(pID, nID) note, err := client.GetNote(
context,
&pb.GetNoteRequest{
Name: name.NoteName(pID, nID),
})
createNewNote := false createNewNote := false
if err != nil { if err != nil {
n := noteWithoutDetails(pID, nID, vuln.Description, string(vuln.Severity), nistVectors, score) note = noteWithoutDetails(pID, nID, vuln.Description, nistVectors, score, severity(vuln.Severity))
note = &n
createNewNote = true createNewNote = true
} }
@ -61,20 +88,29 @@ func (g *Grafeas) Export(datastore database.Datastore) error {
for _, affected := range vuln.Affected { for _, affected := range vuln.Affected {
cpeUri := createCpeUri(affected.Namespace.Name) cpeUri := createCpeUri(affected.Namespace.Name)
detail := detail(cpeUri, affected.FeatureName, vuln.Description, string(vuln.Severity), affected.FixedInVersion) detail := detail(cpeUri, affected.FeatureName, vuln.Description, string(vuln.Severity), affected.FixedInVersion)
index := findDetail(note.VulnerabilityType.Details, detail) index := findDetail(note.GetVulnerabilityType().Details, detail)
if index == -1 { if index == -1 {
note.VulnerabilityType.Details = append(note.VulnerabilityType.Details, detail) note.GetVulnerabilityType().Details = append(note.GetVulnerabilityType().Details, &detail)
containsUpdatedDetail = true containsUpdatedDetail = true
} else if !reflect.DeepEqual(note.VulnerabilityType.Details[index], detail) { } else if !reflect.DeepEqual(note.GetVulnerabilityType().Details[index], detail) {
note.VulnerabilityType.Details[index] = detail note.GetVulnerabilityType().Details[index] = &detail
containsUpdatedDetail = true containsUpdatedDetail = true
} }
} }
if createNewNote { if createNewNote {
_, _, err = client.CreateNote(pID, nID, *note) _, err = client.CreateNote(context,
&pb.CreateNoteRequest{
Parent: fmt.Sprintf("projects/%s", pID),
NoteId: nID,
Note: note,
})
} else if containsUpdatedDetail { } else if containsUpdatedDetail {
_, _, err = client.UpdateNote(pID, nID, *note) _, err = client.UpdateNote(context,
&pb.UpdateNoteRequest{
Name: name.NoteName(pID, nID),
Note: note,
})
} }
if err != nil { if err != nil {
@ -125,20 +161,39 @@ func createCpeUri(namespaceName string) string {
return "CPE_UNSPECIFIED" return "CPE_UNSPECIFIED"
} }
func findDetail(details []v1alpha1.Detail, detail v1alpha1.Detail) int { func findDetail(details []*pb.VulnerabilityType_Detail, detail pb.VulnerabilityType_Detail) int {
for i, d := range details { for i, d := range details {
if d.CpeUri == detail.CpeUri && d.Package_ == detail.Package_ { if d.CpeUri == detail.CpeUri && d.PackageType == detail.PackageType {
return i return i
} }
} }
return -1 return -1
} }
func fixedLocation(fixedBy, cpeUri, pkg string) v1alpha1.VulnerabilityLocation { func severity(severity database.Severity) pb.VulnerabilityType_Severity {
var version v1alpha1.Version switch severity {
case database.Defcon1Severity:
return pb.VulnerabilityType_CRITICAL
case database.CriticalSeverity:
return pb.VulnerabilityType_CRITICAL
case database.HighSeverity:
return pb.VulnerabilityType_HIGH
case database.MediumSeverity:
return pb.VulnerabilityType_MEDIUM
case database.LowSeverity:
return pb.VulnerabilityType_LOW
case database.NegligibleSeverity:
return pb.VulnerabilityType_LOW
default:
return pb.VulnerabilityType_SEVERITY_UNSPECIFIED
}
}
func fixedLocation(fixedBy, cpeUri, pkg string) *pb.VulnerabilityType_VulnerabilityLocation {
var version pb.VulnerabilityType_Version
if fixedBy == "" { if fixedBy == "" {
version = v1alpha1.Version{ version = pb.VulnerabilityType_Version{
Kind: "MAXIMUM", Kind: pb.VulnerabilityType_Version_MAXIMUM,
} }
} else { } else {
// EVR: Epoch:Version.Revision // EVR: Epoch:Version.Revision
@ -148,51 +203,53 @@ func fixedLocation(fixedBy, cpeUri, pkg string) v1alpha1.VulnerabilityLocation {
versionEpoch, _ := strconv.ParseInt(matches[1], 10, 32) versionEpoch, _ := strconv.ParseInt(matches[1], 10, 32)
versionName := matches[2] versionName := matches[2]
versionRev := matches[3] versionRev := matches[3]
version = v1alpha1.Version{ version = pb.VulnerabilityType_Version{
Epoch: int32(versionEpoch), Epoch: int32(versionEpoch),
Name: versionName, Name: versionName,
Revision: versionRev, Revision: versionRev,
} }
} else { } else {
version = v1alpha1.Version{ version = pb.VulnerabilityType_Version{
Name: fixedBy, Name: fixedBy,
} }
} }
} }
return v1alpha1.VulnerabilityLocation{ return &pb.VulnerabilityType_VulnerabilityLocation{
CpeUri: cpeUri, CpeUri: cpeUri,
Package_: pkg, Package: pkg,
Version: version, Version: &version,
} }
} }
func detail(cpeUri, packageName, description, severity, fixedBy string) v1alpha1.Detail { func detail(cpeUri, packageName, description, severity, fixedBy string) pb.VulnerabilityType_Detail {
return v1alpha1.Detail{ return pb.VulnerabilityType_Detail{
CpeUri: cpeUri, CpeUri: cpeUri,
Package_: packageName, Package: packageName,
Description: description, Description: description,
MinAffectedVersion: v1alpha1.Version{ MinAffectedVersion: &pb.VulnerabilityType_Version{
Kind: "MINIMUM", Kind: pb.VulnerabilityType_Version_MINIMUM,
}, },
SeverityName: severity, SeverityName: severity,
FixedLocation: fixedLocation(fixedBy, cpeUri, packageName), FixedLocation: fixedLocation(fixedBy, cpeUri, packageName),
} }
} }
func noteWithoutDetails(pID, name, description, severity, nistVectors string, score float32) v1alpha1.Note { func noteWithoutDetails(pID, name, description, nistVectors string, score float32, severity pb.VulnerabilityType_Severity) *pb.Note {
var longDescription string var longDescription string
if nistVectors != "" { if nistVectors != "" {
longDescription = fmt.Sprintf("NIST vectors: %v", nistVectors) longDescription = fmt.Sprintf("NIST vectors: %v", nistVectors)
} }
return v1alpha1.Note{ return &pb.Note{
Name: fmt.Sprintf("projects/%v/notes/%v", pID, name), Name: fmt.Sprintf("projects/%v/notes/%v", pID, name),
ShortDescription: name, ShortDescription: name,
LongDescription: longDescription, LongDescription: longDescription,
Kind: "PACKAGE_VULNERABILITY", Kind: pb.Note_PACKAGE_VULNERABILITY,
VulnerabilityType: v1alpha1.VulnerabilityType{ NoteType: &pb.Note_VulnerabilityType{
CvssScore: score, &pb.VulnerabilityType{
Severity: severity, CvssScore: score,
Details: []v1alpha1.Detail{}, Severity: severity,
Details: []*pb.VulnerabilityType_Detail{},
},
}, },
} }
} }