Skip to content
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 44 additions & 5 deletions server/test/src/tools/sarif-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ function createTestSarif() {
{ location: { physicalLocation: { artifactLocation: { uri: 'src/db.js' }, region: { startLine: 42 } }, message: { text: 'query(...)' } } },
] }] }],
},
{
ruleId: 'js/sql-injection',
ruleIndex: 0,
message: { text: 'SQL injection from request body.' },
locations: [{ physicalLocation: { artifactLocation: { uri: 'src/api.js' }, region: { startLine: 15, startColumn: 3, endColumn: 40 } } }],
},
{
ruleId: 'js/xss',
ruleIndex: 1,
Expand All @@ -64,6 +70,25 @@ function createTestSarif() {
};
}

/** SARIF with a defined rule but zero results β€” validates resultCount: 0 */
function createZeroResultsSarif() {
return {
version: '2.1.0',
runs: [{
tool: {
driver: {
name: 'CodeQL',
version: '2.25.1',
rules: [
{ id: 'js/unused-variable', shortDescription: { text: 'Unused variable' } },
],
},
},
results: [],
}],
};
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -170,7 +195,7 @@ describe('SARIF Tools', () => {
const parsed = JSON.parse(result.content[0].text);

expect(parsed.ruleId).toBe('js/sql-injection');
expect(parsed.resultCount).toBe(1);
expect(parsed.resultCount).toBe(2);
expect(parsed.extractedSarif.runs[0].tool.driver.rules).toHaveLength(1);
});

Expand Down Expand Up @@ -212,15 +237,29 @@ describe('SARIF Tools', () => {
});

describe('sarif_list_rules', () => {
it('should list all rules with result counts', async () => {
it('should list all rules with per-rule result counts', async () => {
const result = await handlers.sarif_list_rules({ sarifPath: testSarifPath });
const parsed = JSON.parse(result.content[0].text);

expect(parsed.totalRules).toBe(2);
expect(parsed.totalResults).toBe(2);
expect(parsed.totalResults).toBe(3);
expect(parsed.rules[0].ruleId).toBe('js/sql-injection');
expect(parsed.rules[0].resultCount).toBe(1);
expect(parsed.rules[0].resultCount).toBe(2);
expect(parsed.rules[1].ruleId).toBe('js/xss');
expect(parsed.rules[1].resultCount).toBe(1);
});

it('should return resultCount 0 for rules with no results', async () => {
const noResultsPath = join(testStorageDir, 'no-results.sarif');
writeFileSync(noResultsPath, JSON.stringify(createZeroResultsSarif()));

const result = await handlers.sarif_list_rules({ sarifPath: noResultsPath });
const parsed = JSON.parse(result.content[0].text);

expect(parsed.totalRules).toBe(1);
expect(parsed.totalResults).toBe(0);
expect(parsed.rules[0].ruleId).toBe('js/unused-variable');
expect(parsed.rules[0].resultCount).toBe(0);
});
});

Expand Down Expand Up @@ -303,7 +342,7 @@ describe('SARIF Tools', () => {

it('should detect changed result counts', async () => {
const sarifB = createTestSarif();
sarifB.runs[0].results = [sarifB.runs[0].results[0]]; // remove XSS result
sarifB.runs[0].results = sarifB.runs[0].results.filter(r => r.ruleId !== 'js/xss');
const pathB = join(testStorageDir, 'modified.sarif');
writeFileSync(pathB, JSON.stringify(sarifB));

Expand Down
Loading