Skip to content

Commit a2f8099

Browse files
author
advancedresearcharray
committed
fix: validate severity/cvss mutual exclusivity for security advisories
GitHub's create advisory API requires exactly one of severity or cvss_vector_string. Reject invalid combinations at the MCP layer with clear errors, and add regression tests.
1 parent c332b58 commit a2f8099

2 files changed

Lines changed: 34 additions & 4 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,12 +1362,12 @@ The following sets of tools are available:
13621362
- **Accepted OAuth Scopes**: `repo`, `security_events`
13631363
- `credits`: Users credited for the advisory. (object[], optional)
13641364
- `cveId`: The CVE ID to assign to the advisory. (string, optional)
1365-
- `cvssVectorString`: The CVSS vector string for the advisory. (string, optional)
1365+
- `cvssVectorString`: The CVSS vector string for the advisory. Exactly one of severity or cvssVectorString is required. (string, optional)
13661366
- `cweIds`: Common Weakness Enumeration IDs (for example, ["CWE-79"]). (string[], optional)
13671367
- `description`: A detailed description of the security advisory. (string, required)
13681368
- `owner`: The owner of the repository. (string, required)
13691369
- `repo`: The name of the repository. (string, required)
1370-
- `severity`: The severity of the advisory. (string, optional)
1370+
- `severity`: The severity of the advisory. Exactly one of severity or cvssVectorString is required. (string, optional)
13711371
- `startPrivateFork`: Whether to create a temporary private fork for collaborating on a fix. (boolean, optional)
13721372
- `summary`: A short summary of the security advisory. (string, required)
13731373
- `vulnerabilities`: Affected products and version ranges. (object[], required)
@@ -1421,13 +1421,13 @@ The following sets of tools are available:
14211421
- **Accepted OAuth Scopes**: `repo`, `security_events`
14221422
- `credits`: Users credited for the advisory. (object[], optional)
14231423
- `cveId`: The CVE ID to assign to the advisory. (string, optional)
1424-
- `cvssVectorString`: The CVSS vector string for the advisory. (string, optional)
1424+
- `cvssVectorString`: The CVSS vector string for the advisory. Cannot be set together with severity. (string, optional)
14251425
- `cweIds`: Common Weakness Enumeration IDs (for example, ["CWE-79"]). (string[], optional)
14261426
- `description`: A detailed description of the security advisory. (string, optional)
14271427
- `ghsaId`: GitHub Security Advisory ID (format: GHSA-xxxx-xxxx-xxxx). (string, required)
14281428
- `owner`: The owner of the repository. (string, required)
14291429
- `repo`: The name of the repository. (string, required)
1430-
- `severity`: The severity of the advisory. (string, optional)
1430+
- `severity`: The severity of the advisory. Cannot be set together with cvssVectorString. (string, optional)
14311431
- `state`: The advisory state. Set to "published" to publish the advisory. (string, optional)
14321432
- `summary`: A short summary of the security advisory. (string, optional)
14331433
- `vulnerabilities`: Affected products and version ranges. (object[], optional)

pkg/github/security_advisories_write_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ func Test_CreateRepositorySecurityAdvisory(t *testing.T) {
9393
expectError: false,
9494
expectedAdvisory: mockAdvisory,
9595
},
96+
{
97+
name: "successful advisory creation with cvss only",
98+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
99+
PostReposSecurityAdvisoriesByOwnerByRepo: expectRequestBody(t, map[string]any{
100+
"summary": "Stored XSS in Core",
101+
"description": "A stored XSS vulnerability in Core.",
102+
"cvss_vector_string": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
103+
"vulnerabilities": []any{
104+
map[string]any{
105+
"package": map[string]any{
106+
"ecosystem": "npm",
107+
"name": "example-package",
108+
},
109+
"vulnerable_version_range": "< 2.0.0",
110+
"patched_versions": "2.0.0",
111+
},
112+
},
113+
}).andThen(mockResponse(t, http.StatusCreated, mockAdvisory)),
114+
}),
115+
requestArgs: map[string]any{
116+
"owner": "octo",
117+
"repo": "hello-world",
118+
"summary": "Stored XSS in Core",
119+
"description": "A stored XSS vulnerability in Core.",
120+
"cvssVectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
121+
"vulnerabilities": sampleAdvisoryVulnerabilities(),
122+
},
123+
expectError: false,
124+
expectedAdvisory: mockAdvisory,
125+
},
96126
{
97127
name: "missing required summary",
98128
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{

0 commit comments

Comments
 (0)