ubon
Version:
Security scanner for AI-generated React/Next.js and Python apps. Catches hardcoded secrets, accessibility issues, and vulnerabilities that traditional linters miss.
114 lines (113 loc) • 4.11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectSuppressions = detectSuppressions;
exports.applySuppressions = applySuppressions;
exports.filterSuppressedResults = filterSuppressedResults;
const fs_1 = require("fs");
/**
* Detects inline suppression comments in a file
* Supports formats:
* - // ubon-disable-next-line RULEID
* - // ubon-disable-next-line RULEID reason goes here
* - comment: ubon-disable-next-line RULEID
* - comment: ubon-disable-next-line RULEID reason goes here
*/
function detectSuppressions(filePath) {
try {
const content = (0, fs_1.readFileSync)(filePath, 'utf8');
const lines = content.split('\n');
const suppressions = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const lineNumber = i + 1;
// Match both // and /* */ style comments
const patterns = [
// Single line: // ubon-disable-next-line RULEID optional reason
/\/\/\s*ubon-disable-next-line\s+([A-Z0-9]+)(?:\s+(.+))?$/,
// Multi line: /* ubon-disable-next-line RULEID optional reason */
/\/\*\s*ubon-disable-next-line\s+([A-Z0-9]+)(?:\s+([^*]+))?\s*\*\//
];
for (const pattern of patterns) {
const match = line.match(pattern);
if (match) {
const ruleId = match[1];
const reason = match[2]?.trim();
suppressions.push({
ruleId,
reason,
line: lineNumber
});
break; // Only one suppression per line
}
}
}
return suppressions;
}
catch (error) {
// File doesn't exist or can't be read
return [];
}
}
/**
* Applies suppressions to scan results
*/
function applySuppressions(results) {
const suppressionCache = new Map();
return results.map(result => {
if (!result.file || !result.line) {
return result;
}
// Cache suppressions per file
// Try both the relative and absolute path
const filePath = result.file;
let cacheKey = filePath;
if (!suppressionCache.has(cacheKey)) {
// Try to resolve the file path - could be relative or absolute
let suppressions = [];
try {
suppressions = detectSuppressions(filePath);
}
catch (error) {
// If direct path fails, try with current working directory
try {
const path = require('path');
const fullPath = path.resolve(filePath);
suppressions = detectSuppressions(fullPath);
}
catch (error2) {
suppressions = [];
}
}
suppressionCache.set(cacheKey, suppressions);
}
const suppressions = suppressionCache.get(cacheKey);
// Check if this result is suppressed
// Look for suppression on the line before the issue
const suppressionLine = result.line - 1;
const suppression = suppressions.find(s => s.line === suppressionLine &&
(s.ruleId === result.ruleId || s.ruleId === 'ALL'));
if (suppression) {
return {
...result,
suppressed: true,
suppressionReason: suppression.reason
};
}
return result;
});
}
/**
* Filters results based on suppression options
*/
function filterSuppressedResults(results, options) {
if (options.ignoreSuppressed) {
// Completely ignore suppressed results
return results.filter(r => !r.suppressed);
}
if (options.showSuppressed) {
// Show all results including suppressed ones
return results;
}
// Default: hide suppressed results but include them in counts
return results.filter(r => !r.suppressed);
}