Skip to content

Commit 0feb361

Browse files
committed
added test
1 parent fe3d98b commit 0feb361

3 files changed

Lines changed: 120 additions & 9 deletions

File tree

controllers/dependency_vuln_controller.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/json"
66
"log/slog"
77
"slices"
8-
"strings"
98
"time"
109

1110
"go.opentelemetry.io/otel/trace"
@@ -518,19 +517,17 @@ func (controller DependencyVulnController) GetRecommendation(ctx echo.Context) e
518517
}
519518

520519
version := extractVersionFromPURL(*recommendedVersion)
520+
if version == "" {
521+
return ctx.JSON(200, dtos.Recommendation{RecommendedVersion: ""})
522+
}
521523

522524
return ctx.JSON(200, dtos.Recommendation{RecommendedVersion: version})
523525
}
524526

525527
func extractVersionFromPURL(input string) string {
526-
if !strings.HasPrefix(input, "pkg:") {
527-
return input
528-
}
529-
530528
parsed, err := packageurl.FromString(input)
531529
if err != nil {
532-
slog.Error("could not parse purl", "error", err)
533-
return input
530+
return ""
534531
}
535532

536533
return parsed.Version

database/repositories/dependency_vuln_repository.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package repositories
22

33
import (
44
"context"
5+
"database/sql"
56
"fmt"
67
"log/slog"
78

@@ -544,7 +545,7 @@ func (repository *dependencyVulnRepository) FindByVEXRules(ctx context.Context,
544545
}
545546

546547
func (repository *dependencyVulnRepository) GetDirectDependencyFixedVersionByPackageName(ctx context.Context, tx *gorm.DB, packageName string) (*string, error) {
547-
var directDependencyFixedVersion *string
548+
var directDependencyFixedVersion sql.NullString
548549

549550
err := repository.GetDB(ctx, tx).
550551
WithContext(ctx).
@@ -559,6 +560,10 @@ func (repository *dependencyVulnRepository) GetDirectDependencyFixedVersionByPac
559560
if err != nil {
560561
return nil, err
561562
}
563+
if !directDependencyFixedVersion.Valid || directDependencyFixedVersion.String == "" {
564+
return nil, nil
565+
}
562566

563-
return directDependencyFixedVersion, nil
567+
version := directDependencyFixedVersion.String
568+
return &version, nil
564569
}

tests/dependency_vuln_controller_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package tests
33
import (
44
"bytes"
55
"encoding/json"
6+
"net/http"
67
"net/http/httptest"
78
"os"
89
"testing"
@@ -17,12 +18,120 @@ import (
1718
"github.com/l3montree-dev/devguard/mocks"
1819
"github.com/l3montree-dev/devguard/shared"
1920

21+
"github.com/labstack/echo/v4"
2022
"github.com/stretchr/testify/assert"
2123
"github.com/stretchr/testify/mock"
2224
gitlab "gitlab.com/gitlab-org/api/client-go"
2325
"go.uber.org/fx"
2426
)
2527

28+
func TestDependencyVulnControllerGetRecommendation(t *testing.T) {
29+
buildController := func(t *testing.T, depVulnRepo *mocks.DependencyVulnRepository) *controllers.DependencyVulnController {
30+
return controllers.NewDependencyVulnController(
31+
depVulnRepo,
32+
mocks.NewDependencyVulnService(t),
33+
mocks.NewProjectService(t),
34+
mocks.NewStatisticsService(t),
35+
mocks.NewVulnEventRepository(t),
36+
nil,
37+
)
38+
}
39+
40+
t.Run("uses packageName/packageValue and returns extracted version", func(t *testing.T) {
41+
depVulnRepo := mocks.NewDependencyVulnRepository(t)
42+
controller := buildController(t, depVulnRepo)
43+
44+
recommendedPurl := "pkg:npm/lodash@4.17.21"
45+
depVulnRepo.On("GetDirectDependencyFixedVersionByPackageName", mock.Anything, mock.Anything, "lodash").Return(&recommendedPurl, nil).Once()
46+
47+
req := httptest.NewRequest(http.MethodGet, "/dependency_vuln/recommendation?packageName=lodash&packageValue=^4.0.0", nil)
48+
rec := httptest.NewRecorder()
49+
ctx := NewContext(req, rec)
50+
51+
err := controller.GetRecommendation(ctx)
52+
assert.NoError(t, err)
53+
assert.Equal(t, http.StatusOK, rec.Code)
54+
55+
var response dtos.Recommendation
56+
assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &response))
57+
assert.Equal(t, "4.17.21", response.RecommendedVersion)
58+
depVulnRepo.AssertExpectations(t)
59+
})
60+
61+
t.Run("uses depName/currentValue aliases and returns empty recommendation for non-PURL value", func(t *testing.T) {
62+
depVulnRepo := mocks.NewDependencyVulnRepository(t)
63+
controller := buildController(t, depVulnRepo)
64+
65+
recommendedVersion := "2.3.4"
66+
depVulnRepo.On("GetDirectDependencyFixedVersionByPackageName", mock.Anything, mock.Anything, "leftpad").Return(&recommendedVersion, nil).Once()
67+
68+
req := httptest.NewRequest(http.MethodGet, "/dependency_vuln/recommendation?depName=leftpad&currentValue=2.0.0", nil)
69+
rec := httptest.NewRecorder()
70+
ctx := NewContext(req, rec)
71+
72+
err := controller.GetRecommendation(ctx)
73+
assert.NoError(t, err)
74+
assert.Equal(t, http.StatusOK, rec.Code)
75+
76+
var response map[string]string
77+
assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &response))
78+
assert.Equal(t, "", response["recommendedVersion"])
79+
depVulnRepo.AssertExpectations(t)
80+
})
81+
82+
t.Run("returns empty recommendation when repository returns nil", func(t *testing.T) {
83+
depVulnRepo := mocks.NewDependencyVulnRepository(t)
84+
controller := buildController(t, depVulnRepo)
85+
86+
depVulnRepo.On("GetDirectDependencyFixedVersionByPackageName", mock.Anything, mock.Anything, "chalk").Return((*string)(nil), nil).Once()
87+
88+
req := httptest.NewRequest(http.MethodGet, "/dependency_vuln/recommendation?packageName=chalk&packageValue=5.0.0", nil)
89+
rec := httptest.NewRecorder()
90+
ctx := NewContext(req, rec)
91+
92+
err := controller.GetRecommendation(ctx)
93+
assert.NoError(t, err)
94+
assert.Equal(t, http.StatusOK, rec.Code)
95+
96+
var response dtos.Recommendation
97+
assert.NoError(t, json.Unmarshal(rec.Body.Bytes(), &response))
98+
assert.Equal(t, "", response.RecommendedVersion)
99+
depVulnRepo.AssertExpectations(t)
100+
})
101+
102+
t.Run("returns bad request when package name params are missing", func(t *testing.T) {
103+
depVulnRepo := mocks.NewDependencyVulnRepository(t)
104+
controller := buildController(t, depVulnRepo)
105+
106+
req := httptest.NewRequest(http.MethodGet, "/dependency_vuln/recommendation?packageValue=1.2.3", nil)
107+
rec := httptest.NewRecorder()
108+
ctx := NewContext(req, rec)
109+
110+
err := controller.GetRecommendation(ctx)
111+
httpErr, ok := err.(*echo.HTTPError)
112+
assert.True(t, ok)
113+
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
114+
assert.Equal(t, "missing packageName or depName", httpErr.Message)
115+
depVulnRepo.AssertNotCalled(t, "GetDirectDependencyFixedVersionByPackageName", mock.Anything, mock.Anything, mock.Anything)
116+
})
117+
118+
t.Run("returns bad request when current version params are missing", func(t *testing.T) {
119+
depVulnRepo := mocks.NewDependencyVulnRepository(t)
120+
controller := buildController(t, depVulnRepo)
121+
122+
req := httptest.NewRequest(http.MethodGet, "/dependency_vuln/recommendation?packageName=react", nil)
123+
rec := httptest.NewRecorder()
124+
ctx := NewContext(req, rec)
125+
126+
err := controller.GetRecommendation(ctx)
127+
httpErr, ok := err.(*echo.HTTPError)
128+
assert.True(t, ok)
129+
assert.Equal(t, http.StatusBadRequest, httpErr.Code)
130+
assert.Equal(t, "missing packageValue or currentValue", httpErr.Message)
131+
depVulnRepo.AssertNotCalled(t, "GetDirectDependencyFixedVersionByPackageName", mock.Anything, mock.Anything, mock.Anything)
132+
})
133+
}
134+
26135
func TestDependencyVulnControllerCreateEvent(t *testing.T) {
27136
os.Setenv("FRONTEND_URL", "http://localhost:3000")
28137

0 commit comments

Comments
 (0)