diff --git a/Dockerfile.scanner b/Dockerfile.scanner index f562b2cc4..4aae99999 100644 --- a/Dockerfile.scanner +++ b/Dockerfile.scanner @@ -55,9 +55,33 @@ RUN CGO_ENABLED=0 make devguard-scanner FROM alpine:3.22.1@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 RUN apk add --no-cache git python3 -RUN python3 -m venv /usr/local/bin/venv && \ - /usr/local/bin/venv/bin/pip install --upgrade pip && \ - /usr/local/bin/venv/bin/pip install semgrep checkov +# Create virtualenvs +ENV VENV_DIR=/opt/tools +RUN python -m venv ${VENV_DIR}/semgrep && \ + python -m venv ${VENV_DIR}/checkov + +# Install semgrep in its venv +RUN ${VENV_DIR}/semgrep/bin/pip install --upgrade pip && \ + ${VENV_DIR}/semgrep/bin/pip install semgrep==1.131.0 + +# Install checkov in its venv +RUN ${VENV_DIR}/checkov/bin/pip install --upgrade pip && \ + ${VENV_DIR}/checkov/bin/pip install checkov==3.2.457 + + +RUN cat < /usr/local/bin/semgrep +#!/bin/sh +exec ${VENV_DIR}/semgrep/bin/semgrep "\$@" +EOF + +RUN chmod +x /usr/local/bin/semgrep + +RUN cat < /usr/local/bin/checkov +#!/bin/sh +exec ${VENV_DIR}/checkov/bin/checkov "\$@" +EOF + +RUN chmod +x /usr/local/bin/checkov # add venv bin to path ENV PATH="/usr/local/bin/venv/bin:$PATH" diff --git a/internal/core/vuln/dependency_vuln_service.go b/internal/core/vuln/dependency_vuln_service.go index d11f9894c..beeccc619 100644 --- a/internal/core/vuln/dependency_vuln_service.go +++ b/internal/core/vuln/dependency_vuln_service.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "log/slog" + "slices" "time" "github.com/google/uuid" @@ -105,7 +106,16 @@ func (s *service) UserDetectedExistingVulnOnDifferentBranch(tx core.DB, scannerI ev := models.NewDetectedOnAnotherBranchEvent(dependencyVuln.CalculateHash(), models.VulnTypeDependencyVuln, "system", riskReport, scannerID, assetVersion.Name) events[i] = append(events[i], ev) // replay all events on the dependencyVuln - for _, ev := range alreadyExistingEvents[i] { + // but sort them by the time they were created ascending + slices.SortStableFunc(events[i], func(a, b models.VulnEvent) int { + if a.CreatedAt.Before(b.CreatedAt) { + return -1 + } else if a.CreatedAt.After(b.CreatedAt) { + return 1 + } + return 0 + }) + for _, ev := range events[i] { ev.Apply(&dependencyVulns[i]) } } diff --git a/internal/core/vulndb/scan/scan_integration_test.go b/internal/core/vulndb/scan/scan_integration_test.go index f87ed4db0..c8d2a0d2a 100644 --- a/internal/core/vulndb/scan/scan_integration_test.go +++ b/internal/core/vulndb/scan/scan_integration_test.go @@ -177,12 +177,6 @@ func TestScanning(t *testing.T) { // should be only a single vulnerability assert.Nil(t, err) assert.Len(t, vulns, 1) - // mark the vuln as accepted - vulns[0].State = models.VulnStateAccepted - // save it - err = dependencyVulnRepository.Save(nil, &vulns[0]) - assert.Nil(t, err) - // create an accepted event inside the database acceptedEvent := models.NewAcceptedEvent(vulns[0].ID, vulns[0].GetType(), "abc", "accepting the vulnerability") err = dependencyVulnRepository.ApplyAndSave(nil, &vulns[0], &acceptedEvent) @@ -219,12 +213,27 @@ func TestScanning(t *testing.T) { newVuln = v } } + assert.NotEmpty(t, newVuln.Events) lastTwoEvents := newVuln.Events[len(newVuln.Events)-2:] - assert.Equal(t, models.EventTypeAccepted, lastTwoEvents[0].Type) - assert.Equal(t, "accepting the vulnerability", *lastTwoEvents[0].Justification) - assert.Equal(t, "main", *lastTwoEvents[0].OriginalAssetVersionName) - assert.Equal(t, models.EventTypeDetectedOnAnotherBranch, lastTwoEvents[1].Type) + + // we can not really rely on the created_at since the events are created in the same second + // nevertheless - one has to be the accepted event and the other the detected on different branch event + var accEvent models.VulnEvent + var detectedOnAnotherBranchEvent models.VulnEvent + for _, ev := range lastTwoEvents { + if ev.Type == models.EventTypeAccepted { + accEvent = ev + } else { + detectedOnAnotherBranchEvent = ev + } + } + + assert.NotEmpty(t, accEvent) + assert.NotEmpty(t, detectedOnAnotherBranchEvent) + assert.Equal(t, models.EventTypeAccepted, accEvent.Type) + assert.Equal(t, "accepting the vulnerability", *accEvent.Justification) + assert.Equal(t, "main", *accEvent.OriginalAssetVersionName) }) } diff --git a/internal/database/repositories/vulnerability_repository.go b/internal/database/repositories/vulnerability_repository.go index 03f8816c8..188969abe 100644 --- a/internal/database/repositories/vulnerability_repository.go +++ b/internal/database/repositories/vulnerability_repository.go @@ -112,7 +112,9 @@ func (r *VulnerabilityRepository[T]) GetByAssetID( var vulns = []T{} // get all vulnerabilities of the asset - if err := r.Repository.GetDB(tx).Where("asset_id = ?", assetID).Preload("Events").Find(&vulns).Error; err != nil { + if err := r.Repository.GetDB(tx).Where("asset_id = ?", assetID).Preload("Events", func(db *gorm.DB) *gorm.DB { + return db.Order("vuln_events.created_at ASC") + }).Find(&vulns).Error; err != nil { return nil, err } return vulns, nil