Skip to content

Commit fd53415

Browse files
committed
fix(security-sync): accept nullable dependabot fields
1 parent dd68e11 commit fd53415

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

services/security-sync/src/sync.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,41 @@ function stubFetch(response: Response | (() => Response)) {
7373
return fetchStub;
7474
}
7575

76+
function createDependabotAlert(overrides: Record<string, unknown> = {}) {
77+
return {
78+
number: 23,
79+
state: 'open',
80+
dependency: {
81+
package: { ecosystem: 'npm', name: 'lodash' },
82+
manifest_path: 'package.json',
83+
scope: 'runtime',
84+
},
85+
security_advisory: {
86+
ghsa_id: 'GHSA-1234-5678-90ab',
87+
cve_id: null,
88+
summary: 'Prototype pollution in lodash',
89+
description: 'A vulnerable lodash version allows prototype pollution.',
90+
severity: 'high',
91+
cvss: { score: 7.5, vector_string: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H' },
92+
cwes: [{ cwe_id: 'CWE-1321', name: 'Improperly Controlled Modification' }],
93+
},
94+
security_vulnerability: {
95+
vulnerable_version_range: '< 4.17.21',
96+
first_patched_version: { identifier: '4.17.21' },
97+
},
98+
created_at: '2026-05-18T10:00:00Z',
99+
updated_at: '2026-05-18T10:00:00Z',
100+
fixed_at: null,
101+
dismissed_at: null,
102+
dismissed_by: null,
103+
dismissed_reason: null,
104+
dismissed_comment: null,
105+
html_url: 'https://github.com/acme/widgets/security/dependabot/23',
106+
url: 'https://api.github.com/repos/acme/widgets/dependabot/alerts/23',
107+
...overrides,
108+
};
109+
}
110+
76111
describe('selectRepositoriesForSync', () => {
77112
it('allows a manual repository command to target an accessible repo outside configured sync selection', () => {
78113
const repositories = selectRepositoriesForSync(
@@ -91,6 +126,25 @@ describe('selectRepositoriesForSync', () => {
91126
});
92127

93128
describe('Worker GitHub auth-invalid sync', () => {
129+
it('accepts Dependabot alerts with nullable advisory fields', async () => {
130+
const alert = createDependabotAlert({
131+
security_advisory: {
132+
...createDependabotAlert().security_advisory,
133+
cvss: { score: 7.5, vector_string: null },
134+
},
135+
security_vulnerability: {
136+
vulnerable_version_range: '< 4.17.21',
137+
first_patched_version: null,
138+
},
139+
});
140+
stubFetch(new Response(JSON.stringify([alert]), { status: 200 }));
141+
142+
await expect(fetchAllDependabotAlerts('github-token', 'acme', 'widgets')).resolves.toEqual({
143+
status: 'success',
144+
alerts: [alert],
145+
});
146+
});
147+
94148
it('classifies a direct GitHub 401 as auth_invalid', async () => {
95149
stubFetch(new Response('Bad credentials', { status: 401 }));
96150

services/security-sync/src/sync.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@ const dependabotAlertRawSchema = z.object({
5454
summary: z.string(),
5555
description: z.string(),
5656
severity: securitySeveritySchema,
57-
cvss: z.object({ score: z.number(), vector_string: z.string() }).optional(),
57+
cvss: z.object({ score: z.number(), vector_string: z.string().nullable() }).optional(),
5858
cwes: z.array(z.object({ cwe_id: z.string(), name: z.string() })).optional(),
5959
}),
6060
security_vulnerability: z.object({
6161
vulnerable_version_range: z.string(),
62-
first_patched_version: z.object({ identifier: z.string() }).optional(),
62+
first_patched_version: z.object({ identifier: z.string() }).nullable().optional(),
6363
}),
6464
created_at: z.string().datetime(),
6565
updated_at: z.string().datetime(),

0 commit comments

Comments
 (0)