@aspect-guard/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +395 -0
- package/dist/index.js +1565 -0
- package/dist/index.js.map +1 -0
- package/package.json +37 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types/severity.ts","../src/scanner/scanner.ts","../src/scanner/ide-detector.ts","../src/scanner/extension-reader.ts","../src/scanner/file-collector.ts","../src/rules/rule-registry.ts","../src/rules/rule-engine.ts","../src/rules/built-in/crit-data-exfiltration.ts","../src/rules/built-in/crit-remote-execution.ts","../src/rules/built-in/crit-credential-access.ts","../src/rules/built-in/high-suspicious-network.ts","../src/rules/built-in/high-obfuscated-code.ts","../src/rules/built-in/high-hardcoded-secret.ts","../src/rules/built-in/med-excessive-activation.ts","../src/rules/built-in/index.ts","../src/reporter/json-reporter.ts","../src/reporter/sarif-reporter.ts","../src/reporter/markdown-reporter.ts","../src/policy/policy-loader.ts","../src/policy/policy-engine.ts","../src/index.ts"],"sourcesContent":["export type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';\n\nexport type RiskLevel = 'critical' | 'high' | 'medium' | 'low' | 'safe';\n\nexport const SEVERITY_ORDER: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n};\n\nexport function compareSeverity(a: Severity, b: Severity): number {\n return SEVERITY_ORDER[a] - SEVERITY_ORDER[b];\n}\n\nexport function isAtLeastSeverity(\n severity: Severity,\n minimum: Severity\n): boolean {\n return SEVERITY_ORDER[severity] <= SEVERITY_ORDER[minimum];\n}\n","import * as os from 'node:os';\nimport { randomUUID } from 'node:crypto';\nimport type {\n ScanOptions,\n FullScanReport,\n ScanResult,\n ScanSummary,\n RiskLevel,\n Severity,\n FindingCategory,\n DetectedIDE,\n ExtensionManifest,\n} from '../types/index.js';\nimport { detectIDEPaths } from './ide-detector.js';\nimport { readExtensionsFromDirectory } from './extension-reader.js';\nimport { collectFiles } from './file-collector.js';\nimport { VERSION } from '../index.js';\nimport { RuleEngine } from '../rules/rule-engine.js';\nimport { registerBuiltInRules } from '../rules/built-in/index.js';\n\n// Register built-in rules once at module load\nlet rulesRegistered = false;\nfunction ensureRulesRegistered(): void {\n if (!rulesRegistered) {\n registerBuiltInRules();\n rulesRegistered = true;\n }\n}\n\nconst DEFAULT_OPTIONS: Required<ScanOptions> = {\n idePaths: [],\n autoDetect: true,\n severity: 'info',\n rules: [],\n skipRules: [],\n concurrency: 4,\n timeout: 30000,\n};\n\nconst SEVERITY_PENALTY: Record<Severity, number> = {\n critical: 35,\n high: 18,\n medium: 8,\n low: 3,\n info: 1,\n};\n\nexport class ExtensionGuardScanner {\n private options: Required<ScanOptions>;\n private ruleEngine: RuleEngine;\n\n constructor(options?: Partial<ScanOptions>) {\n ensureRulesRegistered();\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.ruleEngine = new RuleEngine({\n rules: this.options.rules.length > 0 ? this.options.rules : undefined,\n skipRules: this.options.skipRules.length > 0 ? this.options.skipRules : undefined,\n minSeverity: this.options.severity,\n });\n }\n\n async scan(options?: Partial<ScanOptions>): Promise<FullScanReport> {\n const startTime = Date.now();\n const mergedOptions = { ...this.options, ...options };\n\n // Detect IDE paths\n let ides: DetectedIDE[];\n if (mergedOptions.autoDetect && mergedOptions.idePaths.length === 0) {\n ides = detectIDEPaths();\n } else {\n ides = mergedOptions.idePaths.map((p) => ({\n name: 'Custom',\n path: p,\n extensionCount: 0,\n }));\n }\n\n // Collect all extensions\n const allExtensions = await Promise.all(\n ides.map((ide) => readExtensionsFromDirectory(ide.path))\n );\n\n const extensionMap = new Map<string, { ide: DetectedIDE; ext: Awaited<ReturnType<typeof readExtensionsFromDirectory>>[number] }>();\n for (let i = 0; i < ides.length; i++) {\n const ide = ides[i]!;\n for (const ext of allExtensions[i]!) {\n if (!extensionMap.has(ext.id)) {\n extensionMap.set(ext.id, { ide, ext });\n }\n }\n // Update extension count\n ide.extensionCount = allExtensions[i]!.length;\n }\n\n // Scan each extension\n const results: ScanResult[] = [];\n for (const { ext } of extensionMap.values()) {\n const result = await this.scanExtension(ext);\n results.push(result);\n }\n\n // Calculate summary\n const summary = this.calculateSummary(results);\n\n return {\n scanId: randomUUID(),\n version: VERSION,\n timestamp: new Date().toISOString(),\n environment: {\n os: `${os.platform()} ${os.release()}`,\n ides,\n },\n totalExtensions: Array.from(allExtensions).reduce((sum, arr) => sum + arr.length, 0),\n uniqueExtensions: extensionMap.size,\n results,\n summary,\n scanDurationMs: Date.now() - startTime,\n };\n }\n\n private async scanExtension(\n ext: Awaited<ReturnType<typeof readExtensionsFromDirectory>>[number]\n ): Promise<ScanResult> {\n const startTime = Date.now();\n const files = await collectFiles(ext.installPath);\n\n // Parse manifest for rule engine\n const manifestContent = files.get('package.json');\n let manifest: ExtensionManifest = {\n name: ext.id.split('.')[1] || ext.id,\n publisher: ext.publisher.name,\n version: ext.version,\n };\n if (manifestContent) {\n try {\n manifest = JSON.parse(manifestContent);\n } catch {\n // Use default manifest\n }\n }\n\n // Run rules\n const findings = this.ruleEngine.run(files, manifest);\n\n // Calculate trust score\n const trustScore = this.calculateTrustScore(findings);\n const riskLevel = this.calculateRiskLevel(trustScore, findings);\n\n return {\n extensionId: ext.id,\n displayName: ext.displayName,\n version: ext.version,\n trustScore,\n riskLevel,\n findings,\n metadata: ext,\n analyzedFiles: files.size,\n scanDurationMs: Date.now() - startTime,\n };\n }\n\n private calculateTrustScore(findings: ScanResult['findings']): number {\n let score = 100;\n\n // Apply penalties per finding\n for (const finding of findings) {\n score -= SEVERITY_PENALTY[finding.severity];\n }\n\n // Clamp to [0, 100]\n return Math.max(0, Math.min(100, score));\n }\n\n private calculateRiskLevel(trustScore: number, findings: ScanResult['findings']): RiskLevel {\n // If any critical finding, always critical\n if (findings.some((f) => f.severity === 'critical')) {\n return 'critical';\n }\n // If any high finding, at least high\n if (findings.some((f) => f.severity === 'high')) {\n return 'high';\n }\n\n // Otherwise, base on trust score\n if (trustScore >= 90) return 'safe';\n if (trustScore >= 70) return 'low';\n if (trustScore >= 45) return 'medium';\n if (trustScore >= 20) return 'high';\n return 'critical';\n }\n\n private calculateSummary(results: ScanResult[]): ScanSummary {\n const byRiskLevel: Record<RiskLevel, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n safe: 0,\n };\n\n const bySeverity: Record<Severity, number> = {\n critical: 0,\n high: 0,\n medium: 0,\n low: 0,\n info: 0,\n };\n\n const byCategory: Partial<Record<FindingCategory, number>> = {};\n\n for (const result of results) {\n byRiskLevel[result.riskLevel]++;\n\n for (const finding of result.findings) {\n bySeverity[finding.severity]++;\n byCategory[finding.category] = (byCategory[finding.category] ?? 0) + 1;\n }\n }\n\n // Collect top findings (sorted by severity)\n const allFindings = results.flatMap((r) => r.findings);\n const severityOrder: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n };\n const topFindings = allFindings\n .sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity])\n .slice(0, 10);\n\n // Calculate overall health score\n const totalExtensions = results.length;\n const safeCount = byRiskLevel.safe + byRiskLevel.low;\n const overallHealthScore = totalExtensions > 0\n ? Math.round((safeCount / totalExtensions) * 100)\n : 100;\n\n return {\n byRiskLevel,\n bySeverity,\n byCategory,\n topFindings,\n overallHealthScore,\n };\n }\n}\n","import * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport type { DetectedIDE } from '../types/index.js';\n\nexport const IDE_PATHS: Record<string, string[]> = {\n 'VS Code': ['~/.vscode/extensions'],\n 'VS Code Insiders': ['~/.vscode-insiders/extensions'],\n Cursor: ['~/.cursor/extensions'],\n Windsurf: ['~/.windsurf/extensions'],\n Trae: ['~/.trae/extensions'],\n VSCodium: ['~/.vscode-oss/extensions'],\n};\n\nexport function expandPath(inputPath: string): string {\n if (inputPath.startsWith('~')) {\n return path.join(os.homedir(), inputPath.slice(1));\n }\n if (inputPath.includes('%USERPROFILE%')) {\n return inputPath.replace('%USERPROFILE%', os.homedir());\n }\n return inputPath;\n}\n\nfunction countExtensions(dirPath: string): number {\n try {\n const entries = fs.readdirSync(dirPath, { withFileTypes: true });\n return entries.filter((entry) => entry.isDirectory()).length;\n } catch {\n return 0;\n }\n}\n\nexport function detectIDEPaths(): DetectedIDE[] {\n const detected: DetectedIDE[] = [];\n\n for (const [ideName, paths] of Object.entries(IDE_PATHS)) {\n for (const idePath of paths) {\n const expandedPath = expandPath(idePath);\n if (fs.existsSync(expandedPath)) {\n detected.push({\n name: ideName,\n path: expandedPath,\n extensionCount: countExtensions(expandedPath),\n });\n break;\n }\n }\n }\n\n return detected;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { ExtensionInfo, ExtensionManifest } from '../types/index.js';\n\nexport async function readExtension(\n extensionPath: string\n): Promise<ExtensionInfo | null> {\n try {\n const packageJsonPath = path.join(extensionPath, 'package.json');\n const content = await fs.readFile(packageJsonPath, 'utf-8');\n const manifest: ExtensionManifest = JSON.parse(content);\n\n if (!manifest.name || !manifest.publisher || !manifest.version) {\n return null;\n }\n\n const stats = await getDirectoryStats(extensionPath);\n\n const repository = typeof manifest.repository === 'string'\n ? manifest.repository\n : manifest.repository?.url;\n\n return {\n id: `${manifest.publisher}.${manifest.name}`,\n displayName: manifest.displayName ?? manifest.name,\n version: manifest.version,\n publisher: {\n name: manifest.publisher,\n verified: false,\n },\n description: manifest.description ?? '',\n categories: manifest.categories ?? [],\n activationEvents: manifest.activationEvents ?? [],\n extensionDependencies: manifest.extensionDependencies ?? [],\n installPath: extensionPath,\n engines: { vscode: manifest.engines?.vscode ?? '*' },\n repository,\n license: manifest.license,\n fileCount: stats.fileCount,\n totalSize: stats.totalSize,\n };\n } catch {\n return null;\n }\n}\n\nasync function getDirectoryStats(\n dirPath: string\n): Promise<{ fileCount: number; totalSize: number }> {\n let fileCount = 0;\n let totalSize = 0;\n\n async function walk(currentPath: string): Promise<void> {\n try {\n const entries = await fs.readdir(currentPath, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = path.join(currentPath, entry.name);\n if (entry.isDirectory()) {\n if (entry.name !== 'node_modules') {\n await walk(fullPath);\n }\n } else {\n fileCount++;\n try {\n const stat = await fs.stat(fullPath);\n totalSize += stat.size;\n } catch {\n // Skip files we can't stat\n }\n }\n }\n } catch {\n // Skip directories we can't read\n }\n }\n\n await walk(dirPath);\n return { fileCount, totalSize };\n}\n\nexport async function readExtensionsFromDirectory(\n directoryPath: string\n): Promise<ExtensionInfo[]> {\n const extensions: ExtensionInfo[] = [];\n\n try {\n const entries = await fs.readdir(directoryPath, { withFileTypes: true });\n const directories = entries.filter((entry) => entry.isDirectory());\n\n const results = await Promise.all(\n directories.map((dir) =>\n readExtension(path.join(directoryPath, dir.name))\n )\n );\n\n for (const result of results) {\n if (result) {\n extensions.push(result);\n }\n }\n } catch {\n return [];\n }\n\n return extensions;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nconst COLLECTED_EXTENSIONS = new Set([\n '.js',\n '.ts',\n '.jsx',\n '.tsx',\n '.mjs',\n '.cjs',\n '.json',\n]);\n\nconst IGNORED_DIRECTORIES = new Set([\n 'node_modules',\n '.git',\n '.svn',\n '.hg',\n '__pycache__',\n]);\n\nconst IGNORED_PATTERNS = [/\\.min\\.js$/, /\\.map$/, /\\.d\\.ts$/];\n\nconst MAX_FILE_SIZE = 1024 * 1024; // 1MB\n\nexport function shouldCollectFile(filePath: string): boolean {\n const ext = path.extname(filePath).toLowerCase();\n\n if (!COLLECTED_EXTENSIONS.has(ext)) {\n return false;\n }\n\n const parts = filePath.split(path.sep);\n for (const part of parts) {\n if (IGNORED_DIRECTORIES.has(part)) {\n return false;\n }\n }\n\n for (const pattern of IGNORED_PATTERNS) {\n if (pattern.test(filePath)) {\n return false;\n }\n }\n\n return true;\n}\n\nexport async function collectFiles(\n extensionPath: string\n): Promise<Map<string, string>> {\n const files = new Map<string, string>();\n\n async function walk(currentPath: string, relativePath: string): Promise<void> {\n try {\n const entries = await fs.readdir(currentPath, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentPath, entry.name);\n const relPath = relativePath\n ? path.join(relativePath, entry.name)\n : entry.name;\n\n if (entry.isDirectory()) {\n if (!IGNORED_DIRECTORIES.has(entry.name)) {\n await walk(fullPath, relPath);\n }\n } else if (entry.isFile()) {\n if (shouldCollectFile(relPath)) {\n try {\n const stat = await fs.stat(fullPath);\n if (stat.size <= MAX_FILE_SIZE) {\n const content = await fs.readFile(fullPath, 'utf-8');\n files.set(relPath, content);\n }\n } catch {\n // Skip files we can't read\n }\n }\n }\n }\n } catch {\n // Skip directories we can't access\n }\n }\n\n await walk(extensionPath, '');\n return files;\n}\n","import type { DetectionRule } from './rule.interface.js';\n\nclass RuleRegistry {\n private rules: Map<string, DetectionRule> = new Map();\n\n register(rule: DetectionRule): void {\n this.rules.set(rule.id, rule);\n }\n\n get(id: string): DetectionRule | undefined {\n return this.rules.get(id);\n }\n\n getAll(): DetectionRule[] {\n return Array.from(this.rules.values());\n }\n\n getEnabled(): DetectionRule[] {\n return this.getAll().filter((rule) => rule.enabled);\n }\n\n getByCategory(category: string): DetectionRule[] {\n return this.getAll().filter((rule) => rule.category === category);\n }\n\n getBySeverity(severity: string): DetectionRule[] {\n return this.getAll().filter((rule) => rule.severity === severity);\n }\n\n clear(): void {\n this.rules.clear();\n }\n}\n\nexport const ruleRegistry = new RuleRegistry();\n","import type { ExtensionManifest, Finding, Severity } from '../types/index.js';\nimport { SEVERITY_ORDER } from '../types/index.js';\nimport type { DetectionRule, Evidence } from './rule.interface.js';\nimport { ruleRegistry } from './rule-registry.js';\nimport { randomUUID } from 'node:crypto';\n\nexport interface RuleEngineOptions {\n rules?: string[];\n skipRules?: string[];\n minSeverity?: Severity;\n}\n\nexport class RuleEngine {\n private options: RuleEngineOptions;\n\n constructor(options: RuleEngineOptions = {}) {\n this.options = options;\n }\n\n run(\n files: Map<string, string>,\n manifest: ExtensionManifest\n ): Finding[] {\n const findings: Finding[] = [];\n const rules = this.getApplicableRules();\n\n for (const rule of rules) {\n try {\n const evidences = rule.detect(files, manifest);\n for (const evidence of evidences) {\n findings.push(this.createFinding(rule, evidence));\n }\n } catch {\n // Rule failed, continue with other rules\n }\n }\n\n return findings;\n }\n\n private getApplicableRules(): DetectionRule[] {\n let rules = ruleRegistry.getEnabled();\n\n if (this.options.rules && this.options.rules.length > 0) {\n rules = rules.filter((r) => this.options.rules!.includes(r.id));\n }\n\n if (this.options.skipRules && this.options.skipRules.length > 0) {\n rules = rules.filter((r) => !this.options.skipRules!.includes(r.id));\n }\n\n if (this.options.minSeverity) {\n const minOrder = SEVERITY_ORDER[this.options.minSeverity];\n rules = rules.filter((r) => SEVERITY_ORDER[r.severity] <= minOrder);\n }\n\n return rules;\n }\n\n private createFinding(rule: DetectionRule, evidence: Evidence): Finding {\n return {\n id: randomUUID(),\n ruleId: rule.id,\n severity: rule.severity,\n category: rule.category,\n title: rule.name,\n description: rule.description,\n evidence: {\n filePath: evidence.filePath,\n lineNumber: evidence.lineNumber,\n columnNumber: evidence.columnNumber,\n lineContent: evidence.lineContent,\n contextBefore: evidence.contextBefore,\n contextAfter: evidence.contextAfter,\n matchedPattern: evidence.matchedPattern,\n snippet: evidence.snippet,\n },\n mitreAttackId: rule.mitreAttackId,\n };\n }\n}\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\nconst SYSTEM_INFO_PATTERNS = [\n { name: 'os.hostname', pattern: /os\\.hostname\\s*\\(\\)/g },\n { name: 'os.userInfo', pattern: /os\\.userInfo\\s*\\(\\)/g },\n { name: 'os.platform', pattern: /os\\.platform\\s*\\(\\)/g },\n { name: 'os.arch', pattern: /os\\.arch\\s*\\(\\)/g },\n { name: 'os.networkInterfaces', pattern: /os\\.networkInterfaces\\s*\\(\\)/g },\n { name: 'os.cpus', pattern: /os\\.cpus\\s*\\(\\)/g },\n { name: 'os.homedir', pattern: /os\\.homedir\\s*\\(\\)/g },\n { name: 'process.env', pattern: /process\\.env(?:\\[|\\.)/g },\n];\n\nconst HTTP_TO_IP_PATTERN = /(?:https?\\.request|fetch|axios\\.(?:get|post|put|request))\\s*\\(\\s*['\"`]https?:\\/\\/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/g;\n\nexport const critDataExfiltration: DetectionRule = {\n id: 'EG-CRIT-001',\n name: 'Data Exfiltration Pattern',\n description: 'Detects code that collects system info and sends it to external servers via IP address',\n severity: 'critical',\n category: 'data-exfiltration',\n mitreAttackId: 'T1041',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const lines = content.split('\\n');\n\n // Check for system info collection\n let hasSystemInfo = false;\n let systemInfoPatternName = '';\n let systemInfoLine = 0;\n\n for (const { name, pattern } of SYSTEM_INFO_PATTERNS) {\n pattern.lastIndex = 0;\n const match = pattern.exec(content);\n if (match) {\n hasSystemInfo = true;\n systemInfoPatternName = name;\n systemInfoLine = content.slice(0, match.index).split('\\n').length;\n break;\n }\n }\n\n // Check for HTTP to IP\n HTTP_TO_IP_PATTERN.lastIndex = 0;\n const httpMatch = HTTP_TO_IP_PATTERN.exec(content);\n\n if (hasSystemInfo && httpMatch) {\n const httpToIpLine = content.slice(0, httpMatch.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber: httpToIpLine,\n lineContent: lines[httpToIpLine - 1]?.trim(),\n matchedPattern: `${systemInfoPatternName} + http-to-ip`,\n snippet: `System info (${systemInfoPatternName}) collected at line ${systemInfoLine}, sent to IP at line ${httpToIpLine}`,\n });\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\nconst DANGEROUS_PATTERNS = [\n { name: 'eval', pattern: /\\beval\\s*\\(/g },\n { name: 'Function-constructor', pattern: /new\\s+Function\\s*\\(/g },\n { name: 'child_process-exec', pattern: /(?:require\\s*\\(\\s*['\"]child_process['\"]\\s*\\)|child_process)\\.exec\\s*\\(/g },\n { name: 'child_process-execSync', pattern: /(?:require\\s*\\(\\s*['\"]child_process['\"]\\s*\\)|child_process)\\.execSync\\s*\\(/g },\n { name: 'child_process-spawn-shell', pattern: /\\.spawn\\s*\\([^)]*\\{[^}]*shell\\s*:\\s*true/g },\n { name: 'vm-runInContext', pattern: /vm\\.run(?:InContext|InNewContext|InThisContext)\\s*\\(/g },\n { name: 'vm-Script', pattern: /new\\s+vm\\.Script\\s*\\(/g },\n];\n\nconst DYNAMIC_REQUIRE = /require\\s*\\(\\s*(?:[^'\"`\\s)]|`[^`]*\\$\\{)/g;\n\nexport const critRemoteExecution: DetectionRule = {\n id: 'EG-CRIT-002',\n name: 'Remote Code Execution',\n description: 'Detects dangerous code execution patterns like eval, exec, or dynamic require',\n severity: 'critical',\n category: 'remote-code-execution',\n mitreAttackId: 'T1059',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const lines = content.split('\\n');\n\n for (const { name, pattern } of DANGEROUS_PATTERNS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lines[lineNumber - 1]?.trim(),\n matchedPattern: name,\n snippet: match[0],\n });\n }\n }\n\n DYNAMIC_REQUIRE.lastIndex = 0;\n let match;\n while ((match = DYNAMIC_REQUIRE.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lines[lineNumber - 1]?.trim(),\n matchedPattern: 'dynamic-require',\n snippet: match[0],\n });\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\nconst SENSITIVE_PATHS = [\n { name: 'ssh-keys', pattern: /['\"`][^'\"`]*\\.ssh[/\\\\](?:id_rsa|id_ed25519|id_ecdsa|known_hosts|config|authorized_keys)[^'\"`]*['\"`]/gi },\n { name: 'gnupg', pattern: /['\"`][^'\"`]*\\.gnupg[/\\\\][^'\"`]*['\"`]/gi },\n { name: 'aws-credentials', pattern: /['\"`][^'\"`]*\\.aws[/\\\\]credentials[^'\"`]*['\"`]/gi },\n { name: 'azure-config', pattern: /['\"`][^'\"`]*\\.azure[/\\\\][^'\"`]*['\"`]/gi },\n { name: 'kube-config', pattern: /['\"`][^'\"`]*\\.kube[/\\\\]config[^'\"`]*['\"`]/gi },\n { name: 'git-credentials', pattern: /['\"`][^'\"`]*\\.git-credentials[^'\"`]*['\"`]/gi },\n { name: 'env-file', pattern: /['\"`][^'\"`]*\\.env(?:\\.\\w+)?['\"`]/gi },\n { name: 'npmrc', pattern: /['\"`][^'\"`]*\\.npmrc[^'\"`]*['\"`]/gi },\n { name: 'docker-config', pattern: /['\"`][^'\"`]*\\.docker[/\\\\]config\\.json[^'\"`]*['\"`]/gi },\n { name: 'netrc', pattern: /['\"`][^'\"`]*\\.netrc[^'\"`]*['\"`]/gi },\n];\n\nconst FILE_READ_CONTEXT = /(?:readFile|readFileSync|createReadStream|access|accessSync|exists|existsSync|stat|statSync|open|openSync)/;\n\nexport const critCredentialAccess: DetectionRule = {\n id: 'EG-CRIT-003',\n name: 'Credential File Access',\n description: 'Detects attempts to read sensitive credential files like SSH keys, AWS credentials, or .env files',\n severity: 'critical',\n category: 'credential-theft',\n mitreAttackId: 'T1552.004',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const lines = content.split('\\n');\n\n for (const { name, pattern } of SENSITIVE_PATHS) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(content)) !== null) {\n const startIndex = Math.max(0, match.index - 200);\n const endIndex = Math.min(content.length, match.index + match[0].length + 200);\n const context = content.slice(startIndex, endIndex);\n\n if (FILE_READ_CONTEXT.test(context)) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lines[lineNumber - 1]?.trim(),\n matchedPattern: name,\n snippet: match[0],\n });\n }\n }\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\n// HTTP requests to IP addresses instead of domains\nconst HTTP_TO_IP = /(?:fetch|axios(?:\\.(?:get|post|put|delete|request))?|https?\\.(?:get|post|request)|XMLHttpRequest)\\s*\\([^)]*['\"`]https?:\\/\\/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/g;\n\n// Dynamic URL construction (template literals or concatenation)\nconst DYNAMIC_URL = /(?:fetch|axios|https?\\.request)\\s*\\(\\s*(?:`[^`]*\\$\\{|['\"][^'\"]*['\"]\\s*\\+\\s*\\w)/g;\n\n// WebSocket connections to IP addresses\nconst WEBSOCKET_TO_IP = /new\\s+WebSocket\\s*\\(\\s*['\"`]wss?:\\/\\/\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/g;\n\n// Unusual ports\nconst UNUSUAL_PORTS = /['\"`]https?:\\/\\/[^'\"`:]+:(?!443|80|8080|3000|8443|5000)[0-9]{2,5}/g;\n\nexport const highSuspiciousNetwork: DetectionRule = {\n id: 'EG-HIGH-002',\n name: 'Suspicious Network Activity',\n description: 'Detects network requests to IP addresses, dynamic URLs, or unusual ports',\n severity: 'high',\n category: 'suspicious-network',\n mitreAttackId: 'T1071',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const lines = content.split('\\n');\n const patterns = [\n { pattern: HTTP_TO_IP, name: 'http-to-ip' },\n { pattern: DYNAMIC_URL, name: 'dynamic-url' },\n { pattern: WEBSOCKET_TO_IP, name: 'websocket-to-ip' },\n { pattern: UNUSUAL_PORTS, name: 'unusual-port' },\n ];\n\n for (const { pattern, name } of patterns) {\n pattern.lastIndex = 0;\n let match;\n while ((match = pattern.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lines[lineNumber - 1]?.trim(),\n matchedPattern: name,\n snippet: match[0].slice(0, 100),\n });\n }\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\nconst MIN_BASE64_LENGTH = 100;\nconst BASE64_PATTERN = /['\"`]([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?['\"`]/g;\nconst HEX_PATTERN = /(?:\\\\x[0-9a-fA-F]{2}){10,}/g;\nconst CHAR_CODE_PATTERN = /String\\.fromCharCode\\s*\\(\\s*(?:\\d+\\s*,?\\s*){5,}\\)/g;\nconst UNICODE_ESCAPE_PATTERN = /(?:\\\\u[0-9a-fA-F]{4}){10,}/g;\n\nfunction calculateEntropy(str: string): number {\n const len = str.length;\n if (len === 0) return 0;\n const freq: Record<string, number> = {};\n for (const char of str) {\n freq[char] = (freq[char] || 0) + 1;\n }\n let entropy = 0;\n for (const count of Object.values(freq)) {\n const p = count / len;\n entropy -= p * Math.log2(p);\n }\n return entropy;\n}\n\nexport const highObfuscatedCode: DetectionRule = {\n id: 'EG-HIGH-001',\n name: 'Code Obfuscation Detected',\n description: 'Detects heavily obfuscated code patterns that may hide malicious behavior',\n severity: 'high',\n category: 'code-obfuscation',\n mitreAttackId: 'T1027',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n if (!filePath.endsWith('.js') && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const lines = content.split('\\n');\n\n // Check for large base64 strings\n BASE64_PATTERN.lastIndex = 0;\n let match;\n while ((match = BASE64_PATTERN.exec(content)) !== null) {\n const base64Content = match[0].slice(1, -1);\n if (base64Content.length >= MIN_BASE64_LENGTH) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: (lines[lineNumber - 1]?.trim() || '').slice(0, 80) + '...',\n matchedPattern: 'large-base64',\n snippet: `Base64 string of ${base64Content.length} characters`,\n });\n }\n }\n\n // Check for hex-encoded strings\n HEX_PATTERN.lastIndex = 0;\n while ((match = HEX_PATTERN.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: (lines[lineNumber - 1]?.trim() || '').slice(0, 80) + '...',\n matchedPattern: 'hex-encoded',\n snippet: match[0].slice(0, 50) + '...',\n });\n }\n\n // Check for String.fromCharCode abuse\n CHAR_CODE_PATTERN.lastIndex = 0;\n while ((match = CHAR_CODE_PATTERN.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lines[lineNumber - 1]?.trim(),\n matchedPattern: 'charcode-obfuscation',\n snippet: match[0].slice(0, 80),\n });\n }\n\n // Check for unicode escape sequences\n UNICODE_ESCAPE_PATTERN.lastIndex = 0;\n while ((match = UNICODE_ESCAPE_PATTERN.exec(content)) !== null) {\n const lineNumber = content.slice(0, match.index).split('\\n').length;\n evidences.push({\n filePath,\n lineNumber,\n lineContent: (lines[lineNumber - 1]?.trim() || '').slice(0, 80) + '...',\n matchedPattern: 'unicode-escape',\n snippet: match[0].slice(0, 50) + '...',\n });\n }\n\n // Check overall file entropy for large files\n if (content.length > 5000) {\n const entropy = calculateEntropy(content);\n if (entropy > 5.8) {\n evidences.push({\n filePath,\n lineNumber: 1,\n matchedPattern: 'high-entropy',\n snippet: `File entropy: ${entropy.toFixed(2)} (threshold: 5.8)`,\n });\n }\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\n// Minimum length for a value to be considered a potential secret\nconst MIN_SECRET_LENGTH = 8;\n\n// Patterns that indicate placeholder values (false positives)\nconst PLACEHOLDER_PATTERNS = [\n /^your[_-]?/i,\n /^<[^>]+>$/,\n /^replace[_-]?me$/i,\n /^xxx+$/i,\n /^x{3,}[_-]x{3,}/i,\n /^todo$/i,\n /^fixme$/i,\n /^example$/i,\n /^placeholder$/i,\n /^changeme$/i,\n /^\\*+$/,\n /^\\.+$/,\n /^test$/i,\n /^demo$/i,\n];\n\n// File patterns to exclude (test files, examples, docs)\nconst EXCLUDED_FILE_PATTERNS = [\n /\\.test\\.[jt]sx?$/,\n /\\.spec\\.[jt]sx?$/,\n /__tests__\\//,\n /(?:^|\\/)test\\//,\n /(?:^|\\/)tests\\//,\n /(?:^|\\/)examples?\\//,\n /(?:^|\\/)demo\\//,\n /\\.md$/,\n /\\.txt$/,\n /\\.rst$/,\n];\n\n// Code file extensions to scan\nconst CODE_FILE_EXTENSIONS = ['.js', '.ts', '.jsx', '.tsx', '.mjs', '.cjs'];\n\ninterface SecretPattern {\n name: string;\n pattern: RegExp;\n matchGroup?: number;\n}\n\nconst SECRET_PATTERNS: SecretPattern[] = [\n // AWS Access Key ID (starts with AKIA)\n {\n name: 'aws-access-key',\n pattern: /AKIA[0-9A-Z]{16}/g,\n },\n // AWS Secret Access Key\n {\n name: 'aws-secret-key',\n pattern: /(?:aws[_-]?secret(?:[_-]?access)?[_-]?key|secret[_-]?access[_-]?key)\\s*[:=]\\s*['\"`]([A-Za-z0-9/+=]{40})['\"`]/gi,\n matchGroup: 1,\n },\n // GitHub tokens (ghp_, gho_, ghs_, ghr_)\n {\n name: 'github-token',\n pattern: /gh[pors]_[A-Za-z0-9]{36,}/g,\n },\n // Slack tokens (xoxb-, xoxp-, xoxa-, xoxr-)\n {\n name: 'slack-token',\n pattern: /xox[bpar]-[0-9]+-[0-9]+-[A-Za-z0-9]+/g,\n },\n // Private keys\n {\n name: 'private-key',\n pattern: /-----BEGIN\\s+(?:RSA\\s+|EC\\s+|DSA\\s+|OPENSSH\\s+)?PRIVATE\\s+KEY-----/g,\n },\n // Bearer tokens (JWT format)\n {\n name: 'bearer-token',\n pattern: /Bearer\\s+([A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+)/g,\n matchGroup: 1,\n },\n // API key assignments\n {\n name: 'api-key',\n pattern: /(?:api[_-]?key|apikey)\\s*[:=]\\s*['\"`]([A-Za-z0-9_-]{16,})['\"`]/gi,\n matchGroup: 1,\n },\n // Generic secrets (password, secret, token, passwd, pwd)\n {\n name: 'generic-secret',\n pattern: /(?:password|passwd|pwd|secret|token)\\s*[:=]\\s*['\"`]([^'\"`]{8,})['\"`]/gi,\n matchGroup: 1,\n },\n];\n\nfunction isCodeFile(filePath: string): boolean {\n return CODE_FILE_EXTENSIONS.some((ext) => filePath.endsWith(ext));\n}\n\nfunction isExcludedFile(filePath: string): boolean {\n return EXCLUDED_FILE_PATTERNS.some((pattern) => pattern.test(filePath));\n}\n\nfunction isPlaceholder(value: string): boolean {\n return PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(value));\n}\n\nfunction isInComment(content: string, matchIndex: number): boolean {\n // Find the start of the line containing the match\n const lineStart = content.lastIndexOf('\\n', matchIndex) + 1;\n const lineContent = content.slice(lineStart, matchIndex);\n\n // Check for single-line comment\n if (lineContent.includes('//')) {\n return true;\n }\n\n // Check for block comment - look for /* before the match without a closing */\n const beforeMatch = content.slice(0, matchIndex);\n const lastBlockStart = beforeMatch.lastIndexOf('/*');\n const lastBlockEnd = beforeMatch.lastIndexOf('*/');\n\n if (lastBlockStart > lastBlockEnd) {\n return true;\n }\n\n return false;\n}\n\nfunction getLineNumber(content: string, index: number): number {\n return content.slice(0, index).split('\\n').length;\n}\n\nexport const highHardcodedSecret: DetectionRule = {\n id: 'EG-HIGH-006',\n name: 'Hardcoded Secrets',\n description: 'Detects hardcoded API keys, tokens, passwords, and other secrets in code',\n severity: 'high',\n category: 'hardcoded-secret',\n mitreAttackId: 'T1552.001',\n enabled: true,\n\n detect(\n files: Map<string, string>,\n _manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n for (const [filePath, content] of files) {\n // Skip non-code files\n if (!isCodeFile(filePath)) {\n continue;\n }\n\n // Skip test/example files\n if (isExcludedFile(filePath)) {\n continue;\n }\n\n // Skip empty files\n if (!content || content.trim().length === 0) {\n continue;\n }\n\n const lines = content.split('\\n');\n\n for (const secretPattern of SECRET_PATTERNS) {\n // Reset regex lastIndex to avoid issues with global flag\n secretPattern.pattern.lastIndex = 0;\n\n let match;\n while ((match = secretPattern.pattern.exec(content)) !== null) {\n const matchIndex = match.index;\n\n // Skip if in a comment\n if (isInComment(content, matchIndex)) {\n continue;\n }\n\n // Get the actual secret value (either from capture group or full match)\n const secretValue = secretPattern.matchGroup !== undefined\n ? match[secretPattern.matchGroup]\n : match[0];\n\n // Skip if no secret value found\n if (!secretValue) {\n continue;\n }\n\n // Skip short values for generic patterns\n if (secretPattern.name === 'generic-secret' && secretValue.length < MIN_SECRET_LENGTH) {\n continue;\n }\n\n // Skip placeholder values\n if (isPlaceholder(secretValue)) {\n continue;\n }\n\n const lineNumber = getLineNumber(content, matchIndex);\n const lineContent = lines[lineNumber - 1]?.trim() || '';\n\n evidences.push({\n filePath,\n lineNumber,\n lineContent: lineContent.length > 100 ? lineContent.slice(0, 100) + '...' : lineContent,\n matchedPattern: secretPattern.name,\n snippet: `Detected ${secretPattern.name}: ${secretValue.slice(0, 20)}${secretValue.length > 20 ? '...' : ''}`,\n });\n }\n }\n }\n\n return evidences;\n },\n};\n","import type { DetectionRule } from '../rule.interface.js';\nimport type { Evidence } from '../../types/index.js';\nimport type { ExtensionManifest } from '../../types/index.js';\n\nexport const medExcessiveActivation: DetectionRule = {\n id: 'EG-MED-001',\n name: 'Excessive Activation Events',\n description: 'Extension uses \"*\" activation event which means it activates on every action, potentially for surveillance',\n severity: 'medium',\n category: 'excessive-permission',\n enabled: true,\n\n detect(\n _files: Map<string, string>,\n manifest: ExtensionManifest\n ): Evidence[] {\n const evidences: Evidence[] = [];\n\n const activationEvents = manifest.activationEvents ?? [];\n\n // Check for \"*\" activation event\n if (activationEvents.includes('*')) {\n evidences.push({\n filePath: 'package.json',\n lineNumber: 1,\n matchedPattern: 'activation-star',\n snippet: 'activationEvents: [\"*\"]',\n lineContent: 'Extension activates on every VS Code action',\n });\n }\n\n // Check for onStartupFinished (runs immediately after VS Code starts)\n if (activationEvents.includes('onStartupFinished')) {\n evidences.push({\n filePath: 'package.json',\n lineNumber: 1,\n matchedPattern: 'activation-startup',\n snippet: 'activationEvents: [\"onStartupFinished\"]',\n lineContent: 'Extension activates immediately on VS Code startup',\n });\n }\n\n return evidences;\n },\n};\n","import { ruleRegistry } from '../rule-registry.js';\nimport { critDataExfiltration } from './crit-data-exfiltration.js';\nimport { critRemoteExecution } from './crit-remote-execution.js';\nimport { critCredentialAccess } from './crit-credential-access.js';\nimport { highSuspiciousNetwork } from './high-suspicious-network.js';\nimport { highObfuscatedCode } from './high-obfuscated-code.js';\nimport { highHardcodedSecret } from './high-hardcoded-secret.js';\nimport { medExcessiveActivation } from './med-excessive-activation.js';\n\nexport function registerBuiltInRules(): void {\n ruleRegistry.register(critDataExfiltration);\n ruleRegistry.register(critRemoteExecution);\n ruleRegistry.register(critCredentialAccess);\n ruleRegistry.register(highSuspiciousNetwork);\n ruleRegistry.register(highObfuscatedCode);\n ruleRegistry.register(highHardcodedSecret);\n ruleRegistry.register(medExcessiveActivation);\n}\n\nexport { critDataExfiltration, critRemoteExecution, critCredentialAccess, highSuspiciousNetwork, highObfuscatedCode, highHardcodedSecret, medExcessiveActivation };\n","import type { Reporter, ReporterOptions } from './reporter.interface.js';\nimport type { FullScanReport, ScanResult, Severity } from '../types/index.js';\n\nconst SEVERITY_ORDER: Record<Severity, number> = {\n critical: 0,\n high: 1,\n medium: 2,\n low: 3,\n info: 4,\n};\n\nexport class JsonReporter implements Reporter {\n readonly format = 'json';\n\n generate(report: FullScanReport, options: ReporterOptions = {}): string {\n const {\n includeEvidence = true,\n includeSafe = true,\n minSeverity = 'info',\n } = options;\n\n const filteredResults = this.filterResults(report.results, {\n includeSafe,\n minSeverity,\n includeEvidence,\n });\n\n const output = {\n ...report,\n results: filteredResults,\n };\n\n return JSON.stringify(output, null, 2);\n }\n\n private filterResults(\n results: ScanResult[],\n options: { includeSafe: boolean; minSeverity: Severity; includeEvidence: boolean }\n ): ScanResult[] {\n let filtered = results;\n\n if (!options.includeSafe) {\n filtered = filtered.filter((r) => r.riskLevel !== 'safe' && r.riskLevel !== 'low');\n }\n\n const minOrder = SEVERITY_ORDER[options.minSeverity];\n\n return filtered.map((result) => {\n const filteredFindings = result.findings.filter(\n (f) => SEVERITY_ORDER[f.severity] <= minOrder\n );\n\n const findingsOutput = options.includeEvidence\n ? filteredFindings\n : filteredFindings.map(({ evidence, ...rest }) => rest);\n\n return {\n ...result,\n findings: findingsOutput as ScanResult['findings'],\n };\n });\n }\n}\n","import type { Reporter, ReporterOptions } from './reporter.interface.js';\nimport type { FullScanReport } from '../types/index.js';\n\ninterface SarifRule {\n id: string;\n name: string;\n shortDescription: { text: string };\n fullDescription: { text: string };\n defaultConfiguration: { level: 'error' | 'warning' | 'note' };\n properties?: { 'security-severity'?: string; tags?: string[] };\n}\n\ninterface SarifResult {\n ruleId: string;\n ruleIndex: number;\n level: 'error' | 'warning' | 'note';\n message: { text: string };\n locations: Array<{\n physicalLocation: {\n artifactLocation: { uri: string };\n region?: { startLine: number; startColumn?: number };\n };\n }>;\n properties?: Record<string, unknown>;\n}\n\ninterface SarifOutput {\n $schema: string;\n version: string;\n runs: Array<{\n tool: {\n driver: {\n name: string;\n version: string;\n informationUri: string;\n rules: SarifRule[];\n };\n };\n results: SarifResult[];\n }>;\n}\n\nconst SEVERITY_TO_LEVEL: Record<string, 'error' | 'warning' | 'note'> = {\n critical: 'error',\n high: 'error',\n medium: 'warning',\n low: 'note',\n info: 'note',\n};\n\nconst SEVERITY_TO_SCORE: Record<string, string> = {\n critical: '9.0',\n high: '7.0',\n medium: '5.0',\n low: '3.0',\n info: '1.0',\n};\n\nexport class SarifReporter implements Reporter {\n readonly format = 'sarif';\n\n generate(report: FullScanReport, _options?: ReporterOptions): string {\n const rules = this.extractRules(report);\n const results = this.extractResults(report, rules);\n\n const sarif: SarifOutput = {\n $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',\n version: '2.1.0',\n runs: [\n {\n tool: {\n driver: {\n name: 'Extension Guard',\n version: report.version,\n informationUri: 'https://github.com/aspect-guard/extension-guard',\n rules,\n },\n },\n results,\n },\n ],\n };\n\n return JSON.stringify(sarif, null, 2);\n }\n\n private extractRules(report: FullScanReport): SarifRule[] {\n const ruleMap = new Map<string, SarifRule>();\n\n for (const result of report.results) {\n for (const finding of result.findings) {\n if (!ruleMap.has(finding.ruleId)) {\n ruleMap.set(finding.ruleId, {\n id: finding.ruleId,\n name: finding.title,\n shortDescription: { text: finding.title },\n fullDescription: { text: finding.description },\n defaultConfiguration: { level: SEVERITY_TO_LEVEL[finding.severity] || 'note' },\n properties: {\n 'security-severity': SEVERITY_TO_SCORE[finding.severity] || '1.0',\n tags: ['security', finding.category],\n },\n });\n }\n }\n }\n\n return Array.from(ruleMap.values());\n }\n\n private extractResults(report: FullScanReport, rules: SarifRule[]): SarifResult[] {\n const results: SarifResult[] = [];\n const ruleIndexMap = new Map(rules.map((r, i) => [r.id, i]));\n\n for (const scanResult of report.results) {\n for (const finding of scanResult.findings) {\n const ruleIndex = ruleIndexMap.get(finding.ruleId) ?? 0;\n\n results.push({\n ruleId: finding.ruleId,\n ruleIndex,\n level: SEVERITY_TO_LEVEL[finding.severity] || 'note',\n message: {\n text: `${finding.title} in ${scanResult.extensionId}: ${finding.description}`,\n },\n locations: [\n {\n physicalLocation: {\n artifactLocation: {\n uri: `${scanResult.extensionId}/${finding.evidence.filePath}`,\n },\n region: finding.evidence.lineNumber\n ? {\n startLine: finding.evidence.lineNumber,\n startColumn: finding.evidence.columnNumber,\n }\n : undefined,\n },\n },\n ],\n properties: {\n extensionId: scanResult.extensionId,\n trustScore: scanResult.trustScore,\n mitreAttackId: finding.mitreAttackId,\n },\n });\n }\n }\n\n return results;\n }\n}\n","import type { Reporter, ReporterOptions } from './reporter.interface.js';\nimport type { FullScanReport, ScanResult, Finding, Severity } from '../types/index.js';\n\nconst SEVERITY_EMOJI: Record<Severity, string> = {\n critical: '🔴',\n high: '🟠',\n medium: '🟡',\n low: '🟢',\n info: '⚪',\n};\n\nconst RISK_EMOJI: Record<string, string> = {\n critical: '⛔',\n high: '🔴',\n medium: '🟡',\n low: '🟢',\n safe: '✅',\n};\n\nexport class MarkdownReporter implements Reporter {\n readonly format = 'markdown';\n\n generate(report: FullScanReport, options: ReporterOptions = {}): string {\n const { includeSafe = false } = options;\n const lines: string[] = [];\n\n lines.push('# Extension Guard Scan Report');\n lines.push('');\n lines.push(`**Scan ID:** \\`${report.scanId}\\``);\n lines.push(`**Date:** ${new Date(report.timestamp).toLocaleString()}`);\n lines.push(`**Extension Guard Version:** ${report.version}`);\n lines.push('');\n\n // Environment\n lines.push('## Environment');\n lines.push('');\n lines.push(`- **OS:** ${report.environment.os}`);\n for (const ide of report.environment.ides) {\n lines.push(`- **${ide.name}:** ${ide.path} (${ide.extensionCount} extensions)`);\n }\n lines.push('');\n\n // Summary\n lines.push('## Summary');\n lines.push('');\n lines.push(`| Metric | Value |`);\n lines.push(`|--------|-------|`);\n lines.push(`| Total Extensions | ${report.totalExtensions} |`);\n lines.push(`| Unique Extensions | ${report.uniqueExtensions} |`);\n lines.push(`| Health Score | ${report.summary.overallHealthScore}% |`);\n lines.push(`| Scan Duration | ${(report.scanDurationMs / 1000).toFixed(2)}s |`);\n lines.push('');\n\n // Risk Level Breakdown\n lines.push('### Risk Level Distribution');\n lines.push('');\n lines.push('| Risk Level | Count |');\n lines.push('|------------|-------|');\n for (const [level, count] of Object.entries(report.summary.byRiskLevel)) {\n if (count > 0 || includeSafe) {\n lines.push(`| ${RISK_EMOJI[level] || ''} ${level} | ${count} |`);\n }\n }\n lines.push('');\n\n // Severity Breakdown\n const totalFindings = Object.values(report.summary.bySeverity).reduce((a, b) => a + b, 0);\n if (totalFindings > 0) {\n lines.push('### Findings by Severity');\n lines.push('');\n lines.push('| Severity | Count |');\n lines.push('|----------|-------|');\n for (const [severity, count] of Object.entries(report.summary.bySeverity)) {\n if (count > 0) {\n lines.push(`| ${SEVERITY_EMOJI[severity as Severity] || ''} ${severity} | ${count} |`);\n }\n }\n lines.push('');\n }\n\n // Critical and High Risk Extensions\n const riskyResults = report.results.filter(\n (r) => r.riskLevel === 'critical' || r.riskLevel === 'high'\n );\n\n if (riskyResults.length > 0) {\n lines.push('## ⚠️ High Risk Extensions');\n lines.push('');\n for (const result of riskyResults) {\n lines.push(...this.formatExtensionResult(result));\n }\n }\n\n // Medium Risk Extensions\n const mediumResults = report.results.filter((r) => r.riskLevel === 'medium');\n if (mediumResults.length > 0) {\n lines.push('## Medium Risk Extensions');\n lines.push('');\n for (const result of mediumResults) {\n lines.push(...this.formatExtensionResult(result));\n }\n }\n\n // Safe Extensions (if requested)\n if (includeSafe) {\n const safeResults = report.results.filter(\n (r) => r.riskLevel === 'safe' || r.riskLevel === 'low'\n );\n if (safeResults.length > 0) {\n lines.push('## ✅ Safe Extensions');\n lines.push('');\n lines.push('| Extension | Version | Trust Score |');\n lines.push('|-----------|---------|-------------|');\n for (const result of safeResults) {\n lines.push(`| ${result.extensionId} | ${result.version} | ${result.trustScore}/100 |`);\n }\n lines.push('');\n }\n }\n\n // Footer\n lines.push('---');\n lines.push('');\n lines.push('*Generated by [Extension Guard](https://github.com/aspect-guard/extension-guard)*');\n\n return lines.join('\\n');\n }\n\n private formatExtensionResult(result: ScanResult): string[] {\n const lines: string[] = [];\n\n lines.push(`### ${RISK_EMOJI[result.riskLevel] || ''} ${result.extensionId}`);\n lines.push('');\n lines.push(`- **Display Name:** ${result.displayName}`);\n lines.push(`- **Version:** ${result.version}`);\n lines.push(`- **Publisher:** ${result.metadata.publisher.name}`);\n lines.push(`- **Trust Score:** ${result.trustScore}/100`);\n lines.push(`- **Risk Level:** ${result.riskLevel}`);\n lines.push('');\n\n if (result.findings.length > 0) {\n lines.push('#### Findings');\n lines.push('');\n for (const finding of result.findings) {\n lines.push(...this.formatFinding(finding));\n }\n }\n\n return lines;\n }\n\n private formatFinding(finding: Finding): string[] {\n const lines: string[] = [];\n const emoji = SEVERITY_EMOJI[finding.severity] || '';\n\n lines.push(`- ${emoji} **${finding.severity.toUpperCase()}:** ${finding.title}`);\n lines.push(` - ${finding.description}`);\n if (finding.evidence.filePath) {\n const location = finding.evidence.lineNumber\n ? `${finding.evidence.filePath}:${finding.evidence.lineNumber}`\n : finding.evidence.filePath;\n lines.push(` - 📍 Location: \\`${location}\\``);\n }\n if (finding.mitreAttackId) {\n lines.push(` - 🎯 MITRE ATT&CK: ${finding.mitreAttackId}`);\n }\n lines.push('');\n\n return lines;\n }\n}\n","/**\n * Policy Loader\n *\n * Loads and validates Extension Guard policy configuration files.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport type { PolicyConfig } from './policy.types.js';\n\nconst DEFAULT_CONFIG_NAME = '.extension-guard.json';\n\n/**\n * Load and validate a policy configuration file.\n *\n * @param configPath - Optional path to the config file. If not provided,\n * searches for .extension-guard.json in the current directory.\n * @returns The parsed PolicyConfig or null if not found.\n * @throws Error if the file exists but is invalid JSON or fails validation.\n */\nexport async function loadPolicyConfig(configPath?: string): Promise<PolicyConfig | null> {\n const resolvedPath = configPath ?? path.join(process.cwd(), DEFAULT_CONFIG_NAME);\n\n try {\n const content = await fs.readFile(resolvedPath, 'utf-8');\n const config = JSON.parse(content) as unknown;\n\n validatePolicyConfig(config);\n\n return config as PolicyConfig;\n } catch (error) {\n if (isNodeError(error) && error.code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Validate that the parsed config matches the expected PolicyConfig schema.\n *\n * @param config - The parsed JSON object\n * @throws Error if validation fails\n */\nfunction validatePolicyConfig(config: unknown): asserts config is PolicyConfig {\n if (typeof config !== 'object' || config === null) {\n throw new Error('Policy config must be an object');\n }\n\n const obj = config as Record<string, unknown>;\n\n // Version is required\n if (typeof obj.version !== 'string') {\n throw new Error('Policy config must have a \"version\" field of type string');\n }\n\n // Validate scanning section if present\n if (obj.scanning !== undefined) {\n validateScanningConfig(obj.scanning);\n }\n\n // Validate policy section if present\n if (obj.policy !== undefined) {\n validatePolicySection(obj.policy);\n }\n}\n\n/**\n * Validate the scanning configuration section.\n */\nfunction validateScanningConfig(scanning: unknown): void {\n if (typeof scanning !== 'object' || scanning === null) {\n throw new Error('scanning must be an object');\n }\n\n const obj = scanning as Record<string, unknown>;\n\n if (obj.minSeverity !== undefined) {\n const validSeverities = ['critical', 'high', 'medium', 'low', 'info'];\n if (!validSeverities.includes(obj.minSeverity as string)) {\n throw new Error(`scanning.minSeverity must be one of: ${validSeverities.join(', ')}`);\n }\n }\n\n if (obj.skipRules !== undefined) {\n if (!Array.isArray(obj.skipRules) || !obj.skipRules.every(r => typeof r === 'string')) {\n throw new Error('scanning.skipRules must be an array of strings');\n }\n }\n\n if (obj.timeout !== undefined) {\n if (typeof obj.timeout !== 'number' || obj.timeout <= 0) {\n throw new Error('scanning.timeout must be a positive number');\n }\n }\n}\n\n/**\n * Validate the policy configuration section.\n */\nfunction validatePolicySection(policy: unknown): void {\n if (typeof policy !== 'object' || policy === null) {\n throw new Error('policy must be an object');\n }\n\n const obj = policy as Record<string, unknown>;\n\n if (obj.allowlist !== undefined) {\n if (!Array.isArray(obj.allowlist) || !obj.allowlist.every(id => typeof id === 'string')) {\n throw new Error('policy.allowlist must be an array of extension ID strings');\n }\n }\n\n if (obj.blocklist !== undefined) {\n if (!Array.isArray(obj.blocklist) || !obj.blocklist.every(id => typeof id === 'string')) {\n throw new Error('policy.blocklist must be an array of extension ID strings');\n }\n }\n\n if (obj.rules !== undefined) {\n validatePolicyRules(obj.rules);\n }\n}\n\n/**\n * Validate the policy rules section.\n */\nfunction validatePolicyRules(rules: unknown): void {\n if (typeof rules !== 'object' || rules === null) {\n throw new Error('policy.rules must be an object');\n }\n\n const obj = rules as Record<string, unknown>;\n const validActions = ['block', 'warn', 'info'];\n\n if (obj.minTrustScore !== undefined) {\n const rule = obj.minTrustScore as Record<string, unknown>;\n if (typeof rule.threshold !== 'number' || rule.threshold < 0 || rule.threshold > 100) {\n throw new Error('minTrustScore.threshold must be a number between 0 and 100');\n }\n if (!validActions.includes(rule.action as string)) {\n throw new Error(`minTrustScore.action must be one of: ${validActions.join(', ')}`);\n }\n }\n\n if (obj.requireVerifiedPublisher !== undefined) {\n const rule = obj.requireVerifiedPublisher as Record<string, unknown>;\n if (typeof rule.enabled !== 'boolean') {\n throw new Error('requireVerifiedPublisher.enabled must be a boolean');\n }\n if (!validActions.includes(rule.action as string)) {\n throw new Error(`requireVerifiedPublisher.action must be one of: ${validActions.join(', ')}`);\n }\n if (rule.exceptions !== undefined) {\n if (!Array.isArray(rule.exceptions) || !rule.exceptions.every(e => typeof e === 'string')) {\n throw new Error('requireVerifiedPublisher.exceptions must be an array of strings');\n }\n }\n }\n\n if (obj.maxDaysSinceUpdate !== undefined) {\n const rule = obj.maxDaysSinceUpdate as Record<string, unknown>;\n if (typeof rule.days !== 'number' || rule.days <= 0) {\n throw new Error('maxDaysSinceUpdate.days must be a positive number');\n }\n if (!validActions.includes(rule.action as string)) {\n throw new Error(`maxDaysSinceUpdate.action must be one of: ${validActions.join(', ')}`);\n }\n }\n\n if (obj.blockObfuscated !== undefined) {\n const rule = obj.blockObfuscated as Record<string, unknown>;\n if (typeof rule.enabled !== 'boolean') {\n throw new Error('blockObfuscated.enabled must be a boolean');\n }\n if (!validActions.includes(rule.action as string)) {\n throw new Error(`blockObfuscated.action must be one of: ${validActions.join(', ')}`);\n }\n }\n}\n\n/**\n * Type guard for Node.js errors with error codes.\n */\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && 'code' in error;\n}\n","/**\n * Policy Engine\n *\n * Evaluates extension scan results against policy rules to determine compliance.\n */\n\nimport type { PolicyConfig, PolicyViolation } from './policy.types.js';\nimport type { ScanResult } from '../types/index.js';\n\n/**\n * Rule ID for obfuscated code detection.\n * Must match the rule ID in high-obfuscated-code.ts\n */\nconst OBFUSCATION_RULE_ID = 'EG-HIGH-001';\n\n/**\n * Milliseconds in a day for date calculations.\n */\nconst MS_PER_DAY = 1000 * 60 * 60 * 24;\n\n/**\n * Extended metadata interface that may include lastUpdated.\n * The base ExtensionInfo type doesn't include this, but it may be\n * added by the scanner when available from marketplace data.\n */\ninterface ExtendedMetadata {\n lastUpdated?: string;\n publisher: { verified: boolean; name: string };\n}\n\n/**\n * PolicyEngine evaluates scan results against configured policy rules.\n *\n * @example\n * ```typescript\n * const config = await loadPolicyConfig();\n * const engine = new PolicyEngine(config);\n * const violations = engine.evaluate(scanResults);\n *\n * if (engine.hasBlockingViolations()) {\n * console.error('Policy check failed');\n * process.exit(1);\n * }\n * ```\n */\nexport class PolicyEngine {\n private violations: PolicyViolation[] = [];\n\n /**\n * Create a new PolicyEngine instance.\n *\n * @param config - The policy configuration to evaluate against\n */\n constructor(private config: PolicyConfig) {}\n\n /**\n * Evaluate scan results against the configured policy.\n *\n * Checks are applied in this order for each extension:\n * 1. Blocklist - if matched, block immediately and skip other checks\n * 2. Allowlist - if matched, skip all other checks\n * 3. Individual rules (minTrustScore, blockObfuscated, etc.)\n *\n * @param results - Array of scan results to evaluate\n * @returns Array of policy violations found\n */\n evaluate(results: ScanResult[]): PolicyViolation[] {\n this.violations = [];\n\n for (const result of results) {\n const extId = result.extensionId;\n\n // Check blocklist first\n if (this.config.policy?.blocklist?.includes(extId)) {\n this.violations.push({\n extensionId: extId,\n rule: 'blocklist',\n message: 'Extension is blocklisted',\n action: 'block',\n });\n continue; // Skip all other checks for blocklisted extensions\n }\n\n // Check allowlist - skip all other checks if allowed\n if (this.config.policy?.allowlist?.includes(extId)) {\n continue;\n }\n\n // Check individual rules\n this.checkMinTrustScore(result);\n this.checkBlockObfuscated(result);\n this.checkRequireVerifiedPublisher(result);\n this.checkMaxDaysSinceUpdate(result);\n }\n\n return this.violations;\n }\n\n /**\n * Check if there are any violations with 'block' action.\n *\n * @returns true if any blocking violations exist\n */\n hasBlockingViolations(): boolean {\n return this.violations.some(v => v.action === 'block');\n }\n\n /**\n * Get all violations from the last evaluation.\n *\n * @returns Array of all policy violations\n */\n getViolations(): PolicyViolation[] {\n return this.violations;\n }\n\n /**\n * Check minTrustScore rule.\n */\n private checkMinTrustScore(result: ScanResult): void {\n const rule = this.config.policy?.rules?.minTrustScore;\n if (!rule) return;\n\n if (result.trustScore < rule.threshold) {\n this.violations.push({\n extensionId: result.extensionId,\n rule: 'minTrustScore',\n message: `Trust score ${result.trustScore} below threshold ${rule.threshold}`,\n action: rule.action,\n });\n }\n }\n\n /**\n * Check blockObfuscated rule.\n */\n private checkBlockObfuscated(result: ScanResult): void {\n const rule = this.config.policy?.rules?.blockObfuscated;\n if (!rule?.enabled) return;\n\n const hasObfuscation = result.findings.some(f => f.ruleId === OBFUSCATION_RULE_ID);\n if (hasObfuscation) {\n this.violations.push({\n extensionId: result.extensionId,\n rule: 'blockObfuscated',\n message: 'Extension contains obfuscated code',\n action: rule.action,\n });\n }\n }\n\n /**\n * Check requireVerifiedPublisher rule.\n */\n private checkRequireVerifiedPublisher(result: ScanResult): void {\n const rule = this.config.policy?.rules?.requireVerifiedPublisher;\n if (!rule?.enabled) return;\n\n const metadata = result.metadata as ExtendedMetadata;\n if (!metadata.publisher.verified) {\n // Check if this extension is in the exceptions list\n if (rule.exceptions?.includes(result.extensionId)) {\n return;\n }\n\n this.violations.push({\n extensionId: result.extensionId,\n rule: 'requireVerifiedPublisher',\n message: 'Extension publisher is not verified',\n action: rule.action,\n });\n }\n }\n\n /**\n * Check maxDaysSinceUpdate rule.\n */\n private checkMaxDaysSinceUpdate(result: ScanResult): void {\n const rule = this.config.policy?.rules?.maxDaysSinceUpdate;\n if (!rule) return;\n\n const metadata = result.metadata as ExtendedMetadata;\n if (!metadata.lastUpdated) return;\n\n const lastUpdatedDate = new Date(metadata.lastUpdated);\n const daysSinceUpdate = Math.floor((Date.now() - lastUpdatedDate.getTime()) / MS_PER_DAY);\n\n if (daysSinceUpdate > rule.days) {\n this.violations.push({\n extensionId: result.extensionId,\n rule: 'maxDaysSinceUpdate',\n message: `Extension not updated in ${daysSinceUpdate} days (max: ${rule.days})`,\n action: rule.action,\n });\n }\n }\n}\n","// Extension Guard Core - Scanning Engine\n// @aspect-guard/core\n\nexport const VERSION = '0.1.0';\n\n// Types\nexport * from './types/index.js';\n\n// Scanner\nexport { ExtensionGuardScanner } from './scanner/scanner.js';\nexport { detectIDEPaths, IDE_PATHS, expandPath } from './scanner/ide-detector.js';\nexport { readExtension, readExtensionsFromDirectory } from './scanner/extension-reader.js';\nexport { collectFiles, shouldCollectFile } from './scanner/file-collector.js';\n\n// Rules\nexport * from './rules/index.js';\nexport { registerBuiltInRules } from './rules/built-in/index.js';\n\n// Reporter\nexport * from './reporter/index.js';\n\n// Policy\nexport * from './policy/index.js';\n"],"mappings":"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","names":["os","randomUUID","fs","path","stat","fs","path","stat","match","randomUUID","SEVERITY_ORDER","fs","path"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aspect-guard/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core scanning engine for Extension Guard",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"data"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.0.0",
|
|
21
|
+
"tsup": "^8.0.0",
|
|
22
|
+
"vitest": "^1.6.0",
|
|
23
|
+
"typescript": "^5.4.0"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
|
+
},
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"dev": "tsup --watch",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:watch": "vitest",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"clean": "rm -rf dist"
|
|
36
|
+
}
|
|
37
|
+
}
|