Skip to content

Commit

Permalink
Merge bfd668b into 08e956e
Browse files Browse the repository at this point in the history
  • Loading branch information
matthyx committed Jun 7, 2023
2 parents 08e956e + bfd668b commit 6a8dd65
Show file tree
Hide file tree
Showing 22 changed files with 309 additions and 305 deletions.
2 changes: 1 addition & 1 deletion adapters/mockcve.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (m MockCVEAdapter) Ready(context.Context) bool {
func (m MockCVEAdapter) ScanSBOM(ctx context.Context, sbom domain.SBOM) (domain.CVEManifest, error) {
logger.L().Info("ScanSBOM")
return domain.CVEManifest{
ID: sbom.ID,
Name: sbom.Name,
SBOMCreatorVersion: sbom.SBOMCreatorVersion,
CVEScannerVersion: m.Version(ctx),
CVEDBVersion: m.DBVersion(ctx),
Expand Down
4 changes: 2 additions & 2 deletions adapters/mocksbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func NewMockSBOMAdapter(error, timeout, toomanyrequests bool) *MockSBOMAdapter {
}

// CreateSBOM returns a dummy SBOM for the given imageID
func (m MockSBOMAdapter) CreateSBOM(_ context.Context, imageID string, _ domain.RegistryOptions) (domain.SBOM, error) {
func (m MockSBOMAdapter) CreateSBOM(_ context.Context, name, imageID string, _ domain.RegistryOptions) (domain.SBOM, error) {
logger.L().Info("CreateSBOM")
if m.error {
return domain.SBOM{}, domain.ErrMockError
Expand All @@ -48,7 +48,7 @@ func (m MockSBOMAdapter) CreateSBOM(_ context.Context, imageID string, _ domain.
)
}
sbom := domain.SBOM{
ID: imageID,
Name: name,
SBOMCreatorVersion: m.Version(),
Annotations: map[string]string{
instanceidhandler.ImageIDMetadataKey: imageID,
Expand Down
6 changes: 3 additions & 3 deletions adapters/mocksbom_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@ import (

func TestMockSBOMAdapter_CreateSBOM(t *testing.T) {
m := NewMockSBOMAdapter(false, false, false)
sbom, _ := m.CreateSBOM(context.TODO(), "image", domain.RegistryOptions{})
sbom, _ := m.CreateSBOM(context.TODO(), "name", "image", domain.RegistryOptions{})
assert.NotNil(t, sbom.Content)
}

func TestMockSBOMAdapter_CreateSBOM_Error(t *testing.T) {
m := NewMockSBOMAdapter(true, false, false)
_, err := m.CreateSBOM(context.TODO(), "image", domain.RegistryOptions{})
_, err := m.CreateSBOM(context.TODO(), "name", "image", domain.RegistryOptions{})
assert.Error(t, err)
}

func TestMockSBOMAdapter_CreateSBOM_Timeout(t *testing.T) {
m := NewMockSBOMAdapter(false, true, false)
sbom, _ := m.CreateSBOM(context.TODO(), "image", domain.RegistryOptions{})
sbom, _ := m.CreateSBOM(context.TODO(), "name", "image", domain.RegistryOptions{})
assert.Equal(t, sbom.Status, instanceidhandler.Incomplete)
}

Expand Down
14 changes: 10 additions & 4 deletions adapters/v1/armo_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,17 @@ func (a *ArmoAdapter) postResultsAsGoroutine(ctx context.Context, report *v1.Sca
func (a *ArmoAdapter) postResults(ctx context.Context, report *v1.ScanResultReport, eventReceiverURL, imagetag, wlid string, errorChan chan<- error) {
payload, err := json.Marshal(report)
if err != nil {
logger.L().Ctx(ctx).Error("failed to convert to json", helpers.Error(err), helpers.String("wlid", wlid))
logger.L().Ctx(ctx).Error("failed to convert to json", helpers.Error(err),
helpers.String("wlid", wlid))
errorChan <- err
return
}

urlBase, err := url.Parse(eventReceiverURL)
if err != nil {
logger.L().Ctx(ctx).Error("failed parsing eventReceiverURL", helpers.Error(err), helpers.String("url", eventReceiverURL), helpers.String("wlid", wlid))
logger.L().Ctx(ctx).Error("failed parsing eventReceiverURL", helpers.Error(err),
helpers.String("url", eventReceiverURL),
helpers.String("wlid", wlid))
err = fmt.Errorf("fail parsing URL, %s, err: %s", eventReceiverURL, err.Error())
errorChan <- err
return
Expand All @@ -84,14 +87,17 @@ func (a *ArmoAdapter) postResults(ctx context.Context, report *v1.ScanResultRepo

resp, err := a.httpPostFunc(http.DefaultClient, urlBase.String(), map[string]string{"Content-Type": "application/json"}, payload)
if err != nil {
logger.L().Ctx(ctx).Error("failed posting to event", helpers.String("image", imagetag), helpers.String("wlid", wlid), helpers.Error(err))
logger.L().Ctx(ctx).Error("failed posting to event", helpers.Error(err),
helpers.String("image", imagetag),
helpers.String("wlid", wlid))
errorChan <- err
return
}
defer resp.Body.Close()
body, err := httputils.HttpRespToString(resp)
if err != nil {
logger.L().Ctx(ctx).Error("Vulnerabilities post to event receiver failed", helpers.Error(err), helpers.String("body", body))
logger.L().Ctx(ctx).Error("Vulnerabilities post to event receiver failed", helpers.Error(err),
helpers.String("body", body))
errorChan <- err
return
}
Expand Down
23 changes: 15 additions & 8 deletions adapters/v1/grype.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ func (g *GrypeAdapter) Ready(ctx context.Context) bool {
defer g.mu.Unlock()
ctx, span := otel.Tracer("").Start(ctx, "GrypeAdapter.UpdateDB")
defer span.End()
logger.L().Info("updating grype DB", helpers.String("listingURL", g.dbConfig.ListingURL))
logger.L().Info("updating grype DB",
helpers.String("listingURL", g.dbConfig.ListingURL))
var err error
g.store, g.dbStatus, g.dbCloser, err = grype.LoadVulnerabilityDB(g.dbConfig, true)
if err != nil {
Expand Down Expand Up @@ -113,13 +114,15 @@ func (g *GrypeAdapter) ScanSBOM(ctx context.Context, sbom domain.SBOM) (domain.C
return domain.CVEManifest{}, domain.ErrInitVulnDB
}

logger.L().Debug("decoding SBOM", helpers.String("imageID", sbom.ID))
logger.L().Debug("decoding SBOM",
helpers.String("name", sbom.Name))
s, err := domainToSyft(*sbom.Content)
if err != nil {
return domain.CVEManifest{}, err
}

logger.L().Debug("reading packages from SBOM", helpers.String("imageID", sbom.ID))
logger.L().Debug("reading packages from SBOM",
helpers.String("name", sbom.Name))
packages := pkg.FromCatalog(s.Artifacts.PackageCatalog, pkg.SynthesisConfig{})
if err != nil {
return domain.CVEManifest{}, err
Expand All @@ -133,27 +136,31 @@ func (g *GrypeAdapter) ScanSBOM(ctx context.Context, sbom domain.SBOM) (domain.C
Matchers: getMatchers(),
}

logger.L().Debug("finding vulnerabilities", helpers.String("imageID", sbom.ID))
logger.L().Debug("finding vulnerabilities",
helpers.String("name", sbom.Name))
remainingMatches, ignoredMatches, err := vulnMatcher.FindMatches(packages, pkgContext)
if err != nil {
return domain.CVEManifest{}, err
}

logger.L().Debug("compiling results", helpers.String("imageID", sbom.ID))
logger.L().Debug("compiling results",
helpers.String("name", sbom.Name))
doc, err := models.NewDocument(packages, pkgContext, *remainingMatches, ignoredMatches, g.store, nil, g.dbStatus)
if err != nil {
return domain.CVEManifest{}, err
}

logger.L().Debug("converting results to common format", helpers.String("imageID", sbom.ID))
logger.L().Debug("converting results to common format",
helpers.String("name", sbom.Name))
vulnerabilityResults, err := grypeToDomain(doc)
if err != nil {
return domain.CVEManifest{}, err
}

logger.L().Debug("returning CVE manifest", helpers.String("imageID", sbom.ID))
logger.L().Debug("returning CVE manifest",
helpers.String("name", sbom.Name))
return domain.CVEManifest{
ID: sbom.ID,
Name: sbom.Name,
SBOMCreatorVersion: sbom.SBOMCreatorVersion,
CVEScannerVersion: g.Version(ctx),
CVEDBVersion: g.DBVersion(ctx),
Expand Down
4 changes: 2 additions & 2 deletions adapters/v1/grype_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func Test_grypeAdapter_ScanSBOM(t *testing.T) {
{
name: "valid SBOM produces well-formed vulnerability list",
sbom: domain.SBOM{
ID: "library/alpine@sha256:e2e16842c9b54d985bf1ef9242a313f36b856181f188de21313820e177002501",
Name: "library/alpine@sha256:e2e16842c9b54d985bf1ef9242a313f36b856181f188de21313820e177002501",
SBOMCreatorVersion: "TODO",
Content: fileToSBOM("testdata/alpine-sbom.json"),
},
Expand All @@ -51,7 +51,7 @@ func Test_grypeAdapter_ScanSBOM(t *testing.T) {
{
name: "filtered SBOM",
sbom: domain.SBOM{
ID: "927669769708707a6ec583b2f4f93eeb4d5b59e27d793a6e99134e505dac6c3c",
Name: "927669769708707a6ec583b2f4f93eeb4d5b59e27d793a6e99134e505dac6c3c",
SBOMCreatorVersion: "TODO",
Content: fileToSBOM("testdata/nginx-filtered-sbom.json"),
},
Expand Down
32 changes: 21 additions & 11 deletions adapters/v1/syft.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ func NewSyftAdapter(scanTimeout time.Duration, maxImageSize int64) *SyftAdapter
// CreateSBOM creates an SBOM for a given imageID, restrict parallelism to prevent disk space issues,
// a timeout prevents the process from hanging for too long.
// Format is SPDX JSON and the resulting SBOM is tagged with the Syft version.
func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options domain.RegistryOptions) (domain.SBOM, error) {
func (s *SyftAdapter) CreateSBOM(ctx context.Context, name, imageID string, options domain.RegistryOptions) (domain.SBOM, error) {
ctx, span := otel.Tracer("").Start(ctx, "SyftAdapter.CreateSBOM")
defer span.End()
// prepare an SBOM and fill it progressively
domainSBOM := domain.SBOM{
ID: imageID,
Name: name,
SBOMCreatorVersion: s.Version(),
Annotations: map[string]string{
instanceidhandler.ImageIDMetadataKey: imageID,
Expand Down Expand Up @@ -94,22 +94,27 @@ func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options do
defer func(t *file.TempDirGenerator) {
err := t.Cleanup()
if err != nil {
logger.L().Ctx(ctx).Warning("failed to cleanup temp dir", helpers.String("imageID", imageID), helpers.Error(err))
logger.L().Ctx(ctx).Warning("failed to cleanup temp dir", helpers.Error(err),
helpers.String("imageID", imageID))
}
}(t)
// download image
logger.L().Debug("downloading image", helpers.String("imageID", imageID))
logger.L().Debug("downloading image",
helpers.String("imageID", imageID))
src, err := newFromRegistry(t, sourceInput, registryOptions, s.maxImageSize)
// check for 401 error and retry without credentials
var transportError *transport.Error
if errors.As(err, &transportError) && transportError.StatusCode == http.StatusUnauthorized {
logger.L().Debug("got 401, retrying without credentials", helpers.String("imageID", imageID))
logger.L().Debug("got 401, retrying without credentials",
helpers.String("imageID", imageID))
registryOptions.Credentials = nil
src, err = newFromRegistry(t, sourceInput, registryOptions, s.maxImageSize)
}
switch {
case errors.Is(err, ErrImageTooLarge):
logger.L().Ctx(ctx).Warning("Image exceeds size limit", helpers.Int("maxImageSize", int(s.maxImageSize)), helpers.String("imageID", imageID))
logger.L().Ctx(ctx).Warning("Image exceeds size limit",
helpers.Int("maxImageSize", int(s.maxImageSize)),
helpers.String("imageID", imageID))
domainSBOM.Status = instanceidhandler.Incomplete
return domainSBOM, nil
case err != nil:
Expand All @@ -123,7 +128,8 @@ func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options do
var actualDistro *linux.Release
dl := deadline.New(s.scanTimeout)
err = dl.Run(func(stopper <-chan struct{}) error {
logger.L().Debug("extracting packages", helpers.String("imageID", imageID))
logger.L().Debug("extracting packages",
helpers.String("imageID", imageID))
catalogOptions := cataloger.Config{
Search: cataloger.DefaultSearchConfig(),
Parallelism: 4, // TODO assess this value
Expand All @@ -133,7 +139,8 @@ func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options do
})
switch err {
case deadline.ErrTimedOut:
logger.L().Ctx(ctx).Warning("Syft timed out", helpers.String("imageID", imageID))
logger.L().Ctx(ctx).Warning("Syft timed out",
helpers.String("imageID", imageID))
domainSBOM.Status = instanceidhandler.Incomplete
return domainSBOM, nil
case nil:
Expand All @@ -144,7 +151,8 @@ func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options do
return domainSBOM, err
}
// generate SBOM
logger.L().Debug("generating SBOM", helpers.String("imageID", imageID))
logger.L().Debug("generating SBOM",
helpers.String("imageID", imageID))
syftSBOM := sbom.SBOM{
Source: src.Metadata,
Relationships: relationships,
Expand All @@ -154,10 +162,12 @@ func (s *SyftAdapter) CreateSBOM(ctx context.Context, imageID string, options do
},
}
// convert SBOM
logger.L().Debug("converting SBOM", helpers.String("imageID", imageID))
logger.L().Debug("converting SBOM",
helpers.String("imageID", imageID))
domainSBOM.Content, err = s.syftToDomain(syftSBOM)
// return SBOM
logger.L().Debug("returning SBOM", helpers.String("imageID", imageID))
logger.L().Debug("returning SBOM",
helpers.String("imageID", imageID))
return domainSBOM, err
}

Expand Down
2 changes: 1 addition & 1 deletion adapters/v1/syft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func Test_syftAdapter_CreateSBOM(t *testing.T) {
maxImageSize = tt.maxImageSize
}
s := NewSyftAdapter(5*time.Minute, maxImageSize)
got, err := s.CreateSBOM(context.TODO(), tt.imageID, tt.options)
got, err := s.CreateSBOM(context.TODO(), "name", tt.imageID, tt.options)
if (err != nil) != tt.wantErr {
t.Errorf("CreateSBOM() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
41 changes: 34 additions & 7 deletions controllers/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/k8s-interface/names"
"github.com/kubescape/kubevuln/core/domain"
"github.com/kubescape/kubevuln/core/ports"
"schneider.vip/problem"
Expand Down Expand Up @@ -47,7 +48,10 @@ func (h HTTPController) GenerateSBOM(c *gin.Context) {

ctx, err = h.scanService.ValidateGenerateSBOM(ctx, newScan)
if err != nil {
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err), helpers.String("imageID", newScan.ImageHash))
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
_, _ = problem.Of(http.StatusInternalServerError).Append(details).WriteTo(c.Writer)
return
}
Expand All @@ -57,7 +61,10 @@ func (h HTTPController) GenerateSBOM(c *gin.Context) {
h.workerPool.Submit(func() {
err = h.scanService.GenerateSBOM(ctx)
if err != nil {
logger.L().Ctx(ctx).Error("service error", helpers.Error(err), helpers.String("imageID", newScan.ImageHash))
logger.L().Ctx(ctx).Error("service error", helpers.Error(err),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
}
})
}
Expand Down Expand Up @@ -95,7 +102,10 @@ func (h HTTPController) ScanCVE(c *gin.Context) {

ctx, err = h.scanService.ValidateScanCVE(ctx, newScan)
if err != nil {
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err), helpers.String("wlid", newScan.Wlid), helpers.String("imageID", newScan.ImageHash))
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
_, _ = problem.Of(http.StatusInternalServerError).Append(details).WriteTo(c.Writer)
return
}
Expand All @@ -105,7 +115,11 @@ func (h HTTPController) ScanCVE(c *gin.Context) {
h.workerPool.Submit(func() {
err = h.scanService.ScanCVE(ctx)
if err != nil {
logger.L().Ctx(ctx).Error("service error", helpers.Error(err), helpers.String("wlid", newScan.Wlid), helpers.String("imageID", newScan.ImageHash))
logger.L().Ctx(ctx).Error("service error", helpers.Error(err),
helpers.String("wlid", newScan.Wlid),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
}
})
}
Expand All @@ -123,6 +137,9 @@ func websocketScanCommandToScanCommand(c wssc.WebsocketScanCommand) domain.ScanC
Args: c.Args,
Session: sessionChainToSession(c.Session),
}
if slug, err := names.ImageInfoToSlug(c.ImageTag, c.ImageHash); err == nil {
command.ImageSlug = slug
}
if c.InstanceID != nil {
command.InstanceID = *c.InstanceID
}
Expand Down Expand Up @@ -152,7 +169,10 @@ func (h HTTPController) ScanRegistry(c *gin.Context) {

ctx, err = h.scanService.ValidateScanRegistry(ctx, newScan)
if err != nil {
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err), helpers.String("imageID", newScan.ImageTag))
logger.L().Ctx(ctx).Error("validation error", helpers.Error(err),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
_, _ = problem.Of(http.StatusInternalServerError).Append(details).WriteTo(c.Writer)
return
}
Expand All @@ -162,7 +182,10 @@ func (h HTTPController) ScanRegistry(c *gin.Context) {
h.workerPool.Submit(func() {
err = h.scanService.ScanRegistry(ctx)
if err != nil {
logger.L().Ctx(ctx).Error("service error", helpers.Error(err), helpers.String("imageID", newScan.ImageTag))
logger.L().Ctx(ctx).Error("service error", helpers.Error(err),
helpers.String("imageSlug", newScan.ImageSlug),
helpers.String("imageTag", newScan.ImageTag),
helpers.String("imageHash", newScan.ImageHash))
}
})
}
Expand All @@ -176,10 +199,14 @@ func registryScanCommandToScanCommand(c wssc.RegistryScanCommand) domain.ScanCom
Args: c.Args,
Session: sessionChainToSession(c.Session),
}
if slug, err := names.ImageInfoToSlug(c.ImageTag, "nohash"); err == nil {
command.ImageSlug = slug
}
return command
}

func (h HTTPController) Shutdown() {
logger.L().Info("purging SBOM creation queue", helpers.String("remaining jobs", strconv.Itoa(h.workerPool.WaitingQueueSize())))
logger.L().Info("purging SBOM creation queue",
helpers.String("remaining jobs", strconv.Itoa(h.workerPool.WaitingQueueSize())))
h.workerPool.StopWait()
}
2 changes: 1 addition & 1 deletion core/domain/cve.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type CVEExceptions []armotypes.VulnerabilityExceptionPolicy

// CVEManifest contains a JSON CVE report manifest with some metadata
type CVEManifest struct {
ID string
Name string
Wlid string
SBOMCreatorName string
SBOMCreatorVersion string
Expand Down
2 changes: 1 addition & 1 deletion core/domain/sbom.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

// SBOM contains an SPDX SBOM in JSON format with some metadata
type SBOM struct {
ID string
Name string
SBOMCreatorName string
SBOMCreatorVersion string
Status string
Expand Down
Loading

0 comments on commit 6a8dd65

Please sign in to comment.