← ubon
import { ScanResult } from '../types';
import { RULES } from '../rules';
import { redact } from './redact';
import pkg from '../../package.json';
import { createHash } from 'crypto';
function synthesizeFingerprint(r: ScanResult): string {
return createHash('sha1')
.update([r.ruleId, r.file || '', r.line || 0, r.match || r.message].join('|'))
.digest('hex')
.slice(0, 16);
}
interface SarifLog {
$schema: string;
version: string;
runs: Array<{
tool: { driver: { name: string; informationUri?: string; rules?: any[] } };
results: any[];
}>;
}
export function toSarif(results: ScanResult[], _repoRoot: string): SarifLog {
const rulesMap = new Map<string, any>();
const sarifResults = results.map((r) => {
if (!rulesMap.has(r.ruleId)) {
const meta = (RULES as any)[r.ruleId];
rulesMap.set(r.ruleId, {
id: r.ruleId,
name: r.ruleId,
shortDescription: { text: r.message.slice(0, 64) },
fullDescription: { text: r.message },
properties: {
category: r.category,
severity: r.severity,
confidence: r.confidence,
},
defaultConfiguration: {
level: r.type === 'error' ? 'error' : r.type === 'warning' ? 'warning' : 'note',
},
help: { text: r.fix || (meta?.fix || '') },
helpUri: meta?.helpUri,
});
}
const level = r.type === 'error' ? 'error' : r.type === 'warning' ? 'warning' : 'note';
return {
ruleId: r.ruleId,
level,
message: { text: r.message },
locations: r.file
? [
{
physicalLocation: {
artifactLocation: { uri: normalizePath(r.file) },
region: r.range
? {
startLine: r.range.startLine,
startColumn: r.range.startColumn,
endLine: r.range.endLine,
endColumn: r.range.endColumn,
}
: r.line
? { startLine: r.line }
: undefined,
},
},
]
: [],
properties: {
category: r.category,
severity: r.severity,
confidence: r.confidence,
fingerprint: r.fingerprint,
match: redact(r.match),
fix: r.fix,
},
partialFingerprints: { "ubon/fingerprint": r.fingerprint || synthesizeFingerprint(r) },
};
});
const sarif: SarifLog = {
$schema: 'https://json.schemastore.org/sarif-2.1.0.json',
version: '2.1.0',
runs: [
{
tool: {
driver: {
name: 'ubon',
// @ts-ignore version is allowed in SARIF driver
version: (pkg as any).version,
informationUri: 'https://github.com/luisfer/ubon',
rules: Array.from(rulesMap.values()),
},
},
results: sarifResults,
},
],
};
return sarif;
}
function normalizePath(p: string): string {
// Keep relative paths for SARIF consumers
return p.replace(/\\/g, '/');
}