UNPKG

ubon

Version:

Security scanner for AI-generated apps (Cursor, Lovable, Windsurf, v0). Catches hardcoded secrets, prompt injection, hallucinated imports, Server Actions / Edge runtime mistakes, and the vibe-coded vulnerabilities traditional linters miss.

74 lines 3.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AccessibilityScanner = void 0; const base_scanner_1 = require("./base-scanner"); const rules_1 = require("../rules"); class AccessibilityScanner extends base_scanner_1.BaseScanner { name = 'Accessibility Scanner'; ruleIds = ['A11Y001', 'A11Y002', 'A11Y003', 'A11Y004', 'A11Y005', 'A11Y006', 'A11Y007', 'NEXT005', 'NEXT001', 'NEXT002']; async scan(options) { const results = []; const rules = this.ruleIds.map((id) => (0, rules_1.getRule)(id)).filter(Boolean); for await (const ctx of this.iterateFiles(options, '**/*.{js,jsx,ts,tsx,svelte,astro,html}', ['node_modules/**', 'dist/**', 'build/**', '.next/**', 'examples/**'])) { const fileExt = ctx.file.split('.').pop()?.toLowerCase(); if (this.hasFileSuppression(ctx.lines)) continue; for (const rule of rules) { if (!rule) continue; if (rule.impl.fileTypes && !rule.impl.fileTypes.includes(fileExt || '')) continue; if (rule.impl.detect) { const detectionResults = rule.impl.detect(ctx.content, ctx.file, ctx.lines); for (const detection of detectionResults) { if (this.isSuppressed(ctx.lines, detection.line - 1, rule.meta.id)) continue; results.push(this.createResult({ type: rule.meta.severity === 'high' ? 'error' : 'warning', category: rule.meta.category, message: rule.meta.message, file: ctx.file, line: detection.line, severity: rule.meta.severity, ruleId: rule.meta.id, confidence: detection.confidence || 0.8, confidenceReason: detection.confidenceReason || `Accessibility issue detected by ${rule.meta.id} rule`, fix: rule.meta.fix, match: detection.match, ...(detection.fixEdits ? { fixEdits: detection.fixEdits } : {}) }, ctx.lines[detection.line - 1])); } } if (rule.impl.patterns) { for (const pattern of rule.impl.patterns) { ctx.lines.forEach((line, index) => { if (line.trim().startsWith('//') || line.trim().startsWith('*')) return; if (this.isSuppressed(ctx.lines, index, pattern.ruleId)) return; const match = line.match(pattern.pattern); if (!match) return; results.push(this.createResult({ type: pattern.severity === 'high' ? 'error' : 'warning', category: rule.meta.category, message: pattern.message, file: ctx.file, line: index + 1, severity: pattern.severity, ruleId: pattern.ruleId, confidence: pattern.confidence, confidenceReason: `Pattern match: ${pattern.message}`, fix: pattern.fix, match: match[0]?.slice(0, 200) }, line)); }); } } } } return results; } } exports.AccessibilityScanner = AccessibilityScanner; //# sourceMappingURL=accessibility-scanner.js.map