Skip to content

Commit 69fa1c7

Browse files
Array Fleetcursoragent
andcommitted
fix: reject null credits and cweIds on advisory create/update
Peer review follow-up: null optional fields no longer bypass the update guard or produce silent no-op PATCH bodies. Adds handler and parser tests for null vulnerabilities on create and null credits/cweIds on update. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent f45c7a3 commit 69fa1c7

2 files changed

Lines changed: 104 additions & 3 deletions

File tree

pkg/github/security_advisories_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,39 @@ func Test_CreateRepositorySecurityAdvisory(t *testing.T) {
768768
expectError: true,
769769
expectedErrMsg: "invalid vulnerabilities: at least one vulnerability must be provided",
770770
},
771+
{
772+
name: "reject null vulnerabilities",
773+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
774+
PostReposSecurityAdvisoriesByOwnerByRepo: mockResponse(t, http.StatusCreated, mockAdvisory),
775+
}),
776+
requestArgs: map[string]any{
777+
"owner": "octo",
778+
"repo": "hello-world",
779+
"summary": "Stored XSS in Core",
780+
"description": "A stored XSS vulnerability in Core.",
781+
"severity": "high",
782+
"vulnerabilities": nil,
783+
},
784+
expectError: true,
785+
expectedErrMsg: "invalid vulnerabilities: at least one vulnerability must be provided",
786+
},
787+
{
788+
name: "reject null credits",
789+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
790+
PostReposSecurityAdvisoriesByOwnerByRepo: mockResponse(t, http.StatusCreated, mockAdvisory),
791+
}),
792+
requestArgs: map[string]any{
793+
"owner": "octo",
794+
"repo": "hello-world",
795+
"summary": "Stored XSS in Core",
796+
"description": "A stored XSS vulnerability in Core.",
797+
"severity": "high",
798+
"vulnerabilities": sampleAdvisoryVulnerabilities(),
799+
"credits": nil,
800+
},
801+
expectError: true,
802+
expectedErrMsg: "invalid credits: value must not be null",
803+
},
771804
{
772805
name: "API error handling",
773806
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
@@ -988,6 +1021,34 @@ func Test_UpdateRepositorySecurityAdvisory(t *testing.T) {
9881021
expectError: true,
9891022
expectedErrMsg: "invalid vulnerabilities: at least one vulnerability must be provided",
9901023
},
1024+
{
1025+
name: "reject null credits only",
1026+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
1027+
PatchReposSecurityAdvisoriesByOwnerByRepoByGhsaID: mockResponse(t, http.StatusOK, mockAdvisory),
1028+
}),
1029+
requestArgs: map[string]any{
1030+
"owner": "octo",
1031+
"repo": "hello-world",
1032+
"ghsaId": "GHSA-xxxx-xxxx-xxxx",
1033+
"credits": nil,
1034+
},
1035+
expectError: true,
1036+
expectedErrMsg: "invalid credits: value must not be null",
1037+
},
1038+
{
1039+
name: "reject null cweIds only",
1040+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
1041+
PatchReposSecurityAdvisoriesByOwnerByRepoByGhsaID: mockResponse(t, http.StatusOK, mockAdvisory),
1042+
}),
1043+
requestArgs: map[string]any{
1044+
"owner": "octo",
1045+
"repo": "hello-world",
1046+
"ghsaId": "GHSA-xxxx-xxxx-xxxx",
1047+
"cweIds": nil,
1048+
},
1049+
expectError: true,
1050+
expectedErrMsg: "invalid cweIds: value must not be null",
1051+
},
9911052
{
9921053
name: "successful update with credits and cweIds",
9931054
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
@@ -1374,6 +1435,32 @@ func Test_ParseAdvisoryCredits(t *testing.T) {
13741435
require.Error(t, err)
13751436
assert.Contains(t, err.Error(), `credits[0].type "invalid-type" is invalid`)
13761437
})
1438+
1439+
t.Run("null credits rejected", func(t *testing.T) {
1440+
_, err := parseAdvisoryCredits(map[string]any{
1441+
"credits": nil,
1442+
}, "credits")
1443+
require.Error(t, err)
1444+
assert.Contains(t, err.Error(), "invalid credits: value must not be null")
1445+
})
1446+
}
1447+
1448+
func Test_ParseAdvisoryCWEIDs(t *testing.T) {
1449+
t.Run("valid cweIds", func(t *testing.T) {
1450+
cweIDs, err := parseAdvisoryCWEIDs(map[string]any{
1451+
"cweIds": []any{"CWE-79"},
1452+
}, "cweIds")
1453+
require.NoError(t, err)
1454+
assert.Equal(t, []string{"CWE-79"}, cweIDs)
1455+
})
1456+
1457+
t.Run("null cweIds rejected", func(t *testing.T) {
1458+
_, err := parseAdvisoryCWEIDs(map[string]any{
1459+
"cweIds": nil,
1460+
}, "cweIds")
1461+
require.Error(t, err)
1462+
assert.Contains(t, err.Error(), "invalid cweIds: value must not be null")
1463+
})
13771464
}
13781465

13791466
func Test_validateSeverityOrCVSS(t *testing.T) {

pkg/github/security_advisories_write.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,25 @@ func parseAdvisoryVulnerabilities(args map[string]any, param string, required bo
190190
return vulns, nil
191191
}
192192

193+
func parseAdvisoryCWEIDs(args map[string]any, param string) ([]string, error) {
194+
raw, ok := args[param]
195+
if !ok {
196+
return nil, nil
197+
}
198+
if raw == nil {
199+
return nil, fmt.Errorf("invalid %s: value must not be null", param)
200+
}
201+
return OptionalStringArrayParam(args, param)
202+
}
203+
193204
func parseAdvisoryCredits(args map[string]any, param string) ([]advisoryCreditRequest, error) {
194205
raw, ok := args[param]
195-
if !ok || raw == nil {
206+
if !ok {
196207
return nil, nil
197208
}
209+
if raw == nil {
210+
return nil, fmt.Errorf("invalid %s: value must not be null", param)
211+
}
198212

199213
data, err := json.Marshal(raw)
200214
if err != nil {
@@ -389,7 +403,7 @@ func CreateRepositorySecurityAdvisory(t translations.TranslationHelperFunc) inve
389403
if err != nil {
390404
return utils.NewToolResultError(err.Error()), nil, nil
391405
}
392-
cweIDs, err := OptionalStringArrayParam(args, "cweIds")
406+
cweIDs, err := parseAdvisoryCWEIDs(args, "cweIds")
393407
if err != nil {
394408
return utils.NewToolResultError(err.Error()), nil, nil
395409
}
@@ -561,7 +575,7 @@ func UpdateRepositorySecurityAdvisory(t translations.TranslationHelperFunc) inve
561575
if err != nil {
562576
return utils.NewToolResultError(err.Error()), nil, nil
563577
}
564-
cweIDs, err := OptionalStringArrayParam(args, "cweIds")
578+
cweIDs, err := parseAdvisoryCWEIDs(args, "cweIds")
565579
if err != nil {
566580
return utils.NewToolResultError(err.Error()), nil, nil
567581
}

0 commit comments

Comments
 (0)