pinata-security-cli 0.5.3 → 0.6.1
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/README.md +39 -2
- package/dist/cli/index.js +2423 -1909
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/package.json +8 -1
- package/src/categories/definitions/concurrency/idempotency-missing.yml +5 -5
- package/src/categories/definitions/concurrency/race-condition.yml +2 -2
- package/src/categories/definitions/data/data-race.yml +15 -18
- package/src/categories/definitions/data/encoding-mismatch.yml +4 -4
- package/src/categories/definitions/data/null-handling.yml +8 -23
- package/src/categories/definitions/input/boundary-testing.yml +12 -40
- package/src/categories/definitions/input/injection-fuzzing.yml +19 -0
- package/src/categories/definitions/input/null-undefined.yml +11 -39
- package/src/categories/definitions/network/connection-failure.yml +9 -3
- package/src/categories/definitions/resource/memory-leak.yml +15 -17
- package/src/categories/definitions/security/auth-failures.yml +8 -0
- package/src/categories/definitions/security/command-injection.yml +17 -0
- package/src/categories/definitions/security/csrf.yml +19 -0
- package/src/categories/definitions/security/data-exposure.yml +24 -0
- package/src/categories/definitions/security/dependency-risks.yml +6 -6
- package/src/categories/definitions/security/deserialization.yml +44 -0
- package/src/categories/definitions/security/file-upload.yml +39 -0
- package/src/categories/definitions/security/ldap-injection.yml +23 -0
- package/src/categories/definitions/security/path-traversal.yml +13 -0
- package/src/categories/definitions/security/prompt-injection.yml +14 -0
- package/src/categories/definitions/security/sql-injection.yml +30 -0
- package/src/categories/definitions/security/ssrf.yml +60 -0
- package/src/categories/definitions/security/xss.yml +36 -0
- package/src/categories/definitions/security/xxe.yml +32 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/categories/schema/category.schema.ts","../src/categories/schema/example.schema.ts","../src/categories/schema/pattern.schema.ts","../src/categories/schema/template.schema.ts","../src/categories/schema/index.ts","../src/lib/errors.ts","../src/lib/result.ts","../src/categories/store/category-store.ts","../src/lib/logger.ts","../src/core/detection/ast-parser.ts","../src/core/index.ts","../src/ai/service.ts","../src/ai/explainer.ts","../src/ai/template-filler.ts","../src/ai/pattern-suggester.ts"],"names":["ID_PATTERN","z","__filename","join","SYSTEM_PROMPT"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from \"zod\";\n\n/**\n * Risk domains representing different areas of test coverage\n */\nexport const RiskDomainSchema = z.enum([\n \"security\",\n \"data\",\n \"concurrency\",\n \"input\",\n \"resource\",\n \"reliability\",\n \"performance\",\n \"platform\",\n \"business\",\n \"compliance\",\n]);\n\n/**\n * Test levels from unit to chaos engineering\n */\nexport const TestLevelSchema = z.enum([\n \"unit\",\n \"integration\",\n \"system\",\n \"chaos\",\n]);\n\n/**\n * Priority levels for categorizing importance\n */\nexport const PrioritySchema = z.enum([\"P0\", \"P1\", \"P2\"]);\n\n/**\n * Severity levels for gap findings\n */\nexport const SeveritySchema = z.enum([\"critical\", \"high\", \"medium\", \"low\"]);\n\n/**\n * Confidence levels for pattern detection\n */\nexport const ConfidenceSchema = z.enum([\"high\", \"medium\", \"low\"]);\n\n/**\n * Supported programming languages\n */\nexport const LanguageSchema = z.enum([\n \"python\",\n \"typescript\",\n \"javascript\",\n \"go\",\n \"java\",\n \"rust\",\n]);\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Base category schema without nested types\n * Full CategorySchema is defined in index.ts to avoid circular imports\n */\nexport const CategoryBaseSchema = z.object({\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n version: z.number().int().positive(),\n name: z.string().min(1, \"Name is required\").max(100, \"Name too long\"),\n description: z\n .string()\n .min(10, \"Description must be at least 10 characters\")\n .max(2000, \"Description too long\"),\n domain: RiskDomainSchema,\n level: TestLevelSchema,\n priority: PrioritySchema,\n severity: SeveritySchema,\n applicableLanguages: z.array(LanguageSchema).min(1, \"At least one language required\"),\n cves: z.array(z.string()).optional(),\n references: z.array(z.string().url(\"Invalid URL\")).optional(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\n// Inferred types\nexport type RiskDomain = z.infer<typeof RiskDomainSchema>;\nexport type TestLevel = z.infer<typeof TestLevelSchema>;\nexport type Priority = z.infer<typeof PrioritySchema>;\nexport type Severity = z.infer<typeof SeveritySchema>;\nexport type Confidence = z.infer<typeof ConfidenceSchema>;\nexport type Language = z.infer<typeof LanguageSchema>;\nexport type CategoryBase = z.infer<typeof CategoryBaseSchema>;\n\n/**\n * All available risk domains\n */\nexport const RISK_DOMAINS = RiskDomainSchema.options;\n\n/**\n * All available test levels\n */\nexport const TEST_LEVELS = TestLevelSchema.options;\n\n/**\n * All available languages\n */\nexport const LANGUAGES = LanguageSchema.options;\n","import { z } from \"zod\";\n\nimport { LanguageSchema, SeveritySchema } from \"./category.schema.js\";\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for example vulnerable code and corresponding tests\n */\nexport const ExampleSchema = z.object({\n /** Unique identifier for this example */\n name: z\n .string()\n .regex(ID_PATTERN, \"Name must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Explanation of the vulnerability/edge case concept */\n concept: z.string().min(20, \"Concept must be at least 20 characters\"),\n\n /** Example of vulnerable or problematic code */\n vulnerableCode: z.string().min(10, \"Vulnerable code must be at least 10 characters\"),\n\n /** Example test code that catches this vulnerability */\n testCode: z.string().min(50, \"Test code must be at least 50 characters\"),\n\n /** Programming language of the example */\n language: LanguageSchema,\n\n /** Severity if this vulnerability is exploited */\n severity: SeveritySchema,\n\n /** Optional related CVE identifier */\n cve: z.string().optional(),\n\n /** Optional link to more information */\n reference: z.string().url().optional(),\n});\n\n// Inferred types\nexport type Example = z.infer<typeof ExampleSchema>;\n","import { z } from \"zod\";\n\nimport { ConfidenceSchema, LanguageSchema } from \"./category.schema.js\";\n\n/**\n * Types of detection patterns\n * - ast: Tree-sitter AST queries\n * - regex: Regular expression patterns\n * - semantic: LLM-assisted semantic analysis\n */\nexport const PatternTypeSchema = z.enum([\"ast\", \"regex\", \"semantic\"]);\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for detection patterns that identify code susceptible to a category\n */\nexport const DetectionPatternSchema = z.object({\n /** Unique identifier for this pattern */\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Type of pattern matching to use */\n type: PatternTypeSchema,\n\n /** Target programming language */\n language: LanguageSchema,\n\n /** The pattern string (AST query, regex, or semantic description) */\n pattern: z.string().min(1, \"Pattern is required\"),\n\n /** How confident we are when this pattern matches */\n confidence: ConfidenceSchema,\n\n /** Human-readable description of what this pattern detects */\n description: z.string().min(10, \"Description must be at least 10 characters\"),\n\n /** Optional pattern that indicates code is NOT vulnerable (false positive filter) */\n negativePattern: z.string().optional(),\n\n /** Optional list of framework contexts where this pattern applies */\n frameworks: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for a detection result (pattern match in code)\n */\nexport const DetectionResultSchema = z.object({\n /** ID of the pattern that matched */\n patternId: z.string(),\n\n /** Category this detection belongs to */\n categoryId: z.string(),\n\n /** File path where detection occurred */\n filePath: z.string(),\n\n /** Starting line number (1-indexed) */\n lineStart: z.number().int().positive(),\n\n /** Ending line number (1-indexed) */\n lineEnd: z.number().int().positive(),\n\n /** Code snippet that matched */\n codeSnippet: z.string(),\n\n /** Confidence of this specific match */\n confidence: ConfidenceSchema,\n\n /** Optional additional context */\n context: z.record(z.unknown()).optional(),\n});\n\n// Inferred types\nexport type PatternType = z.infer<typeof PatternTypeSchema>;\nexport type DetectionPattern = z.infer<typeof DetectionPatternSchema>;\nexport type DetectionResult = z.infer<typeof DetectionResultSchema>;\n\n/**\n * All available pattern types\n */\nexport const PATTERN_TYPES = PatternTypeSchema.options;\n","import { z } from \"zod\";\n\nimport { LanguageSchema } from \"./category.schema.js\";\n\n/**\n * Supported test frameworks\n */\nexport const TestFrameworkSchema = z.enum([\n \"pytest\",\n \"unittest\",\n \"jest\",\n \"vitest\",\n \"mocha\",\n \"go-test\",\n \"junit\",\n]);\n\n/**\n * Types for template variables\n */\nexport const VariableTypeSchema = z.enum([\n \"string\",\n \"number\",\n \"boolean\",\n \"array\",\n \"object\",\n]);\n\n/**\n * Regex pattern for valid variable names (camelCase)\n */\nconst VARIABLE_NAME_PATTERN = /^[a-z][a-zA-Z0-9_]*$/;\n\n/**\n * Schema for template variables that get substituted during generation\n */\nexport const TemplateVariableSchema = z.object({\n /** Variable name (used in template as {{name}}) */\n name: z\n .string()\n .regex(VARIABLE_NAME_PATTERN, \"Variable name must be camelCase\"),\n\n /** Type of the variable value */\n type: VariableTypeSchema,\n\n /** Human-readable description */\n description: z.string().min(1, \"Description is required\"),\n\n /** Whether this variable must be provided */\n required: z.boolean().default(true),\n\n /** Default value if not provided */\n defaultValue: z.unknown().optional(),\n});\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for test templates that generate runnable tests\n */\nexport const TestTemplateSchema = z.object({\n /** Unique identifier for this template */\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Target programming language */\n language: LanguageSchema,\n\n /** Target test framework */\n framework: TestFrameworkSchema,\n\n /** Template content with {{variable}} placeholders */\n template: z.string().min(50, \"Template must be at least 50 characters\"),\n\n /** Variables that can be substituted in the template */\n variables: z.array(TemplateVariableSchema),\n\n /** Required imports for the generated test */\n imports: z.array(z.string()).optional(),\n\n /** Required fixtures or setup code */\n fixtures: z.array(z.string()).optional(),\n\n /** Description of what this template tests */\n description: z.string().optional(),\n});\n\n// Inferred types\nexport type TestFramework = z.infer<typeof TestFrameworkSchema>;\nexport type VariableType = z.infer<typeof VariableTypeSchema>;\nexport type TemplateVariable = z.infer<typeof TemplateVariableSchema>;\nexport type TestTemplate = z.infer<typeof TestTemplateSchema>;\n\n/**\n * All available test frameworks\n */\nexport const TEST_FRAMEWORKS = TestFrameworkSchema.options;\n","import { z } from \"zod\";\n\nimport {\n CategoryBaseSchema,\n RiskDomainSchema,\n TestLevelSchema,\n PrioritySchema,\n SeveritySchema,\n ConfidenceSchema,\n LanguageSchema,\n RISK_DOMAINS,\n TEST_LEVELS,\n LANGUAGES,\n} from \"./category.schema.js\";\nimport { ExampleSchema } from \"./example.schema.js\";\nimport { DetectionPatternSchema, DetectionResultSchema, PatternTypeSchema, PATTERN_TYPES } from \"./pattern.schema.js\";\nimport { TestTemplateSchema, TemplateVariableSchema, TestFrameworkSchema, VariableTypeSchema, TEST_FRAMEWORKS } from \"./template.schema.js\";\n\n// Re-export all schemas\nexport {\n // Category schemas\n RiskDomainSchema,\n TestLevelSchema,\n PrioritySchema,\n SeveritySchema,\n ConfidenceSchema,\n LanguageSchema,\n CategoryBaseSchema,\n // Pattern schemas\n PatternTypeSchema,\n DetectionPatternSchema,\n DetectionResultSchema,\n // Template schemas\n TestFrameworkSchema,\n TemplateVariableSchema,\n VariableTypeSchema,\n TestTemplateSchema,\n // Example schema\n ExampleSchema,\n // Constants\n RISK_DOMAINS,\n TEST_LEVELS,\n LANGUAGES,\n PATTERN_TYPES,\n TEST_FRAMEWORKS,\n};\n\n// Re-export all types\nexport type {\n RiskDomain,\n TestLevel,\n Priority,\n Severity,\n Confidence,\n Language,\n CategoryBase,\n} from \"./category.schema.js\";\n\nexport type {\n PatternType,\n DetectionPattern,\n DetectionResult,\n} from \"./pattern.schema.js\";\n\nexport type {\n TestFramework,\n VariableType,\n TemplateVariable,\n TestTemplate,\n} from \"./template.schema.js\";\n\nexport type { Example } from \"./example.schema.js\";\n\n/**\n * Complete Category schema with all nested types\n */\nexport const CategorySchema = CategoryBaseSchema.extend({\n detectionPatterns: z.array(DetectionPatternSchema).min(1, \"At least one detection pattern required\"),\n testTemplates: z.array(TestTemplateSchema).min(1, \"At least one test template required\"),\n examples: z.array(ExampleSchema).min(1, \"At least one example required\"),\n});\n\n/**\n * Complete Category type\n */\nexport type Category = z.infer<typeof CategorySchema>;\n\n/**\n * Category without nested arrays (for partial loading)\n */\nexport const CategorySummarySchema = CategoryBaseSchema.pick({\n id: true,\n name: true,\n domain: true,\n level: true,\n priority: true,\n severity: true,\n description: true,\n});\n\nexport type CategorySummary = z.infer<typeof CategorySummarySchema>;\n","/**\n * Base error class for all Pinata errors\n */\nexport class PinataError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly context?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"PinataError\";\n // Maintains proper stack trace for where error was thrown (V8 only)\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n /**\n * Serialize error for logging or API responses\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n };\n }\n}\n\n/**\n * Error for schema validation failures\n */\nexport class ValidationError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"VALIDATION_ERROR\", context);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Error for file/code parsing failures\n */\nexport class ParseError extends PinataError {\n constructor(\n message: string,\n public readonly filePath: string,\n public readonly line?: number,\n context?: Record<string, unknown>\n ) {\n super(message, \"PARSE_ERROR\", { ...context, filePath, line });\n this.name = \"ParseError\";\n }\n}\n\n/**\n * Error for configuration issues\n */\nexport class ConfigError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"CONFIG_ERROR\", context);\n this.name = \"ConfigError\";\n }\n}\n\n/**\n * Error during codebase analysis\n */\nexport class AnalysisError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"ANALYSIS_ERROR\", context);\n this.name = \"AnalysisError\";\n }\n}\n\n/**\n * Error during test generation\n */\nexport class GenerationError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"GENERATION_ERROR\", context);\n this.name = \"GenerationError\";\n }\n}\n\n/**\n * Error for category not found\n */\nexport class CategoryNotFoundError extends PinataError {\n constructor(categoryId: string) {\n super(`Category not found: ${categoryId}`, \"CATEGORY_NOT_FOUND\", { categoryId });\n this.name = \"CategoryNotFoundError\";\n }\n}\n\n/**\n * Error for pattern not found\n */\nexport class PatternNotFoundError extends PinataError {\n constructor(patternId: string) {\n super(`Pattern not found: ${patternId}`, \"PATTERN_NOT_FOUND\", { patternId });\n this.name = \"PatternNotFoundError\";\n }\n}\n","/**\n * Result type for operations that can fail\n * Prefer this over throwing exceptions for expected failures\n */\nexport type Result<T, E = Error> =\n | { success: true; data: T }\n | { success: false; error: E };\n\n/**\n * Create a successful result\n */\nexport function ok<T>(data: T): Result<T, never> {\n return { success: true, data };\n}\n\n/**\n * Create a failed result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { success: false, error };\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n * Use sparingly - prefer pattern matching with if/else\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.success) {\n return result.data;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n if (result.success) {\n return result.data;\n }\n return defaultValue;\n}\n\n/**\n * Map over a successful result\n */\nexport function map<T, U, E>(\n result: Result<T, E>,\n fn: (value: T) => U\n): Result<U, E> {\n if (result.success) {\n return ok(fn(result.data));\n }\n return result;\n}\n\n/**\n * Map over a failed result\n */\nexport function mapErr<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => F\n): Result<T, F> {\n if (!result.success) {\n return err(fn(result.error));\n }\n return result;\n}\n\n/**\n * Chain results together (flatMap)\n */\nexport function andThen<T, U, E>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, E>\n): Result<U, E> {\n if (result.success) {\n return fn(result.data);\n }\n return result;\n}\n\n/**\n * Combine multiple results into one\n * Returns first error if any fail, otherwise returns array of all values\n */\nexport function all<T, E>(results: Result<T, E>[]): Result<T[], E> {\n const values: T[] = [];\n for (const result of results) {\n if (!result.success) {\n return result;\n }\n values.push(result.data);\n }\n return ok(values);\n}\n\n/**\n * Try to execute a function, returning a Result\n */\nexport function tryCatch<T>(fn: () => T): Result<T, Error> {\n try {\n return ok(fn());\n } catch (e) {\n return err(e instanceof Error ? e : new Error(String(e)));\n }\n}\n\n/**\n * Try to execute an async function, returning a Result\n */\nexport async function tryCatchAsync<T>(\n fn: () => Promise<T>\n): Promise<Result<T, Error>> {\n try {\n return ok(await fn());\n } catch (e) {\n return err(e instanceof Error ? e : new Error(String(e)));\n }\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\n\nimport YAML from \"yaml\";\n\nimport { ValidationError, CategoryNotFoundError } from \"../../lib/errors.js\";\nimport { ok, err, all, tryCatchAsync } from \"../../lib/result.js\";\nimport { CategorySchema, CategorySummarySchema } from \"../schema/index.js\";\n\nimport type { Result } from \"../../lib/result.js\";\nimport type {\n Category,\n CategorySummary,\n RiskDomain,\n TestLevel,\n Language,\n Priority,\n Severity,\n} from \"../schema/index.js\";\n\n/**\n * Options for filtering categories\n */\nexport interface CategoryFilter {\n domain?: RiskDomain;\n level?: TestLevel;\n language?: Language;\n priority?: Priority;\n severity?: Severity;\n}\n\n/**\n * Options for searching categories\n */\nexport interface SearchOptions {\n query: string;\n filter?: CategoryFilter;\n limit?: number;\n}\n\n/**\n * Search result with relevance score\n */\nexport interface SearchResult {\n category: CategorySummary;\n score: number;\n matches: string[];\n}\n\n/**\n * Store for managing test categories\n *\n * Provides:\n * - CRUD operations for categories\n * - Indexing by domain, level, language\n * - Full-text search\n * - Validation on load\n */\nexport class CategoryStore {\n /** All loaded categories by ID */\n private categories: Map<string, Category> = new Map();\n\n /** Index by domain */\n private domainIndex: Map<RiskDomain, Set<string>> = new Map();\n\n /** Index by level */\n private levelIndex: Map<TestLevel, Set<string>> = new Map();\n\n /** Index by language */\n private languageIndex: Map<Language, Set<string>> = new Map();\n\n /** Index by priority */\n private priorityIndex: Map<Priority, Set<string>> = new Map();\n\n /** Search index: word -> category IDs */\n private searchIndex: Map<string, Set<string>> = new Map();\n\n /** Version tracking for loaded categories */\n private versions: Map<string, number> = new Map();\n\n /**\n * Get total number of loaded categories\n */\n get size(): number {\n return this.categories.size;\n }\n\n /**\n * Load a single category into the store\n */\n add(category: Category): Result<Category, ValidationError> {\n // Validate the category\n const validation = CategorySchema.safeParse(category);\n if (!validation.success) {\n return err(\n new ValidationError(\"Invalid category\", {\n categoryId: category.id,\n issues: validation.error.issues,\n })\n );\n }\n\n const validated = validation.data;\n\n // Check for duplicate ID\n const existing = this.categories.get(validated.id);\n if (existing !== undefined) {\n // Allow update if version is higher\n const existingVersion = this.versions.get(validated.id) ?? 0;\n if (validated.version <= existingVersion) {\n return err(\n new ValidationError(`Category ${validated.id} already exists with same or higher version`, {\n categoryId: validated.id,\n existingVersion,\n newVersion: validated.version,\n })\n );\n }\n // Remove old indexes before updating\n this.removeFromIndexes(existing);\n }\n\n // Store category\n this.categories.set(validated.id, validated);\n this.versions.set(validated.id, validated.version);\n\n // Update indexes\n this.addToIndexes(validated);\n\n return ok(validated);\n }\n\n /**\n * Get a category by ID\n */\n get(id: string): Result<Category, CategoryNotFoundError> {\n const category = this.categories.get(id);\n if (category === undefined) {\n return err(new CategoryNotFoundError(id));\n }\n return ok(category);\n }\n\n /**\n * Check if a category exists\n */\n has(id: string): boolean {\n return this.categories.has(id);\n }\n\n /**\n * Remove a category by ID\n */\n remove(id: string): Result<Category, CategoryNotFoundError> {\n const category = this.categories.get(id);\n if (category === undefined) {\n return err(new CategoryNotFoundError(id));\n }\n\n this.removeFromIndexes(category);\n this.categories.delete(id);\n this.versions.delete(id);\n\n return ok(category);\n }\n\n /**\n * List all categories, optionally filtered\n */\n list(filter?: CategoryFilter): CategorySummary[] {\n let ids: Set<string> | undefined;\n\n // Apply filters by intersecting index sets\n if (filter?.domain !== undefined) {\n const domainIds = this.domainIndex.get(filter.domain);\n if (domainIds === undefined) return []; // No categories in this domain\n ids = this.intersect(ids, domainIds);\n }\n if (filter?.level !== undefined) {\n const levelIds = this.levelIndex.get(filter.level);\n if (levelIds === undefined) return []; // No categories at this level\n ids = this.intersect(ids, levelIds);\n }\n if (filter?.language !== undefined) {\n const langIds = this.languageIndex.get(filter.language);\n if (langIds === undefined) return []; // No categories for this language\n ids = this.intersect(ids, langIds);\n }\n if (filter?.priority !== undefined) {\n const priorityIds = this.priorityIndex.get(filter.priority);\n if (priorityIds === undefined) return []; // No categories at this priority\n ids = this.intersect(ids, priorityIds);\n }\n\n // Get categories for matching IDs\n const categories: CategorySummary[] = [];\n const targetIds = ids ?? this.categories.keys();\n\n for (const id of targetIds) {\n const category = this.categories.get(id);\n if (category !== undefined) {\n // Apply severity filter if specified\n if (filter?.severity !== undefined && category.severity !== filter.severity) {\n continue;\n }\n categories.push(this.toSummary(category));\n }\n }\n\n // Sort by priority, then severity, then name\n return categories.sort((a, b) => {\n const priorityOrder = { P0: 0, P1: 1, P2: 2 };\n const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };\n\n const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];\n if (priorityDiff !== 0) return priorityDiff;\n\n const severityDiff = severityOrder[a.severity] - severityOrder[b.severity];\n if (severityDiff !== 0) return severityDiff;\n\n return a.name.localeCompare(b.name);\n });\n }\n\n /**\n * Get all categories in a specific domain\n */\n byDomain(domain: RiskDomain): CategorySummary[] {\n return this.list({ domain });\n }\n\n /**\n * Get all categories at a specific test level\n */\n byLevel(level: TestLevel): CategorySummary[] {\n return this.list({ level });\n }\n\n /**\n * Get all categories applicable to a language\n */\n byLanguage(language: Language): CategorySummary[] {\n return this.list({ language });\n }\n\n /**\n * Full-text search across categories\n */\n search(options: SearchOptions): SearchResult[] {\n const { query, filter, limit = 20 } = options;\n\n // Tokenize query\n const queryTokens = this.tokenize(query.toLowerCase());\n if (queryTokens.length === 0) {\n return [];\n }\n\n // Find matching category IDs\n const scores: Map<string, { score: number; matches: string[] }> = new Map();\n\n for (const token of queryTokens) {\n // Exact match\n const exactMatches = this.searchIndex.get(token);\n if (exactMatches !== undefined) {\n for (const id of exactMatches) {\n const current = scores.get(id) ?? { score: 0, matches: [] };\n current.score += 10; // Exact match weight\n current.matches.push(token);\n scores.set(id, current);\n }\n }\n\n // Prefix match\n for (const [indexToken, ids] of this.searchIndex) {\n if (indexToken.startsWith(token) && indexToken !== token) {\n for (const id of ids) {\n const current = scores.get(id) ?? { score: 0, matches: [] };\n current.score += 5; // Prefix match weight\n if (!current.matches.includes(token)) {\n current.matches.push(token);\n }\n scores.set(id, current);\n }\n }\n }\n }\n\n // Build results with category data\n const results: SearchResult[] = [];\n\n for (const [id, { score, matches }] of scores) {\n const category = this.categories.get(id);\n if (category === undefined) continue;\n\n // Apply filters\n if (filter !== undefined) {\n if (filter.domain !== undefined && category.domain !== filter.domain) continue;\n if (filter.level !== undefined && category.level !== filter.level) continue;\n if (filter.priority !== undefined && category.priority !== filter.priority) continue;\n if (filter.severity !== undefined && category.severity !== filter.severity) continue;\n if (\n filter.language !== undefined &&\n !category.applicableLanguages.includes(filter.language)\n ) {\n continue;\n }\n }\n\n results.push({\n category: this.toSummary(category),\n score,\n matches: [...new Set(matches)],\n });\n }\n\n // Sort by score descending, then by priority\n results.sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n const priorityOrder = { P0: 0, P1: 1, P2: 2 };\n return priorityOrder[a.category.priority] - priorityOrder[b.category.priority];\n });\n\n return results.slice(0, limit);\n }\n\n /**\n * Load categories from a directory of YAML files\n */\n async loadFromDirectory(dirPath: string): Promise<Result<number, ValidationError>> {\n const results = await this.loadYamlFilesRecursive(dirPath);\n const combined = all(results);\n\n if (!combined.success) {\n return combined;\n }\n\n return ok(combined.data.length);\n }\n\n /**\n * Load a single category from a YAML file\n */\n async loadFromFile(filePath: string): Promise<Result<Category, ValidationError>> {\n const result = await tryCatchAsync(async () => {\n const content = await fs.readFile(filePath, \"utf-8\");\n return YAML.parse(content) as unknown;\n });\n\n if (!result.success) {\n return err(\n new ValidationError(`Failed to read category file: ${filePath}`, {\n filePath,\n cause: result.error.message,\n })\n );\n }\n\n const validation = CategorySchema.safeParse(result.data);\n if (!validation.success) {\n return err(\n new ValidationError(`Invalid category in ${filePath}`, {\n filePath,\n issues: validation.error.issues,\n })\n );\n }\n\n return this.add(validation.data);\n }\n\n /**\n * Export all categories as an array\n */\n toArray(): Category[] {\n return Array.from(this.categories.values());\n }\n\n /**\n * Clear all categories and indexes\n */\n clear(): void {\n this.categories.clear();\n this.domainIndex.clear();\n this.levelIndex.clear();\n this.languageIndex.clear();\n this.priorityIndex.clear();\n this.searchIndex.clear();\n this.versions.clear();\n }\n\n /**\n * Get statistics about loaded categories\n */\n stats(): {\n total: number;\n byDomain: Record<string, number>;\n byLevel: Record<string, number>;\n byPriority: Record<string, number>;\n } {\n const byDomain: Record<string, number> = {};\n const byLevel: Record<string, number> = {};\n const byPriority: Record<string, number> = {};\n\n for (const [domain, ids] of this.domainIndex) {\n byDomain[domain] = ids.size;\n }\n for (const [level, ids] of this.levelIndex) {\n byLevel[level] = ids.size;\n }\n for (const [priority, ids] of this.priorityIndex) {\n byPriority[priority] = ids.size;\n }\n\n return {\n total: this.categories.size,\n byDomain,\n byLevel,\n byPriority,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private methods\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Add category to all indexes\n */\n private addToIndexes(category: Category): void {\n const id = category.id;\n\n // Domain index\n this.addToIndex(this.domainIndex, category.domain, id);\n\n // Level index\n this.addToIndex(this.levelIndex, category.level, id);\n\n // Language index (multiple)\n for (const lang of category.applicableLanguages) {\n this.addToIndex(this.languageIndex, lang, id);\n }\n\n // Priority index\n this.addToIndex(this.priorityIndex, category.priority, id);\n\n // Search index\n this.indexForSearch(category);\n }\n\n /**\n * Remove category from all indexes\n */\n private removeFromIndexes(category: Category): void {\n const id = category.id;\n\n this.removeFromIndex(this.domainIndex, category.domain, id);\n this.removeFromIndex(this.levelIndex, category.level, id);\n for (const lang of category.applicableLanguages) {\n this.removeFromIndex(this.languageIndex, lang, id);\n }\n this.removeFromIndex(this.priorityIndex, category.priority, id);\n this.removeFromSearchIndex(id);\n }\n\n /**\n * Add ID to an index map\n */\n private addToIndex<K>(index: Map<K, Set<string>>, key: K, id: string): void {\n let set = index.get(key);\n if (set === undefined) {\n set = new Set();\n index.set(key, set);\n }\n set.add(id);\n }\n\n /**\n * Remove ID from an index map\n */\n private removeFromIndex<K>(index: Map<K, Set<string>>, key: K, id: string): void {\n const set = index.get(key);\n if (set !== undefined) {\n set.delete(id);\n if (set.size === 0) {\n index.delete(key);\n }\n }\n }\n\n /**\n * Index category text for search\n */\n private indexForSearch(category: Category): void {\n const id = category.id;\n const textToIndex = [\n category.id,\n category.name,\n category.description,\n category.domain,\n category.level,\n ...category.applicableLanguages,\n ...(category.cves ?? []),\n ].join(\" \");\n\n const tokens = this.tokenize(textToIndex.toLowerCase());\n for (const token of tokens) {\n this.addToIndex(this.searchIndex, token, id);\n }\n }\n\n /**\n * Remove category from search index\n */\n private removeFromSearchIndex(id: string): void {\n for (const [token, ids] of this.searchIndex) {\n ids.delete(id);\n if (ids.size === 0) {\n this.searchIndex.delete(token);\n }\n }\n }\n\n /**\n * Tokenize text for search indexing\n */\n private tokenize(text: string): string[] {\n return text\n .split(/[\\s\\-_.,;:!?'\"()\\[\\]{}]+/)\n .filter((token) => token.length >= 2)\n .map((token) => token.toLowerCase());\n }\n\n /**\n * Intersect two sets, handling undefined\n * Returns empty set if either input is empty set (filter found no matches)\n */\n private intersect(a: Set<string> | undefined, b: Set<string> | undefined): Set<string> | undefined {\n if (a === undefined) return b;\n if (b === undefined) return a;\n // If b is empty (filter matched nothing), return empty set\n if (b.size === 0) return new Set();\n return new Set([...a].filter((x) => b.has(x)));\n }\n\n /**\n * Convert full category to summary\n */\n private toSummary(category: Category): CategorySummary {\n return CategorySummarySchema.parse({\n id: category.id,\n name: category.name,\n domain: category.domain,\n level: category.level,\n priority: category.priority,\n severity: category.severity,\n description: category.description,\n });\n }\n\n /**\n * Recursively load YAML files from directory\n */\n private async loadYamlFilesRecursive(dirPath: string): Promise<Result<Category, ValidationError>[]> {\n const results: Result<Category, ValidationError>[] = [];\n\n const loadResult = await tryCatchAsync(async () => {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries;\n });\n\n if (!loadResult.success) {\n return [\n err(\n new ValidationError(`Failed to read directory: ${dirPath}`, {\n dirPath,\n cause: loadResult.error.message,\n })\n ),\n ];\n }\n\n for (const entry of loadResult.data) {\n const fullPath = path.join(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n const subResults = await this.loadYamlFilesRecursive(fullPath);\n results.push(...subResults);\n } else if (entry.isFile() && (entry.name.endsWith(\".yml\") || entry.name.endsWith(\".yaml\"))) {\n const result = await this.loadFromFile(fullPath);\n results.push(result);\n }\n }\n\n return results;\n }\n}\n\n/**\n * Create a new CategoryStore instance\n */\nexport function createCategoryStore(): CategoryStore {\n return new CategoryStore();\n}\n","import chalk from \"chalk\";\n\n/**\n * Log levels from most to least verbose\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\n/**\n * Logger configuration\n */\ninterface LoggerConfig {\n level: LogLevel;\n prefix?: string;\n}\n\n/**\n * Simple logger with colored output\n */\nclass Logger {\n private level: LogLevel = \"info\";\n private prefix: string = \"\";\n\n /**\n * Configure the logger\n */\n configure(config: Partial<LoggerConfig>): void {\n if (config.level !== undefined) {\n this.level = config.level;\n }\n if (config.prefix !== undefined) {\n this.prefix = config.prefix;\n }\n }\n\n /**\n * Check if a log level should be output\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[this.level];\n }\n\n /**\n * Format a message with optional prefix\n */\n private format(message: string): string {\n return this.prefix ? `${this.prefix} ${message}` : message;\n }\n\n /**\n * Debug level logging (gray)\n */\n debug(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"debug\")) {\n console.debug(chalk.gray(this.format(message)), ...args);\n }\n }\n\n /**\n * Info level logging (default color)\n */\n info(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"info\")) {\n console.info(this.format(message), ...args);\n }\n }\n\n /**\n * Warning level logging (yellow)\n */\n warn(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"warn\")) {\n console.warn(chalk.yellow(this.format(message)), ...args);\n }\n }\n\n /**\n * Error level logging (red)\n */\n error(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"error\")) {\n console.error(chalk.red(this.format(message)), ...args);\n }\n }\n\n /**\n * Success message (green)\n */\n success(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"info\")) {\n console.info(chalk.green(this.format(message)), ...args);\n }\n }\n\n /**\n * Create a child logger with a prefix\n */\n child(prefix: string): Logger {\n const child = new Logger();\n child.level = this.level;\n child.prefix = this.prefix ? `${this.prefix} ${prefix}` : prefix;\n return child;\n }\n}\n\n/**\n * Global logger instance\n */\nexport const logger = new Logger();\n","/**\n * Tree-sitter AST Parser\n *\n * Provides AST parsing and querying capabilities using web-tree-sitter.\n * Supports Python, TypeScript, and JavaScript.\n */\n\nimport { existsSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nimport {\n Parser as TreeSitterParser,\n Language as TreeSitterLanguage,\n Tree as TreeSitterTree,\n Node as TreeSitterNode,\n Query as TreeSitterQuery,\n} from \"web-tree-sitter\";\n\nimport { PinataError, ParseError } from \"../../lib/errors.js\";\nimport { logger } from \"../../lib/logger.js\";\nimport { ok, err } from \"../../lib/result.js\";\n\nimport type { Language } from \"../../categories/schema/index.js\";\nimport type { Result } from \"../../lib/result.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Map of language to tree-sitter grammar name\n */\nconst LANGUAGE_GRAMMAR_MAP: Record<Language, string | null> = {\n python: \"tree-sitter-python\",\n typescript: \"tree-sitter-typescript\",\n javascript: \"tree-sitter-javascript\",\n go: null, // Not yet supported\n java: null, // Not yet supported\n rust: null, // Not yet supported\n};\n\n/**\n * AST match result\n */\nexport interface AstMatch {\n /** Matched node text */\n text: string;\n /** Node type (e.g., \"call_expression\") */\n nodeType: string;\n /** Starting line (0-indexed) */\n startLine: number;\n /** Ending line (0-indexed) */\n endLine: number;\n /** Starting column (0-indexed) */\n startColumn: number;\n /** Ending column (0-indexed) */\n endColumn: number;\n /** Capture name from the query (e.g., \"@call\") */\n captureName: string;\n /** Child captures from the same match group */\n captures: Map<string, string>;\n}\n\n/**\n * Query match with all captures\n */\ninterface QueryMatch {\n pattern: number;\n captures: Array<{\n name: string;\n node: TreeSitterNode;\n }>;\n}\n\n/**\n * Cached parser instances per language\n */\nconst parserCache = new Map<string, TreeSitterParser>();\n\n/**\n * Cached language instances\n */\nconst languageCache = new Map<string, TreeSitterLanguage>();\n\n/**\n * Whether Parser has been initialized\n */\nlet parserInitialized = false;\n\n/**\n * WASM file locations - tries multiple paths\n * web-tree-sitter uses web-tree-sitter.wasm as the main parser WASM file\n */\nfunction getWasmPaths(): string[] {\n return [\n // Development: relative to project root\n join(process.cwd(), \"node_modules/web-tree-sitter/web-tree-sitter.wasm\"),\n // Built: relative to dist\n join(__dirname, \"../../../node_modules/web-tree-sitter/web-tree-sitter.wasm\"),\n // Alternative locations\n join(__dirname, \"../../wasm/web-tree-sitter.wasm\"),\n join(process.cwd(), \"wasm/web-tree-sitter.wasm\"),\n ];\n}\n\n/**\n * Language WASM file locations\n */\nfunction getLanguageWasmPaths(language: string): string[] {\n const grammarName = `tree-sitter-${language}`;\n const wasmName = `${grammarName}.wasm`;\n\n return [\n // Project wasm directory (recommended)\n join(process.cwd(), \"wasm\", wasmName),\n // src directory\n join(process.cwd(), \"src/core/detection/wasm\", wasmName),\n // Fallback locations\n join(__dirname, \"wasm\", wasmName),\n join(__dirname, \"../../../wasm\", wasmName),\n ];\n}\n\n/**\n * Initialize the tree-sitter Parser\n */\nasync function initializeParser(): Promise<Result<void, PinataError>> {\n if (parserInitialized) {\n return ok(undefined);\n }\n\n const wasmPaths = getWasmPaths();\n let wasmPath: string | null = null;\n\n for (const path of wasmPaths) {\n if (existsSync(path)) {\n wasmPath = path;\n break;\n }\n }\n\n if (!wasmPath) {\n return err(\n new ParseError(\n \"tree-sitter.wasm not found. Run: npm run setup:wasm\",\n \"tree-sitter.wasm\"\n )\n );\n }\n\n try {\n await TreeSitterParser.init({\n locateFile: () => wasmPath,\n });\n parserInitialized = true;\n logger.debug(\"Tree-sitter initialized\");\n return ok(undefined);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to initialize tree-sitter: ${error instanceof Error ? error.message : String(error)}`,\n wasmPath\n )\n );\n }\n}\n\n/**\n * Load a language grammar\n */\nasync function loadLanguage(language: Language): Promise<Result<TreeSitterLanguage, PinataError>> {\n const grammarName = LANGUAGE_GRAMMAR_MAP[language];\n\n if (grammarName === null) {\n return err(\n new ParseError(`Language not supported for AST parsing: ${language}`, language)\n );\n }\n\n // Check cache\n const cached = languageCache.get(language);\n if (cached) {\n return ok(cached);\n }\n\n // Handle TypeScript special case (uses typescript grammar from tree-sitter-typescript)\n const langKey = language === \"typescript\" ? \"typescript\" : language;\n const wasmPaths = getLanguageWasmPaths(langKey);\n\n let wasmPath: string | null = null;\n for (const path of wasmPaths) {\n if (existsSync(path)) {\n wasmPath = path;\n break;\n }\n }\n\n if (!wasmPath) {\n return err(\n new ParseError(\n `Language WASM not found for ${language}. Run: npm run setup:wasm`,\n language\n )\n );\n }\n\n try {\n const lang = await TreeSitterLanguage.load(wasmPath);\n languageCache.set(language, lang);\n logger.debug(`Loaded language: ${language}`);\n return ok(lang);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to load language ${language}: ${error instanceof Error ? error.message : String(error)}`,\n wasmPath\n )\n );\n }\n}\n\n/**\n * Get or create a parser for a specific language\n */\nasync function getParser(language: Language): Promise<Result<TreeSitterParser, PinataError>> {\n // Initialize if needed\n const initResult = await initializeParser();\n if (!initResult.success) {\n return initResult;\n }\n\n // Check cache\n const cached = parserCache.get(language);\n if (cached) {\n return ok(cached);\n }\n\n // Load language\n const langResult = await loadLanguage(language);\n if (!langResult.success) {\n return langResult;\n }\n\n // Create parser\n const parser = new TreeSitterParser();\n parser.setLanguage(langResult.data);\n parserCache.set(language, parser);\n\n return ok(parser);\n}\n\n/**\n * Parse source code into an AST\n */\nexport async function parseSource(\n source: string,\n language: Language\n): Promise<Result<TreeSitterTree, PinataError>> {\n const parserResult = await getParser(language);\n if (!parserResult.success) {\n return parserResult;\n }\n\n try {\n const tree = parserResult.data.parse(source);\n if (!tree) {\n return err(\n new ParseError(\"Failed to parse source: parser returned null\", \"source\")\n );\n }\n return ok(tree);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to parse source: ${error instanceof Error ? error.message : String(error)}`,\n \"source\"\n )\n );\n }\n}\n\n/**\n * Execute a tree-sitter query against an AST\n *\n * Query syntax follows tree-sitter query format:\n * https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries\n *\n * @example\n * ```typescript\n * // Find all function calls\n * const query = \"(call_expression) @call\";\n *\n * // Find SQL execute with string concatenation\n * const query = `\n * (call_expression\n * function: (attribute\n * attribute: (identifier) @method)\n * arguments: (argument_list\n * (binary_operator) @concat))\n * (#match? @method \"execute|executemany\")\n * @call\n * `;\n * ```\n */\nexport async function executeQuery(\n tree: TreeSitterTree,\n queryString: string,\n language: Language\n): Promise<Result<AstMatch[], PinataError>> {\n const langResult = await loadLanguage(language);\n if (!langResult.success) {\n return langResult;\n }\n\n try {\n // Create query from language\n const query = new TreeSitterQuery(langResult.data, queryString);\n const matches = query.matches(tree.rootNode);\n\n const results: AstMatch[] = [];\n\n for (const match of matches) {\n // Get all captures for this match\n const captureMap = new Map<string, string>();\n for (const capture of match.captures) {\n captureMap.set(capture.name, capture.node.text);\n }\n\n // Create a result for each capture\n for (const capture of match.captures) {\n const node = capture.node;\n results.push({\n text: node.text,\n nodeType: node.type,\n startLine: node.startPosition.row,\n endLine: node.endPosition.row,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n captureName: capture.name,\n captures: captureMap,\n });\n }\n }\n\n return ok(results);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to execute query: ${error instanceof Error ? error.message : String(error)}`,\n \"query\"\n )\n );\n }\n}\n\n/**\n * AstPatternMatcher - Executes AST queries against source code\n *\n * Provides a higher-level interface for pattern detection using tree-sitter.\n */\nexport class AstPatternMatcher {\n private readonly sourceCache = new Map<string, TreeSitterTree>();\n private readonly log = logger.child(\"AstPatternMatcher\");\n\n /**\n * Check if AST parsing is available for a language\n */\n isLanguageSupported(language: Language): boolean {\n return LANGUAGE_GRAMMAR_MAP[language] !== null;\n }\n\n /**\n * Get list of supported languages\n */\n getSupportedLanguages(): Language[] {\n return Object.entries(LANGUAGE_GRAMMAR_MAP)\n .filter(([_, grammar]) => grammar !== null)\n .map(([lang]) => lang as Language);\n }\n\n /**\n * Parse source code and cache the AST\n */\n async parse(\n source: string,\n language: Language,\n cacheKey?: string\n ): Promise<Result<TreeSitterTree, PinataError>> {\n // Check cache\n if (cacheKey) {\n const cached = this.sourceCache.get(cacheKey);\n if (cached) {\n return ok(cached);\n }\n }\n\n const result = await parseSource(source, language);\n if (result.success && cacheKey) {\n this.sourceCache.set(cacheKey, result.data);\n }\n\n return result;\n }\n\n /**\n * Execute a query against source code\n *\n * @param source Source code to analyze\n * @param query Tree-sitter query string\n * @param language Programming language\n * @param cacheKey Optional cache key for the parsed AST\n */\n async query(\n source: string,\n query: string,\n language: Language,\n cacheKey?: string\n ): Promise<Result<AstMatch[], PinataError>> {\n const treeResult = await this.parse(source, language, cacheKey);\n if (!treeResult.success) {\n return treeResult;\n }\n\n return executeQuery(treeResult.data, query, language);\n }\n\n /**\n * Execute multiple queries against the same source\n */\n async queryMultiple(\n source: string,\n queries: string[],\n language: Language,\n cacheKey?: string\n ): Promise<Result<AstMatch[][], PinataError>> {\n const treeResult = await this.parse(source, language, cacheKey);\n if (!treeResult.success) {\n return treeResult;\n }\n\n const results: AstMatch[][] = [];\n for (const query of queries) {\n const queryResult = await executeQuery(treeResult.data, query, language);\n if (!queryResult.success) {\n return queryResult;\n }\n results.push(queryResult.data);\n }\n\n return ok(results);\n }\n\n /**\n * Clear the AST cache\n */\n clearCache(): void {\n this.sourceCache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getCacheStats(): { entries: number; languages: Set<string> } {\n return {\n entries: this.sourceCache.size,\n languages: new Set(parserCache.keys()),\n };\n }\n}\n\n/**\n * Create a new AstPatternMatcher instance\n */\nexport function createAstMatcher(): AstPatternMatcher {\n return new AstPatternMatcher();\n}\n\n/**\n * Predefined AST queries for common vulnerability patterns\n */\nexport const COMMON_AST_PATTERNS = {\n // Python: SQL injection via string formatting\n pythonSqlStringFormat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator\n operator: \"%\") @concat))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via f-string\n pythonSqlFString: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (string\n (interpolation)) @fstring))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via concatenation\n pythonSqlConcat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator\n operator: \"+\") @concat))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via .format()\n pythonSqlFormat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (call\n function: (attribute\n attribute: (identifier) @format_method))))\n (#match? @method \"^execute$|^executemany$\")\n (#match? @format_method \"^format$\")\n @call\n `,\n\n // JavaScript/TypeScript: SQL injection via template literal\n jsSqlTemplateLiteral: `\n (call_expression\n function: (member_expression\n property: (property_identifier) @method)\n arguments: (arguments\n (template_string\n (template_substitution)) @template))\n (#match? @method \"^query$|^execute$|^run$\")\n @call\n `,\n\n // JavaScript/TypeScript: SQL injection via concatenation\n jsSqlConcat: `\n (call_expression\n function: (member_expression\n property: (property_identifier) @method)\n arguments: (arguments\n (binary_expression\n operator: \"+\") @concat))\n (#match? @method \"^query$|^execute$|^run$\")\n @call\n `,\n\n // Python: Command injection via subprocess\n pythonCommandInjection: `\n (call\n function: (attribute\n object: (identifier) @module\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator) @concat))\n (#match? @module \"^subprocess$|^os$\")\n (#match? @method \"^call$|^run$|^Popen$|^system$\")\n @call\n `,\n\n // Python: Path traversal via open\n pythonPathTraversal: `\n (call\n function: (identifier) @func\n arguments: (argument_list\n (binary_operator\n operator: \"+\") @concat))\n (#match? @func \"^open$\")\n @call\n `,\n\n // JavaScript: eval usage\n jsEval: `\n (call_expression\n function: (identifier) @func)\n (#match? @func \"^eval$\")\n @call\n `,\n\n // TypeScript: Any type assertion\n tsAnyAssertion: `\n (as_expression\n type: (type_identifier) @type)\n (#match? @type \"^any$\")\n @assertion\n `,\n} as const;\n\n/**\n * Check if tree-sitter is properly initialized\n */\nexport async function checkTreeSitterSetup(): Promise<Result<{ ready: boolean; languages: Language[] }, PinataError>> {\n const initResult = await initializeParser();\n if (!initResult.success) {\n logger.debug(`Tree-sitter init failed: ${initResult.error.message}`);\n return ok({ ready: false, languages: [] });\n }\n\n const supportedLanguages: Language[] = [];\n for (const lang of [\"python\", \"typescript\", \"javascript\"] as Language[]) {\n const langResult = await loadLanguage(lang);\n if (langResult.success) {\n supportedLanguages.push(lang);\n } else {\n logger.debug(`Failed to load language ${lang}: ${langResult.error.message}`);\n }\n }\n\n return ok({\n ready: supportedLanguages.length > 0,\n languages: supportedLanguages,\n });\n}\n","/**\n * Core analysis engine\n *\n * This module contains:\n * - detection/ - Pattern matching against categories\n * - scanner/ - Codebase analysis orchestration\n * - ingestion/ - Code parsing and AST extraction (coming soon)\n * - generation/ - Test code generation (coming soon)\n */\n\nexport const VERSION = \"0.4.0\";\n\n// Detection module\nexport {\n PatternMatcher,\n createPatternMatcher,\n detectLanguage,\n getSupportedExtensions,\n isExtensionSupported,\n type PatternMatcherOptions,\n type ScanOptions,\n type PatternMatch,\n type FileScanResult,\n type AggregatedResults,\n} from \"./detection/index.js\";\n\n// Scanner module\nexport {\n Scanner,\n createScanner,\n SEVERITY_WEIGHTS,\n CONFIDENCE_WEIGHTS,\n PRIORITY_WEIGHTS,\n DEFAULT_TEST_PATTERNS,\n type ScannerOptions,\n type ScanResult,\n type Gap,\n type DomainCoverage,\n type CoverageMetrics,\n type FileStats,\n type PinataScore,\n type ScanSummary,\n} from \"./scanner/index.js\";\n","/**\n * AI Service Implementation\n *\n * Provides a unified interface for AI completions across providers.\n * Supports Anthropic Claude and OpenAI GPT models.\n */\n\nimport type {\n AIConfig,\n AIProvider,\n AIResponse,\n CompletionRequest,\n} from \"./types.js\";\n\nconst DEFAULT_CONFIG: Required<AIConfig> = {\n provider: \"anthropic\",\n apiKey: \"\",\n model: \"claude-sonnet-4-20250514\",\n maxTokens: 1024,\n temperature: 0.3,\n timeoutMs: 30000,\n};\n\nconst PROVIDER_MODELS: Record<AIProvider, string> = {\n anthropic: \"claude-sonnet-4-20250514\",\n openai: \"gpt-4o\",\n mock: \"mock-model\",\n};\n\nconst PROVIDER_ENDPOINTS: Record<AIProvider, string> = {\n anthropic: \"https://api.anthropic.com/v1/messages\",\n openai: \"https://api.openai.com/v1/chat/completions\",\n mock: \"\",\n};\n\n/**\n * AI Service for generating completions\n */\nexport class AIService {\n private readonly config: Required<AIConfig>;\n\n constructor(config: Partial<AIConfig> = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n apiKey: config.apiKey ?? this.getApiKeyFromEnv(config.provider ?? \"anthropic\"),\n model: config.model ?? PROVIDER_MODELS[config.provider ?? \"anthropic\"],\n };\n }\n\n /**\n * Get API key from environment variable\n * For config file support, use the sync version below\n */\n private getApiKeyFromEnv(provider: AIProvider): string {\n if (provider === \"mock\") return \"mock-key\";\n\n const envVar = provider === \"anthropic\" ? \"ANTHROPIC_API_KEY\" : \"OPENAI_API_KEY\";\n const envValue = process.env[envVar];\n if (envValue !== undefined && envValue.length > 0) {\n return envValue;\n }\n\n // Try sync config file read (works in Node.js)\n return this.getApiKeyFromConfig(provider);\n }\n\n /**\n * Read API key from config file synchronously\n * Uses require() for sync file access in constructor context\n */\n private getApiKeyFromConfig(provider: AIProvider): string {\n try {\n /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */\n const { existsSync, readFileSync } = require(\"node:fs\") as typeof import(\"fs\");\n const { homedir } = require(\"node:os\") as typeof import(\"os\");\n const { join } = require(\"node:path\") as typeof import(\"path\");\n /* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */\n\n const configPath = join(homedir(), \".pinata\", \"config.json\");\n if (!existsSync(configPath)) {\n return \"\";\n }\n\n const content = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(content) as {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n };\n\n return (provider === \"anthropic\" ? config.anthropicApiKey : config.openaiApiKey) ?? \"\";\n } catch {\n return \"\";\n }\n }\n\n /**\n * Check if the service is configured with an API key\n */\n isConfigured(): boolean {\n return this.config.provider === \"mock\" || this.config.apiKey.length > 0;\n }\n\n /**\n * Get the current provider\n */\n getProvider(): AIProvider {\n return this.config.provider;\n }\n\n /**\n * Generate a completion\n */\n async complete(request: CompletionRequest): Promise<AIResponse<string>> {\n const startTime = Date.now();\n\n if (!this.isConfigured()) {\n return {\n success: false,\n error: `API key not configured for ${this.config.provider}. Set ${this.config.provider === \"anthropic\" ? \"ANTHROPIC_API_KEY\" : \"OPENAI_API_KEY\"} environment variable.`,\n durationMs: Date.now() - startTime,\n };\n }\n\n if (this.config.provider === \"mock\") {\n return this.mockComplete(request, startTime);\n }\n\n try {\n const response = await this.callProvider(request);\n return {\n success: true,\n data: response.content,\n usage: response.usage,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n durationMs: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Generate a JSON completion (parses response as JSON)\n */\n async completeJSON<T>(request: CompletionRequest): Promise<AIResponse<T>> {\n const response = await this.complete({\n ...request,\n messages: [\n ...request.messages,\n {\n role: \"user\",\n content: \"\\n\\nRespond with valid JSON only. No markdown, no explanation.\",\n },\n ],\n });\n\n if (!response.success || response.data === undefined) {\n return {\n success: false,\n error: response.error ?? \"No response data\",\n durationMs: response.durationMs,\n };\n }\n\n try {\n // Extract JSON from response (handle markdown code blocks)\n let jsonStr = response.data;\n const jsonMatch = jsonStr.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (jsonMatch) {\n jsonStr = jsonMatch[1] ?? jsonStr;\n }\n\n // Try to find JSON object or array\n const objectMatch = jsonStr.match(/\\{[\\s\\S]*\\}/);\n const arrayMatch = jsonStr.match(/\\[[\\s\\S]*\\]/);\n jsonStr = objectMatch?.[0] ?? arrayMatch?.[0] ?? jsonStr;\n\n const parsed = JSON.parse(jsonStr.trim()) as T;\n const result: AIResponse<T> = {\n success: true,\n data: parsed,\n durationMs: response.durationMs,\n };\n if (response.usage) {\n result.usage = response.usage;\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: `Failed to parse JSON response: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n durationMs: response.durationMs,\n };\n }\n }\n\n /**\n * Call the AI provider API\n */\n private async callProvider(request: CompletionRequest): Promise<{\n content: string;\n usage: { inputTokens: number; outputTokens: number };\n }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n try {\n if (this.config.provider === \"anthropic\") {\n return await this.callAnthropic(request, controller.signal);\n } else {\n return await this.callOpenAI(request, controller.signal);\n }\n } finally {\n clearTimeout(timeout);\n }\n }\n\n /**\n * Call Anthropic API\n */\n private async callAnthropic(\n request: CompletionRequest,\n signal: AbortSignal\n ): Promise<{ content: string; usage: { inputTokens: number; outputTokens: number } }> {\n const messages = request.messages.filter((m) => m.role !== \"system\");\n\n const response = await fetch(PROVIDER_ENDPOINTS.anthropic, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.config.apiKey,\n \"anthropic-version\": \"2023-06-01\",\n },\n body: JSON.stringify({\n model: this.config.model,\n max_tokens: request.maxTokens ?? this.config.maxTokens,\n temperature: request.temperature ?? this.config.temperature,\n system: request.systemPrompt,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n }),\n signal,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{ text: string }>;\n usage: { input_tokens: number; output_tokens: number };\n };\n\n return {\n content: data.content[0]?.text ?? \"\",\n usage: {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n },\n };\n }\n\n /**\n * Call OpenAI API\n */\n private async callOpenAI(\n request: CompletionRequest,\n signal: AbortSignal\n ): Promise<{ content: string; usage: { inputTokens: number; outputTokens: number } }> {\n const messages: Array<{ role: string; content: string }> = [];\n\n if (request.systemPrompt !== undefined && request.systemPrompt.length > 0) {\n messages.push({ role: \"system\", content: request.systemPrompt });\n }\n\n for (const m of request.messages) {\n messages.push({ role: m.role, content: m.content });\n }\n\n const response = await fetch(PROVIDER_ENDPOINTS.openai, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n max_tokens: request.maxTokens ?? this.config.maxTokens,\n temperature: request.temperature ?? this.config.temperature,\n messages,\n }),\n signal,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>;\n usage: { prompt_tokens: number; completion_tokens: number };\n };\n\n return {\n content: data.choices[0]?.message.content ?? \"\",\n usage: {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n },\n };\n }\n\n /**\n * Mock completion for testing\n */\n private mockComplete(request: CompletionRequest, startTime: number): AIResponse<string> {\n const lastMessage = request.messages[request.messages.length - 1];\n const content = lastMessage?.content ?? \"\";\n\n // Generate mock responses based on content\n let response = \"Mock AI response\";\n\n if (content.includes(\"explain\") || content.includes(\"explanation\")) {\n response = JSON.stringify({\n summary: \"This code pattern may introduce a security vulnerability.\",\n explanation: \"The detected pattern suggests potential security risk.\",\n risk: \"An attacker could exploit this vulnerability to compromise the system.\",\n remediation: \"Use parameterized queries or proper input validation.\",\n safeExample: \"cursor.execute('SELECT * FROM users WHERE id = ?', (user_id,))\",\n });\n } else if (content.includes(\"variable\") || content.includes(\"template\")) {\n response = JSON.stringify({\n suggestions: [\n {\n name: \"className\",\n value: \"UserService\",\n reasoning: \"Based on the file name and context\",\n confidence: 0.8,\n },\n {\n name: \"functionName\",\n value: \"get_user\",\n reasoning: \"Extracted from the code snippet\",\n confidence: 0.9,\n },\n ],\n });\n } else if (content.includes(\"pattern\") || content.includes(\"regex\")) {\n response = JSON.stringify({\n suggestions: [\n {\n id: \"custom-sql-pattern\",\n pattern: \"execute\\\\s*\\\\(.*\\\\+\",\n description: \"Detects SQL execution with string concatenation\",\n confidence: \"medium\",\n matchExample: \"cursor.execute(query + user_input)\",\n safeExample: \"cursor.execute(query, (user_input,))\",\n reasoning: \"String concatenation in SQL queries is a common injection vector\",\n },\n ],\n });\n }\n\n return {\n success: true,\n data: response,\n usage: { inputTokens: 100, outputTokens: 50 },\n durationMs: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Create an AI service instance\n */\nexport function createAIService(config?: Partial<AIConfig>): AIService {\n return new AIService(config);\n}\n","/**\n * Gap Explainer\n *\n * Uses AI to generate natural language explanations of detected gaps.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, GapExplanation } from \"./types.js\";\nimport type { Category } from \"../categories/schema/index.js\";\nimport type { Gap } from \"../core/scanner/types.js\";\n\nconst SYSTEM_PROMPT = `You are a security expert explaining code vulnerabilities to developers.\nYour explanations should be:\n- Clear and actionable\n- Focused on the specific code pattern\n- Include concrete remediation steps\n- Reference relevant security standards (OWASP, CWE) when applicable\n\nAlways respond with valid JSON matching this structure:\n{\n \"summary\": \"1-2 sentence summary\",\n \"explanation\": \"Detailed explanation of the vulnerability\",\n \"risk\": \"What an attacker could do if this is exploited\",\n \"remediation\": \"Step-by-step instructions to fix\",\n \"safeExample\": \"Code example showing the safe pattern\",\n \"references\": [\"optional array of CVE/CWE/OWASP references\"]\n}`;\n\n/**\n * Explain a single gap\n */\nexport async function explainGap(\n gap: Gap,\n category?: Category,\n config?: Partial<AIConfig>\n): Promise<AIResponse<GapExplanation>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n return {\n success: false,\n error: \"AI service not configured\",\n durationMs: 0,\n };\n }\n\n const prompt = buildExplainPrompt(gap, category);\n\n const response = await ai.completeJSON<GapExplanation>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 1024,\n temperature: 0.3,\n });\n\n return response;\n}\n\n/**\n * Explain multiple gaps in batch\n */\nexport async function explainGaps(\n gaps: Gap[],\n categories?: Map<string, Category>,\n config?: Partial<AIConfig>\n): Promise<Map<string, AIResponse<GapExplanation>>> {\n const results = new Map<string, AIResponse<GapExplanation>>();\n\n // Process in parallel with concurrency limit\n const BATCH_SIZE = 5;\n\n for (let i = 0; i < gaps.length; i += BATCH_SIZE) {\n const batch = gaps.slice(i, i + BATCH_SIZE);\n const promises = batch.map(async (gap) => {\n const category = categories?.get(gap.categoryId);\n const result = await explainGap(gap, category, config);\n return { key: `${gap.filePath}:${gap.lineStart}:${gap.categoryId}`, result };\n });\n\n const batchResults = await Promise.all(promises);\n for (const { key, result } of batchResults) {\n results.set(key, result);\n }\n }\n\n return results;\n}\n\n/**\n * Build the explanation prompt for a gap\n */\nfunction buildExplainPrompt(gap: Gap, category?: Category): string {\n const parts: string[] = [];\n\n parts.push(`Explain this security finding:\\n`);\n\n parts.push(`**Category:** ${gap.categoryName} (${gap.categoryId})`);\n parts.push(`**Severity:** ${gap.severity}`);\n parts.push(`**Confidence:** ${gap.confidence}`);\n parts.push(`**File:** ${gap.filePath}`);\n parts.push(`**Line:** ${gap.lineStart}`);\n\n if (gap.codeSnippet) {\n parts.push(`\\n**Code:**\\n\\`\\`\\`\\n${gap.codeSnippet}\\n\\`\\`\\``);\n }\n\n parts.push(`\\n**Pattern:** ${gap.patternId}`);\n parts.push(`**Detection Type:** ${gap.patternType}`);\n\n if (category) {\n parts.push(`\\n**Category Description:** ${category.description}`);\n\n if (category.cves && category.cves.length > 0) {\n parts.push(`**Related CVEs:** ${category.cves.join(\", \")}`);\n }\n\n if (category.references && category.references.length > 0) {\n parts.push(`**References:** ${category.references.slice(0, 3).join(\", \")}`);\n }\n }\n\n parts.push(`\\nProvide a clear, actionable explanation for a developer.`);\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Generate a quick summary without AI (fallback)\n */\nexport function generateFallbackExplanation(gap: Gap): GapExplanation {\n const summaries: Record<string, string> = {\n \"sql-injection\": \"SQL query constructed with user input may allow injection attacks.\",\n \"xss\": \"User input rendered without escaping may allow script injection.\",\n \"command-injection\": \"Shell command constructed with user input may allow command execution.\",\n \"path-traversal\": \"File path constructed with user input may allow directory traversal.\",\n \"hardcoded-secrets\": \"Sensitive credentials found in source code.\",\n \"deserialization\": \"Untrusted data deserialization may allow code execution.\",\n \"ssrf\": \"Server-side request with user-controlled URL may allow internal access.\",\n \"xxe\": \"XML parser may be vulnerable to external entity injection.\",\n \"csrf\": \"State-changing request lacks CSRF protection.\",\n \"ldap-injection\": \"LDAP query constructed with user input may allow injection.\",\n };\n\n const remediations: Record<string, string> = {\n \"sql-injection\": \"Use parameterized queries or prepared statements. Never concatenate user input into SQL strings.\",\n \"xss\": \"Escape all user input before rendering in HTML. Use framework auto-escaping features.\",\n \"command-injection\": \"Avoid shell execution with user input. Use allowlists and subprocess arrays instead of shell strings.\",\n \"path-traversal\": \"Validate and sanitize file paths. Use path.resolve() and verify the result is within allowed directories.\",\n \"hardcoded-secrets\": \"Move secrets to environment variables or a secrets manager. Never commit credentials to source control.\",\n \"deserialization\": \"Avoid deserializing untrusted data. If necessary, use safe formats like JSON instead of pickle/yaml.\",\n \"ssrf\": \"Validate and allowlist URLs. Block private IP ranges and localhost.\",\n \"xxe\": \"Disable external entity processing in XML parser configuration.\",\n \"csrf\": \"Implement CSRF tokens for all state-changing requests.\",\n \"ldap-injection\": \"Escape special LDAP characters in user input. Use parameterized LDAP queries.\",\n };\n\n const summary = summaries[gap.categoryId] ?? `Potential ${gap.categoryName} vulnerability detected.`;\n const remediation = remediations[gap.categoryId] ?? `Review the code for security issues and apply appropriate fixes.`;\n\n return {\n summary,\n explanation: `The pattern \"${gap.patternId}\" detected a potential ${gap.categoryName} vulnerability at line ${gap.lineStart}. This type of issue has ${gap.severity} severity and was detected with ${gap.confidence} confidence.`,\n risk: `If exploited, this vulnerability could compromise the security of the application. Severity: ${gap.severity}.`,\n remediation,\n references: [],\n };\n}\n","/**\n * AI Template Variable Filler\n *\n * Uses AI to intelligently fill template variables based on context.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, VariableSuggestion } from \"./types.js\";\nimport type { TemplateVariable } from \"../categories/schema/index.js\";\nimport type { Gap } from \"../core/scanner/types.js\";\n\nconst SYSTEM_PROMPT = `You are an expert at analyzing code and extracting meaningful variable values for test generation.\nGiven a code snippet and a list of template variables, suggest appropriate values for each variable.\n\nFor each variable, analyze:\n1. The code snippet to extract relevant information (class names, function names, etc.)\n2. The variable description to understand what's needed\n3. The variable type to ensure correct formatting\n\nAlways respond with valid JSON matching this structure:\n{\n \"suggestions\": [\n {\n \"name\": \"variableName\",\n \"value\": \"suggested value\",\n \"reasoning\": \"why this value was chosen\",\n \"confidence\": 0.0-1.0\n }\n ]\n}\n\nFor arrays, use: \"value\": [\"item1\", \"item2\"]\nFor booleans, use: \"value\": true or \"value\": false\nFor numbers, use: \"value\": 42`;\n\nexport interface VariableFillRequest {\n /** Code snippet for context */\n codeSnippet: string;\n /** File path for additional context */\n filePath: string;\n /** Template variables to fill */\n variables: TemplateVariable[];\n /** Optional gap information */\n gap?: Gap;\n /** Any pre-filled values to exclude */\n existingValues?: Record<string, unknown>;\n}\n\nexport interface VariableFillResult {\n /** Suggested values for each variable */\n suggestions: Map<string, VariableSuggestion>;\n /** Variables that couldn't be filled */\n unfilled: string[];\n /** Merged values (suggestions + existing) */\n values: Record<string, unknown>;\n}\n\n/**\n * Suggest variable values for a template\n */\nexport async function suggestVariables(\n request: VariableFillRequest,\n config?: Partial<AIConfig>\n): Promise<AIResponse<VariableFillResult>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n // Fall back to rule-based extraction\n return {\n success: true,\n data: extractVariablesFromCode(request),\n durationMs: 0,\n };\n }\n\n const prompt = buildVariablePrompt(request);\n const startTime = Date.now();\n\n const response = await ai.completeJSON<{ suggestions: VariableSuggestion[] }>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 1024,\n temperature: 0.2,\n });\n\n if (!response.success || !response.data) {\n // Fall back to rule-based extraction\n return {\n success: true,\n data: extractVariablesFromCode(request),\n durationMs: Date.now() - startTime,\n };\n }\n\n // Process AI suggestions\n const suggestions = new Map<string, VariableSuggestion>();\n const unfilled: string[] = [];\n const values: Record<string, unknown> = { ...request.existingValues };\n\n const suggestionsList = response.data.suggestions ?? [];\n for (const suggestion of suggestionsList) {\n suggestions.set(suggestion.name, suggestion);\n if (!(suggestion.name in values)) {\n values[suggestion.name] = suggestion.value;\n }\n }\n\n // Check for unfilled variables\n for (const variable of request.variables) {\n if (!suggestions.has(variable.name) && !(variable.name in values)) {\n if (variable.defaultValue !== undefined) {\n values[variable.name] = variable.defaultValue;\n } else {\n unfilled.push(variable.name);\n }\n }\n }\n\n const result: AIResponse<VariableFillResult> = {\n success: true,\n data: { suggestions, unfilled, values },\n durationMs: response.durationMs,\n };\n\n if (response.usage) {\n result.usage = response.usage;\n }\n\n return result;\n}\n\n/**\n * Build the prompt for variable suggestion\n */\nfunction buildVariablePrompt(request: VariableFillRequest): string {\n const parts: string[] = [];\n\n parts.push(\"Analyze this code and suggest values for the template variables:\\n\");\n\n parts.push(\"**Code:**\");\n parts.push(\"```\");\n parts.push(request.codeSnippet);\n parts.push(\"```\\n\");\n\n parts.push(`**File:** ${request.filePath}\\n`);\n\n if (request.gap) {\n parts.push(`**Category:** ${request.gap.categoryName}`);\n parts.push(`**Line:** ${request.gap.lineStart}\\n`);\n }\n\n parts.push(\"**Variables to fill:**\");\n for (const variable of request.variables) {\n const required = variable.required ? \" (required)\" : \" (optional)\";\n const defaultVal = variable.defaultValue !== undefined\n ? ` [default: ${JSON.stringify(variable.defaultValue)}]`\n : \"\";\n parts.push(`- ${variable.name} (${variable.type})${required}${defaultVal}: ${variable.description}`);\n }\n\n if (request.existingValues && Object.keys(request.existingValues).length > 0) {\n parts.push(\"\\n**Already provided:**\");\n for (const [name, value] of Object.entries(request.existingValues)) {\n parts.push(`- ${name}: ${JSON.stringify(value)}`);\n }\n }\n\n parts.push(\"\\nExtract appropriate values from the code context.\");\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Rule-based variable extraction (fallback when AI is not available)\n */\nfunction extractVariablesFromCode(request: VariableFillRequest): VariableFillResult {\n const suggestions = new Map<string, VariableSuggestion>();\n const unfilled: string[] = [];\n const values: Record<string, unknown> = { ...request.existingValues };\n\n const code = request.codeSnippet;\n const filePath = request.filePath;\n\n for (const variable of request.variables) {\n if (variable.name in values) continue;\n\n let value: unknown = undefined;\n let reasoning = \"\";\n let confidence = 0;\n\n switch (variable.name.toLowerCase()) {\n case \"classname\":\n case \"class_name\": {\n // Extract class name from code or file\n const classMatch = code.match(/class\\s+(\\w+)/);\n if (classMatch) {\n value = classMatch[1];\n reasoning = \"Extracted from class definition in code\";\n confidence = 0.9;\n } else {\n // Try to infer from file name\n const fileName = filePath.split(\"/\").pop()?.replace(/\\.\\w+$/, \"\") ?? \"\";\n value = toPascalCase(fileName);\n reasoning = \"Inferred from file name\";\n confidence = 0.6;\n }\n break;\n }\n\n case \"functionname\":\n case \"function_name\":\n case \"methodname\": {\n // Extract function name from code\n const funcMatch = code.match(/(?:def|function|async function)\\s+(\\w+)/);\n if (funcMatch) {\n value = funcMatch[1];\n reasoning = \"Extracted from function definition\";\n confidence = 0.9;\n }\n break;\n }\n\n case \"modulepath\":\n case \"module_path\": {\n // Convert file path to module path\n value = filePath\n .replace(/\\.[jt]sx?$/, \"\")\n .replace(/\\.py$/, \"\")\n .replace(/\\//g, \".\")\n .replace(/^\\.+/, \"\");\n reasoning = \"Derived from file path\";\n confidence = 0.7;\n break;\n }\n\n case \"tablename\":\n case \"table_name\": {\n // Look for table name in SQL\n const tableMatch = code.match(/(?:FROM|INTO|UPDATE)\\s+(\\w+)/i);\n if (tableMatch) {\n value = tableMatch[1];\n reasoning = \"Extracted from SQL statement\";\n confidence = 0.8;\n } else {\n value = \"users\";\n reasoning = \"Default table name\";\n confidence = 0.3;\n }\n break;\n }\n\n case \"exceptionclass\":\n case \"exception_class\": {\n value = \"ValueError\";\n reasoning = \"Common exception for input validation\";\n confidence = 0.5;\n break;\n }\n\n case \"dbclient\":\n case \"db_client\": {\n // Look for database client variable\n const clientMatch = code.match(/(db|conn|connection|client|cursor)\\s*[=.]/i);\n if (clientMatch) {\n value = clientMatch[1];\n reasoning = \"Extracted from code\";\n confidence = 0.7;\n } else {\n value = \"db\";\n reasoning = \"Default database client name\";\n confidence = 0.4;\n }\n break;\n }\n\n case \"functioncall\":\n case \"function_call\": {\n const funcName = values[\"functionName\"] ?? values[\"function_name\"];\n if (typeof funcName === \"string\" && funcName.length > 0) {\n value = `${funcName}(user_input)`;\n reasoning = \"Constructed from function name\";\n confidence = 0.6;\n }\n break;\n }\n\n case \"fixtures\": {\n value = \"db_session\";\n reasoning = \"Common pytest fixture\";\n confidence = 0.5;\n break;\n }\n\n default:\n // Use default value if available\n if (variable.defaultValue !== undefined) {\n value = variable.defaultValue;\n reasoning = \"Using default value\";\n confidence = 1.0;\n }\n }\n\n if (value !== undefined) {\n suggestions.set(variable.name, {\n name: variable.name,\n value: value as string | number | boolean | string[],\n reasoning,\n confidence,\n });\n values[variable.name] = value;\n } else if (variable.required) {\n unfilled.push(variable.name);\n }\n }\n\n return { suggestions, unfilled, values };\n}\n\n/**\n * Convert string to PascalCase\n */\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n","/**\n * AI Pattern Suggester\n *\n * Uses AI to suggest new detection patterns based on code samples.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, PatternSuggestion } from \"./types.js\";\n\nconst SYSTEM_PROMPT = `You are an expert at creating regex patterns for detecting security vulnerabilities in code.\nGiven vulnerable code samples, generate regex patterns that will detect similar vulnerabilities.\n\nYour patterns should:\n1. Be specific enough to avoid false positives\n2. Be general enough to catch variations\n3. Use standard regex syntax (no lookbehind for compatibility)\n4. Include examples of what matches and what doesn't\n\nAlways respond with valid JSON matching this structure:\n{\n \"suggestions\": [\n {\n \"id\": \"pattern-id-kebab-case\",\n \"pattern\": \"regex pattern here\",\n \"description\": \"What this pattern detects\",\n \"confidence\": \"high|medium|low\",\n \"matchExample\": \"code that should match\",\n \"safeExample\": \"similar code that should NOT match\",\n \"reasoning\": \"Why this pattern works\"\n }\n ]\n}\n\nImportant:\n- Escape backslashes properly for JSON (use \\\\\\\\s not \\\\s)\n- Test your patterns mentally against the examples\n- Prefer simpler patterns that are less likely to cause ReDoS`;\n\nexport interface PatternSuggestionRequest {\n /** Category to suggest patterns for */\n category: string;\n /** Vulnerable code samples */\n vulnerableCode: string[];\n /** Safe code samples (to avoid matching) */\n safeCode?: string[];\n /** Language of the code */\n language: string;\n /** Existing patterns to avoid duplicating */\n existingPatterns?: string[];\n /** Maximum number of suggestions */\n maxSuggestions?: number;\n}\n\nexport interface PatternSuggestionResult {\n /** Suggested patterns */\n suggestions: PatternSuggestion[];\n /** Patterns that were tested but had issues */\n rejected: Array<{\n pattern: string;\n reason: string;\n }>;\n}\n\n/**\n * Suggest patterns based on code samples\n */\nexport async function suggestPatterns(\n request: PatternSuggestionRequest,\n config?: Partial<AIConfig>\n): Promise<AIResponse<PatternSuggestionResult>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n return {\n success: false,\n error: \"AI service not configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY.\",\n durationMs: 0,\n };\n }\n\n const prompt = buildPatternPrompt(request);\n\n const response = await ai.completeJSON<{ suggestions: PatternSuggestion[] }>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 2048,\n temperature: 0.3,\n });\n\n if (!response.success || !response.data) {\n return {\n success: false,\n error: response.error ?? \"Failed to generate patterns\",\n durationMs: response.durationMs,\n };\n }\n\n // Validate and test each pattern\n const validated = validatePatterns(\n response.data.suggestions ?? [],\n request.vulnerableCode,\n request.safeCode ?? []\n );\n\n const result: AIResponse<PatternSuggestionResult> = {\n success: true,\n data: validated,\n durationMs: response.durationMs,\n };\n\n if (response.usage) {\n result.usage = response.usage;\n }\n\n return result;\n}\n\n/**\n * Build the prompt for pattern suggestion\n */\nfunction buildPatternPrompt(request: PatternSuggestionRequest): string {\n const parts: string[] = [];\n\n parts.push(`Generate regex patterns to detect ${request.category} vulnerabilities in ${request.language} code.\\n`);\n\n parts.push(\"**Vulnerable code samples (patterns SHOULD match these):**\");\n for (let i = 0; i < request.vulnerableCode.length; i++) {\n parts.push(`\\nExample ${i + 1}:`);\n parts.push(\"```\");\n parts.push(request.vulnerableCode[i] ?? \"\");\n parts.push(\"```\");\n }\n\n if (request.safeCode && request.safeCode.length > 0) {\n parts.push(\"\\n**Safe code samples (patterns should NOT match these):**\");\n for (let i = 0; i < request.safeCode.length; i++) {\n parts.push(`\\nSafe ${i + 1}:`);\n parts.push(\"```\");\n parts.push(request.safeCode[i] ?? \"\");\n parts.push(\"```\");\n }\n }\n\n if (request.existingPatterns && request.existingPatterns.length > 0) {\n parts.push(\"\\n**Existing patterns (avoid duplicating):**\");\n for (const pattern of request.existingPatterns) {\n parts.push(`- ${pattern}`);\n }\n }\n\n parts.push(`\\nGenerate up to ${request.maxSuggestions ?? 3} distinct patterns.`);\n parts.push(\"Focus on patterns that will have high precision (low false positives).\");\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Validate patterns against test samples\n */\nfunction validatePatterns(\n suggestions: PatternSuggestion[],\n vulnerableCode: string[],\n safeCode: string[]\n): PatternSuggestionResult {\n const validated: PatternSuggestion[] = [];\n const rejected: Array<{ pattern: string; reason: string }> = [];\n\n for (const suggestion of suggestions) {\n try {\n // Test if pattern compiles\n const regex = new RegExp(suggestion.pattern, \"gm\");\n\n // Test against vulnerable samples\n let matchCount = 0;\n for (const code of vulnerableCode) {\n regex.lastIndex = 0;\n if (regex.test(code)) {\n matchCount++;\n }\n }\n\n // Test against safe samples\n let falsePositives = 0;\n for (const code of safeCode) {\n regex.lastIndex = 0;\n if (regex.test(code)) {\n falsePositives++;\n }\n }\n\n // Check for ReDoS potential (simple heuristic)\n if (hasRedosPotential(suggestion.pattern)) {\n rejected.push({\n pattern: suggestion.pattern,\n reason: \"Pattern may be vulnerable to ReDoS\",\n });\n continue;\n }\n\n // Accept if it matches at least some vulnerable code\n if (matchCount > 0) {\n // Adjust confidence based on actual results\n if (falsePositives > 0 && suggestion.confidence === \"high\") {\n suggestion.confidence = \"medium\";\n }\n if (matchCount < vulnerableCode.length / 2 && suggestion.confidence === \"high\") {\n suggestion.confidence = \"medium\";\n }\n validated.push(suggestion);\n } else {\n rejected.push({\n pattern: suggestion.pattern,\n reason: `Pattern did not match any vulnerable samples (0/${vulnerableCode.length})`,\n });\n }\n } catch (error) {\n rejected.push({\n pattern: suggestion.pattern,\n reason: `Invalid regex: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n });\n }\n }\n\n return { suggestions: validated, rejected };\n}\n\n/**\n * Check for potential ReDoS patterns (simple heuristic)\n */\nfunction hasRedosPotential(pattern: string): boolean {\n // Check for nested quantifiers like (a+)+ or (a*)*\n if (/\\([^)]*[+*][^)]*\\)[+*]/.test(pattern)) {\n return true;\n }\n\n // Check for overlapping alternations with quantifiers\n if (/\\([^)]*\\|[^)]*\\)[+*]/.test(pattern)) {\n // More specific check for dangerous patterns\n const alternationMatch = pattern.match(/\\(([^)]+)\\)/g);\n if (alternationMatch) {\n for (const alt of alternationMatch) {\n // Check if alternation branches can match same input\n if (/\\w+\\|\\w*\\w/.test(alt) && /[+*]/.test(alt)) {\n return true;\n }\n }\n }\n }\n\n return false;\n}\n\n/**\n * Format a pattern suggestion as YAML for adding to category definitions\n */\nexport function formatPatternAsYaml(suggestion: PatternSuggestion, language: string): string {\n // Escape the pattern for YAML\n const escapedPattern = suggestion.pattern\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"');\n\n return ` - id: ${suggestion.id}\n type: regex\n language: ${language}\n pattern: \"${escapedPattern}\"\n confidence: ${suggestion.confidence}\n description: ${suggestion.description}`;\n}\n\n/**\n * Suggest patterns from missed vulnerabilities (for improving detection)\n */\nexport async function suggestPatternsFromMissed(\n category: string,\n missedCode: string[],\n detectedCode: string[],\n language: string,\n config?: Partial<AIConfig>\n): Promise<AIResponse<PatternSuggestionResult>> {\n // The missed code is what we WANT to detect\n // The detected code can help understand what patterns we already catch\n return suggestPatterns(\n {\n category,\n vulnerableCode: missedCode,\n safeCode: [], // We don't have safe code in this context\n language,\n maxSuggestions: 5,\n },\n config\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/categories/schema/category.schema.ts","../src/categories/schema/example.schema.ts","../src/categories/schema/pattern.schema.ts","../src/categories/schema/template.schema.ts","../src/categories/schema/index.ts","../src/lib/errors.ts","../src/lib/result.ts","../src/categories/store/category-store.ts","../src/lib/logger.ts","../src/core/detection/ast-parser.ts","../src/core/discovery/attack-surface.ts","../src/core/index.ts","../src/ai/service.ts","../src/ai/explainer.ts","../src/ai/template-filler.ts","../src/ai/pattern-suggester.ts"],"names":["ID_PATTERN","z","__filename","join","SYSTEM_PROMPT"],"mappings":"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","file":"index.js","sourcesContent":["import { z } from \"zod\";\n\n/**\n * Risk domains representing different areas of test coverage\n */\nexport const RiskDomainSchema = z.enum([\n \"security\",\n \"data\",\n \"concurrency\",\n \"input\",\n \"resource\",\n \"reliability\",\n \"performance\",\n \"platform\",\n \"business\",\n \"compliance\",\n]);\n\n/**\n * Test levels from unit to chaos engineering\n */\nexport const TestLevelSchema = z.enum([\n \"unit\",\n \"integration\",\n \"system\",\n \"chaos\",\n]);\n\n/**\n * Priority levels for categorizing importance\n */\nexport const PrioritySchema = z.enum([\"P0\", \"P1\", \"P2\"]);\n\n/**\n * Severity levels for gap findings\n */\nexport const SeveritySchema = z.enum([\"critical\", \"high\", \"medium\", \"low\"]);\n\n/**\n * Confidence levels for pattern detection\n */\nexport const ConfidenceSchema = z.enum([\"high\", \"medium\", \"low\"]);\n\n/**\n * Supported programming languages\n */\nexport const LanguageSchema = z.enum([\n \"python\",\n \"typescript\",\n \"javascript\",\n \"go\",\n \"java\",\n \"rust\",\n]);\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Base category schema without nested types\n * Full CategorySchema is defined in index.ts to avoid circular imports\n */\nexport const CategoryBaseSchema = z.object({\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n version: z.number().int().positive(),\n name: z.string().min(1, \"Name is required\").max(100, \"Name too long\"),\n description: z\n .string()\n .min(10, \"Description must be at least 10 characters\")\n .max(2000, \"Description too long\"),\n domain: RiskDomainSchema,\n level: TestLevelSchema,\n priority: PrioritySchema,\n severity: SeveritySchema,\n applicableLanguages: z.array(LanguageSchema).min(1, \"At least one language required\"),\n cves: z.array(z.string()).optional(),\n references: z.array(z.string().url(\"Invalid URL\")).optional(),\n createdAt: z.coerce.date(),\n updatedAt: z.coerce.date(),\n});\n\n// Inferred types\nexport type RiskDomain = z.infer<typeof RiskDomainSchema>;\nexport type TestLevel = z.infer<typeof TestLevelSchema>;\nexport type Priority = z.infer<typeof PrioritySchema>;\nexport type Severity = z.infer<typeof SeveritySchema>;\nexport type Confidence = z.infer<typeof ConfidenceSchema>;\nexport type Language = z.infer<typeof LanguageSchema>;\nexport type CategoryBase = z.infer<typeof CategoryBaseSchema>;\n\n/**\n * All available risk domains\n */\nexport const RISK_DOMAINS = RiskDomainSchema.options;\n\n/**\n * All available test levels\n */\nexport const TEST_LEVELS = TestLevelSchema.options;\n\n/**\n * All available languages\n */\nexport const LANGUAGES = LanguageSchema.options;\n","import { z } from \"zod\";\n\nimport { LanguageSchema, SeveritySchema } from \"./category.schema.js\";\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for example vulnerable code and corresponding tests\n */\nexport const ExampleSchema = z.object({\n /** Unique identifier for this example */\n name: z\n .string()\n .regex(ID_PATTERN, \"Name must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Explanation of the vulnerability/edge case concept */\n concept: z.string().min(20, \"Concept must be at least 20 characters\"),\n\n /** Example of vulnerable or problematic code */\n vulnerableCode: z.string().min(10, \"Vulnerable code must be at least 10 characters\"),\n\n /** Example test code that catches this vulnerability */\n testCode: z.string().min(50, \"Test code must be at least 50 characters\"),\n\n /** Programming language of the example */\n language: LanguageSchema,\n\n /** Severity if this vulnerability is exploited */\n severity: SeveritySchema,\n\n /** Optional related CVE identifier */\n cve: z.string().optional(),\n\n /** Optional link to more information */\n reference: z.string().url().optional(),\n});\n\n// Inferred types\nexport type Example = z.infer<typeof ExampleSchema>;\n","import { z } from \"zod\";\n\nimport { ConfidenceSchema, LanguageSchema } from \"./category.schema.js\";\n\n/**\n * Types of detection patterns\n * - ast: Tree-sitter AST queries\n * - regex: Regular expression patterns\n * - semantic: LLM-assisted semantic analysis\n */\nexport const PatternTypeSchema = z.enum([\"ast\", \"regex\", \"semantic\"]);\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for detection patterns that identify code susceptible to a category.\n *\n * The optional `sources` and `sanitizers` fields enable lightweight taint analysis:\n * when a pattern matches a sink, the scanner checks whether a source (user input)\n * is present in the same scope and whether a sanitizer intervenes. Without a source,\n * the match confidence is downgraded. With a sanitizer, the match is suppressed.\n */\nexport const DetectionPatternSchema = z.object({\n /** Unique identifier for this pattern */\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Type of pattern matching to use */\n type: PatternTypeSchema,\n\n /** Target programming language */\n language: LanguageSchema,\n\n /** The pattern string (AST query, regex, or semantic description) */\n pattern: z.string().min(1, \"Pattern is required\"),\n\n /** How confident we are when this pattern matches */\n confidence: ConfidenceSchema,\n\n /** Human-readable description of what this pattern detects */\n description: z.string().min(10, \"Description must be at least 10 characters\"),\n\n /** Optional pattern that indicates code is NOT vulnerable (false positive filter) */\n negativePattern: z.string().optional(),\n\n /** Optional list of framework contexts where this pattern applies */\n frameworks: z.array(z.string()).optional(),\n\n /** Regex patterns identifying taint sources (user input entry points) in the same scope */\n sources: z.array(z.string()).optional(),\n\n /** Regex patterns identifying sanitizers that neutralize tainted data */\n sanitizers: z.array(z.string()).optional(),\n});\n\n/**\n * Schema for a detection result (pattern match in code)\n */\nexport const DetectionResultSchema = z.object({\n /** ID of the pattern that matched */\n patternId: z.string(),\n\n /** Category this detection belongs to */\n categoryId: z.string(),\n\n /** File path where detection occurred */\n filePath: z.string(),\n\n /** Starting line number (1-indexed) */\n lineStart: z.number().int().positive(),\n\n /** Ending line number (1-indexed) */\n lineEnd: z.number().int().positive(),\n\n /** Code snippet that matched */\n codeSnippet: z.string(),\n\n /** Confidence of this specific match */\n confidence: ConfidenceSchema,\n\n /** Optional additional context */\n context: z.record(z.unknown()).optional(),\n});\n\n// Inferred types\nexport type PatternType = z.infer<typeof PatternTypeSchema>;\nexport type DetectionPattern = z.infer<typeof DetectionPatternSchema>;\nexport type DetectionResult = z.infer<typeof DetectionResultSchema>;\n\n/**\n * All available pattern types\n */\nexport const PATTERN_TYPES = PatternTypeSchema.options;\n","import { z } from \"zod\";\n\nimport { LanguageSchema } from \"./category.schema.js\";\n\n/**\n * Supported test frameworks\n */\nexport const TestFrameworkSchema = z.enum([\n \"pytest\",\n \"unittest\",\n \"jest\",\n \"vitest\",\n \"mocha\",\n \"go-test\",\n \"junit\",\n]);\n\n/**\n * Types for template variables\n */\nexport const VariableTypeSchema = z.enum([\n \"string\",\n \"number\",\n \"boolean\",\n \"array\",\n \"object\",\n]);\n\n/**\n * Regex pattern for valid variable names (camelCase)\n */\nconst VARIABLE_NAME_PATTERN = /^[a-z][a-zA-Z0-9_]*$/;\n\n/**\n * Schema for template variables that get substituted during generation\n */\nexport const TemplateVariableSchema = z.object({\n /** Variable name (used in template as {{name}}) */\n name: z\n .string()\n .regex(VARIABLE_NAME_PATTERN, \"Variable name must be camelCase\"),\n\n /** Type of the variable value */\n type: VariableTypeSchema,\n\n /** Human-readable description */\n description: z.string().min(1, \"Description is required\"),\n\n /** Whether this variable must be provided */\n required: z.boolean().default(true),\n\n /** Default value if not provided */\n defaultValue: z.unknown().optional(),\n});\n\n/**\n * Regex pattern for valid IDs (lowercase, alphanumeric with hyphens)\n */\nconst ID_PATTERN = /^[a-z][a-z0-9-]*$/;\n\n/**\n * Schema for test templates that generate runnable tests\n */\nexport const TestTemplateSchema = z.object({\n /** Unique identifier for this template */\n id: z\n .string()\n .regex(ID_PATTERN, \"ID must start with lowercase letter and contain only lowercase letters, numbers, and hyphens\"),\n\n /** Target programming language */\n language: LanguageSchema,\n\n /** Target test framework */\n framework: TestFrameworkSchema,\n\n /** Template content with {{variable}} placeholders */\n template: z.string().min(50, \"Template must be at least 50 characters\"),\n\n /** Variables that can be substituted in the template */\n variables: z.array(TemplateVariableSchema),\n\n /** Required imports for the generated test */\n imports: z.array(z.string()).optional(),\n\n /** Required fixtures or setup code */\n fixtures: z.array(z.string()).optional(),\n\n /** Description of what this template tests */\n description: z.string().optional(),\n});\n\n// Inferred types\nexport type TestFramework = z.infer<typeof TestFrameworkSchema>;\nexport type VariableType = z.infer<typeof VariableTypeSchema>;\nexport type TemplateVariable = z.infer<typeof TemplateVariableSchema>;\nexport type TestTemplate = z.infer<typeof TestTemplateSchema>;\n\n/**\n * All available test frameworks\n */\nexport const TEST_FRAMEWORKS = TestFrameworkSchema.options;\n","import { z } from \"zod\";\n\nimport {\n CategoryBaseSchema,\n RiskDomainSchema,\n TestLevelSchema,\n PrioritySchema,\n SeveritySchema,\n ConfidenceSchema,\n LanguageSchema,\n RISK_DOMAINS,\n TEST_LEVELS,\n LANGUAGES,\n} from \"./category.schema.js\";\nimport { ExampleSchema } from \"./example.schema.js\";\nimport { DetectionPatternSchema, DetectionResultSchema, PatternTypeSchema, PATTERN_TYPES } from \"./pattern.schema.js\";\nimport { TestTemplateSchema, TemplateVariableSchema, TestFrameworkSchema, VariableTypeSchema, TEST_FRAMEWORKS } from \"./template.schema.js\";\n\n// Re-export all schemas\nexport {\n // Category schemas\n RiskDomainSchema,\n TestLevelSchema,\n PrioritySchema,\n SeveritySchema,\n ConfidenceSchema,\n LanguageSchema,\n CategoryBaseSchema,\n // Pattern schemas\n PatternTypeSchema,\n DetectionPatternSchema,\n DetectionResultSchema,\n // Template schemas\n TestFrameworkSchema,\n TemplateVariableSchema,\n VariableTypeSchema,\n TestTemplateSchema,\n // Example schema\n ExampleSchema,\n // Constants\n RISK_DOMAINS,\n TEST_LEVELS,\n LANGUAGES,\n PATTERN_TYPES,\n TEST_FRAMEWORKS,\n};\n\n// Re-export all types\nexport type {\n RiskDomain,\n TestLevel,\n Priority,\n Severity,\n Confidence,\n Language,\n CategoryBase,\n} from \"./category.schema.js\";\n\nexport type {\n PatternType,\n DetectionPattern,\n DetectionResult,\n} from \"./pattern.schema.js\";\n\nexport type {\n TestFramework,\n VariableType,\n TemplateVariable,\n TestTemplate,\n} from \"./template.schema.js\";\n\nexport type { Example } from \"./example.schema.js\";\n\n/**\n * Complete Category schema with all nested types\n */\nexport const CategorySchema = CategoryBaseSchema.extend({\n detectionPatterns: z.array(DetectionPatternSchema).min(1, \"At least one detection pattern required\"),\n testTemplates: z.array(TestTemplateSchema).min(1, \"At least one test template required\"),\n examples: z.array(ExampleSchema).min(1, \"At least one example required\"),\n});\n\n/**\n * Complete Category type\n */\nexport type Category = z.infer<typeof CategorySchema>;\n\n/**\n * Category without nested arrays (for partial loading)\n */\nexport const CategorySummarySchema = CategoryBaseSchema.pick({\n id: true,\n name: true,\n domain: true,\n level: true,\n priority: true,\n severity: true,\n description: true,\n});\n\nexport type CategorySummary = z.infer<typeof CategorySummarySchema>;\n","/**\n * Base error class for all Pinata errors\n */\nexport class PinataError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly context?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"PinataError\";\n // Maintains proper stack trace for where error was thrown (V8 only)\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n /**\n * Serialize error for logging or API responses\n */\n toJSON(): Record<string, unknown> {\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n context: this.context,\n };\n }\n}\n\n/**\n * Error for schema validation failures\n */\nexport class ValidationError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"VALIDATION_ERROR\", context);\n this.name = \"ValidationError\";\n }\n}\n\n/**\n * Error for file/code parsing failures\n */\nexport class ParseError extends PinataError {\n constructor(\n message: string,\n public readonly filePath: string,\n public readonly line?: number,\n context?: Record<string, unknown>\n ) {\n super(message, \"PARSE_ERROR\", { ...context, filePath, line });\n this.name = \"ParseError\";\n }\n}\n\n/**\n * Error for configuration issues\n */\nexport class ConfigError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"CONFIG_ERROR\", context);\n this.name = \"ConfigError\";\n }\n}\n\n/**\n * Error during codebase analysis\n */\nexport class AnalysisError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"ANALYSIS_ERROR\", context);\n this.name = \"AnalysisError\";\n }\n}\n\n/**\n * Error during test generation\n */\nexport class GenerationError extends PinataError {\n constructor(message: string, context?: Record<string, unknown>) {\n super(message, \"GENERATION_ERROR\", context);\n this.name = \"GenerationError\";\n }\n}\n\n/**\n * Error for category not found\n */\nexport class CategoryNotFoundError extends PinataError {\n constructor(categoryId: string) {\n super(`Category not found: ${categoryId}`, \"CATEGORY_NOT_FOUND\", { categoryId });\n this.name = \"CategoryNotFoundError\";\n }\n}\n\n/**\n * Error for pattern not found\n */\nexport class PatternNotFoundError extends PinataError {\n constructor(patternId: string) {\n super(`Pattern not found: ${patternId}`, \"PATTERN_NOT_FOUND\", { patternId });\n this.name = \"PatternNotFoundError\";\n }\n}\n","/**\n * Result type for operations that can fail\n * Prefer this over throwing exceptions for expected failures\n */\nexport type Result<T, E = Error> =\n | { success: true; data: T }\n | { success: false; error: E };\n\n/**\n * Create a successful result\n */\nexport function ok<T>(data: T): Result<T, never> {\n return { success: true, data };\n}\n\n/**\n * Create a failed result\n */\nexport function err<E>(error: E): Result<never, E> {\n return { success: false, error };\n}\n\n/**\n * Unwrap a result, throwing if it's an error\n * Use sparingly - prefer pattern matching with if/else\n */\nexport function unwrap<T, E>(result: Result<T, E>): T {\n if (result.success) {\n return result.data;\n }\n throw result.error;\n}\n\n/**\n * Unwrap a result with a default value for errors\n */\nexport function unwrapOr<T, E>(result: Result<T, E>, defaultValue: T): T {\n if (result.success) {\n return result.data;\n }\n return defaultValue;\n}\n\n/**\n * Map over a successful result\n */\nexport function map<T, U, E>(\n result: Result<T, E>,\n fn: (value: T) => U\n): Result<U, E> {\n if (result.success) {\n return ok(fn(result.data));\n }\n return result;\n}\n\n/**\n * Map over a failed result\n */\nexport function mapErr<T, E, F>(\n result: Result<T, E>,\n fn: (error: E) => F\n): Result<T, F> {\n if (!result.success) {\n return err(fn(result.error));\n }\n return result;\n}\n\n/**\n * Chain results together (flatMap)\n */\nexport function andThen<T, U, E>(\n result: Result<T, E>,\n fn: (value: T) => Result<U, E>\n): Result<U, E> {\n if (result.success) {\n return fn(result.data);\n }\n return result;\n}\n\n/**\n * Combine multiple results into one\n * Returns first error if any fail, otherwise returns array of all values\n */\nexport function all<T, E>(results: Result<T, E>[]): Result<T[], E> {\n const values: T[] = [];\n for (const result of results) {\n if (!result.success) {\n return result;\n }\n values.push(result.data);\n }\n return ok(values);\n}\n\n/**\n * Try to execute a function, returning a Result\n */\nexport function tryCatch<T>(fn: () => T): Result<T, Error> {\n try {\n return ok(fn());\n } catch (e) {\n return err(e instanceof Error ? e : new Error(String(e)));\n }\n}\n\n/**\n * Try to execute an async function, returning a Result\n */\nexport async function tryCatchAsync<T>(\n fn: () => Promise<T>\n): Promise<Result<T, Error>> {\n try {\n return ok(await fn());\n } catch (e) {\n return err(e instanceof Error ? e : new Error(String(e)));\n }\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\n\nimport YAML from \"yaml\";\n\nimport { ValidationError, CategoryNotFoundError } from \"../../lib/errors.js\";\nimport { ok, err, all, tryCatchAsync } from \"../../lib/result.js\";\nimport { CategorySchema, CategorySummarySchema } from \"../schema/index.js\";\n\nimport type { Result } from \"../../lib/result.js\";\nimport type {\n Category,\n CategorySummary,\n RiskDomain,\n TestLevel,\n Language,\n Priority,\n Severity,\n} from \"../schema/index.js\";\n\n/**\n * Options for filtering categories\n */\nexport interface CategoryFilter {\n domain?: RiskDomain;\n level?: TestLevel;\n language?: Language;\n priority?: Priority;\n severity?: Severity;\n}\n\n/**\n * Options for searching categories\n */\nexport interface SearchOptions {\n query: string;\n filter?: CategoryFilter;\n limit?: number;\n}\n\n/**\n * Search result with relevance score\n */\nexport interface SearchResult {\n category: CategorySummary;\n score: number;\n matches: string[];\n}\n\n/**\n * Store for managing test categories\n *\n * Provides:\n * - CRUD operations for categories\n * - Indexing by domain, level, language\n * - Full-text search\n * - Validation on load\n */\nexport class CategoryStore {\n /** All loaded categories by ID */\n private categories: Map<string, Category> = new Map();\n\n /** Index by domain */\n private domainIndex: Map<RiskDomain, Set<string>> = new Map();\n\n /** Index by level */\n private levelIndex: Map<TestLevel, Set<string>> = new Map();\n\n /** Index by language */\n private languageIndex: Map<Language, Set<string>> = new Map();\n\n /** Index by priority */\n private priorityIndex: Map<Priority, Set<string>> = new Map();\n\n /** Search index: word -> category IDs */\n private searchIndex: Map<string, Set<string>> = new Map();\n\n /** Version tracking for loaded categories */\n private versions: Map<string, number> = new Map();\n\n /**\n * Get total number of loaded categories\n */\n get size(): number {\n return this.categories.size;\n }\n\n /**\n * Load a single category into the store\n */\n add(category: Category): Result<Category, ValidationError> {\n // Validate the category\n const validation = CategorySchema.safeParse(category);\n if (!validation.success) {\n return err(\n new ValidationError(\"Invalid category\", {\n categoryId: category.id,\n issues: validation.error.issues,\n })\n );\n }\n\n const validated = validation.data;\n\n // Check for duplicate ID\n const existing = this.categories.get(validated.id);\n if (existing !== undefined) {\n // Allow update if version is higher\n const existingVersion = this.versions.get(validated.id) ?? 0;\n if (validated.version <= existingVersion) {\n return err(\n new ValidationError(`Category ${validated.id} already exists with same or higher version`, {\n categoryId: validated.id,\n existingVersion,\n newVersion: validated.version,\n })\n );\n }\n // Remove old indexes before updating\n this.removeFromIndexes(existing);\n }\n\n // Store category\n this.categories.set(validated.id, validated);\n this.versions.set(validated.id, validated.version);\n\n // Update indexes\n this.addToIndexes(validated);\n\n return ok(validated);\n }\n\n /**\n * Get a category by ID\n */\n get(id: string): Result<Category, CategoryNotFoundError> {\n const category = this.categories.get(id);\n if (category === undefined) {\n return err(new CategoryNotFoundError(id));\n }\n return ok(category);\n }\n\n /**\n * Check if a category exists\n */\n has(id: string): boolean {\n return this.categories.has(id);\n }\n\n /**\n * Remove a category by ID\n */\n remove(id: string): Result<Category, CategoryNotFoundError> {\n const category = this.categories.get(id);\n if (category === undefined) {\n return err(new CategoryNotFoundError(id));\n }\n\n this.removeFromIndexes(category);\n this.categories.delete(id);\n this.versions.delete(id);\n\n return ok(category);\n }\n\n /**\n * List all categories, optionally filtered\n */\n list(filter?: CategoryFilter): CategorySummary[] {\n let ids: Set<string> | undefined;\n\n // Apply filters by intersecting index sets\n if (filter?.domain !== undefined) {\n const domainIds = this.domainIndex.get(filter.domain);\n if (domainIds === undefined) return []; // No categories in this domain\n ids = this.intersect(ids, domainIds);\n }\n if (filter?.level !== undefined) {\n const levelIds = this.levelIndex.get(filter.level);\n if (levelIds === undefined) return []; // No categories at this level\n ids = this.intersect(ids, levelIds);\n }\n if (filter?.language !== undefined) {\n const langIds = this.languageIndex.get(filter.language);\n if (langIds === undefined) return []; // No categories for this language\n ids = this.intersect(ids, langIds);\n }\n if (filter?.priority !== undefined) {\n const priorityIds = this.priorityIndex.get(filter.priority);\n if (priorityIds === undefined) return []; // No categories at this priority\n ids = this.intersect(ids, priorityIds);\n }\n\n // Get categories for matching IDs\n const categories: CategorySummary[] = [];\n const targetIds = ids ?? this.categories.keys();\n\n for (const id of targetIds) {\n const category = this.categories.get(id);\n if (category !== undefined) {\n // Apply severity filter if specified\n if (filter?.severity !== undefined && category.severity !== filter.severity) {\n continue;\n }\n categories.push(this.toSummary(category));\n }\n }\n\n // Sort by priority, then severity, then name\n return categories.sort((a, b) => {\n const priorityOrder = { P0: 0, P1: 1, P2: 2 };\n const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 };\n\n const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];\n if (priorityDiff !== 0) return priorityDiff;\n\n const severityDiff = severityOrder[a.severity] - severityOrder[b.severity];\n if (severityDiff !== 0) return severityDiff;\n\n return a.name.localeCompare(b.name);\n });\n }\n\n /**\n * Get all categories in a specific domain\n */\n byDomain(domain: RiskDomain): CategorySummary[] {\n return this.list({ domain });\n }\n\n /**\n * Get all categories at a specific test level\n */\n byLevel(level: TestLevel): CategorySummary[] {\n return this.list({ level });\n }\n\n /**\n * Get all categories applicable to a language\n */\n byLanguage(language: Language): CategorySummary[] {\n return this.list({ language });\n }\n\n /**\n * Full-text search across categories\n */\n search(options: SearchOptions): SearchResult[] {\n const { query, filter, limit = 20 } = options;\n\n // Tokenize query\n const queryTokens = this.tokenize(query.toLowerCase());\n if (queryTokens.length === 0) {\n return [];\n }\n\n // Find matching category IDs\n const scores: Map<string, { score: number; matches: string[] }> = new Map();\n\n for (const token of queryTokens) {\n // Exact match\n const exactMatches = this.searchIndex.get(token);\n if (exactMatches !== undefined) {\n for (const id of exactMatches) {\n const current = scores.get(id) ?? { score: 0, matches: [] };\n current.score += 10; // Exact match weight\n current.matches.push(token);\n scores.set(id, current);\n }\n }\n\n // Prefix match\n for (const [indexToken, ids] of this.searchIndex) {\n if (indexToken.startsWith(token) && indexToken !== token) {\n for (const id of ids) {\n const current = scores.get(id) ?? { score: 0, matches: [] };\n current.score += 5; // Prefix match weight\n if (!current.matches.includes(token)) {\n current.matches.push(token);\n }\n scores.set(id, current);\n }\n }\n }\n }\n\n // Build results with category data\n const results: SearchResult[] = [];\n\n for (const [id, { score, matches }] of scores) {\n const category = this.categories.get(id);\n if (category === undefined) continue;\n\n // Apply filters\n if (filter !== undefined) {\n if (filter.domain !== undefined && category.domain !== filter.domain) continue;\n if (filter.level !== undefined && category.level !== filter.level) continue;\n if (filter.priority !== undefined && category.priority !== filter.priority) continue;\n if (filter.severity !== undefined && category.severity !== filter.severity) continue;\n if (\n filter.language !== undefined &&\n !category.applicableLanguages.includes(filter.language)\n ) {\n continue;\n }\n }\n\n results.push({\n category: this.toSummary(category),\n score,\n matches: [...new Set(matches)],\n });\n }\n\n // Sort by score descending, then by priority\n results.sort((a, b) => {\n if (b.score !== a.score) return b.score - a.score;\n const priorityOrder = { P0: 0, P1: 1, P2: 2 };\n return priorityOrder[a.category.priority] - priorityOrder[b.category.priority];\n });\n\n return results.slice(0, limit);\n }\n\n /**\n * Load categories from a directory of YAML files\n */\n async loadFromDirectory(dirPath: string): Promise<Result<number, ValidationError>> {\n const results = await this.loadYamlFilesRecursive(dirPath);\n const combined = all(results);\n\n if (!combined.success) {\n return combined;\n }\n\n return ok(combined.data.length);\n }\n\n /**\n * Load a single category from a YAML file\n */\n async loadFromFile(filePath: string): Promise<Result<Category, ValidationError>> {\n const result = await tryCatchAsync(async () => {\n const content = await fs.readFile(filePath, \"utf-8\");\n return YAML.parse(content) as unknown;\n });\n\n if (!result.success) {\n return err(\n new ValidationError(`Failed to read category file: ${filePath}`, {\n filePath,\n cause: result.error.message,\n })\n );\n }\n\n const validation = CategorySchema.safeParse(result.data);\n if (!validation.success) {\n return err(\n new ValidationError(`Invalid category in ${filePath}`, {\n filePath,\n issues: validation.error.issues,\n })\n );\n }\n\n return this.add(validation.data);\n }\n\n /**\n * Export all categories as an array\n */\n toArray(): Category[] {\n return Array.from(this.categories.values());\n }\n\n /**\n * Clear all categories and indexes\n */\n clear(): void {\n this.categories.clear();\n this.domainIndex.clear();\n this.levelIndex.clear();\n this.languageIndex.clear();\n this.priorityIndex.clear();\n this.searchIndex.clear();\n this.versions.clear();\n }\n\n /**\n * Get statistics about loaded categories\n */\n stats(): {\n total: number;\n byDomain: Record<string, number>;\n byLevel: Record<string, number>;\n byPriority: Record<string, number>;\n } {\n const byDomain: Record<string, number> = {};\n const byLevel: Record<string, number> = {};\n const byPriority: Record<string, number> = {};\n\n for (const [domain, ids] of this.domainIndex) {\n byDomain[domain] = ids.size;\n }\n for (const [level, ids] of this.levelIndex) {\n byLevel[level] = ids.size;\n }\n for (const [priority, ids] of this.priorityIndex) {\n byPriority[priority] = ids.size;\n }\n\n return {\n total: this.categories.size,\n byDomain,\n byLevel,\n byPriority,\n };\n }\n\n // ─────────────────────────────────────────────────────────────────────────\n // Private methods\n // ─────────────────────────────────────────────────────────────────────────\n\n /**\n * Add category to all indexes\n */\n private addToIndexes(category: Category): void {\n const id = category.id;\n\n // Domain index\n this.addToIndex(this.domainIndex, category.domain, id);\n\n // Level index\n this.addToIndex(this.levelIndex, category.level, id);\n\n // Language index (multiple)\n for (const lang of category.applicableLanguages) {\n this.addToIndex(this.languageIndex, lang, id);\n }\n\n // Priority index\n this.addToIndex(this.priorityIndex, category.priority, id);\n\n // Search index\n this.indexForSearch(category);\n }\n\n /**\n * Remove category from all indexes\n */\n private removeFromIndexes(category: Category): void {\n const id = category.id;\n\n this.removeFromIndex(this.domainIndex, category.domain, id);\n this.removeFromIndex(this.levelIndex, category.level, id);\n for (const lang of category.applicableLanguages) {\n this.removeFromIndex(this.languageIndex, lang, id);\n }\n this.removeFromIndex(this.priorityIndex, category.priority, id);\n this.removeFromSearchIndex(id);\n }\n\n /**\n * Add ID to an index map\n */\n private addToIndex<K>(index: Map<K, Set<string>>, key: K, id: string): void {\n let set = index.get(key);\n if (set === undefined) {\n set = new Set();\n index.set(key, set);\n }\n set.add(id);\n }\n\n /**\n * Remove ID from an index map\n */\n private removeFromIndex<K>(index: Map<K, Set<string>>, key: K, id: string): void {\n const set = index.get(key);\n if (set !== undefined) {\n set.delete(id);\n if (set.size === 0) {\n index.delete(key);\n }\n }\n }\n\n /**\n * Index category text for search\n */\n private indexForSearch(category: Category): void {\n const id = category.id;\n const textToIndex = [\n category.id,\n category.name,\n category.description,\n category.domain,\n category.level,\n ...category.applicableLanguages,\n ...(category.cves ?? []),\n ].join(\" \");\n\n const tokens = this.tokenize(textToIndex.toLowerCase());\n for (const token of tokens) {\n this.addToIndex(this.searchIndex, token, id);\n }\n }\n\n /**\n * Remove category from search index\n */\n private removeFromSearchIndex(id: string): void {\n for (const [token, ids] of this.searchIndex) {\n ids.delete(id);\n if (ids.size === 0) {\n this.searchIndex.delete(token);\n }\n }\n }\n\n /**\n * Tokenize text for search indexing\n */\n private tokenize(text: string): string[] {\n return text\n .split(/[\\s\\-_.,;:!?'\"()\\[\\]{}]+/)\n .filter((token) => token.length >= 2)\n .map((token) => token.toLowerCase());\n }\n\n /**\n * Intersect two sets, handling undefined\n * Returns empty set if either input is empty set (filter found no matches)\n */\n private intersect(a: Set<string> | undefined, b: Set<string> | undefined): Set<string> | undefined {\n if (a === undefined) return b;\n if (b === undefined) return a;\n // If b is empty (filter matched nothing), return empty set\n if (b.size === 0) return new Set();\n return new Set([...a].filter((x) => b.has(x)));\n }\n\n /**\n * Convert full category to summary\n */\n private toSummary(category: Category): CategorySummary {\n return CategorySummarySchema.parse({\n id: category.id,\n name: category.name,\n domain: category.domain,\n level: category.level,\n priority: category.priority,\n severity: category.severity,\n description: category.description,\n });\n }\n\n /**\n * Recursively load YAML files from directory\n */\n private async loadYamlFilesRecursive(dirPath: string): Promise<Result<Category, ValidationError>[]> {\n const results: Result<Category, ValidationError>[] = [];\n\n const loadResult = await tryCatchAsync(async () => {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries;\n });\n\n if (!loadResult.success) {\n return [\n err(\n new ValidationError(`Failed to read directory: ${dirPath}`, {\n dirPath,\n cause: loadResult.error.message,\n })\n ),\n ];\n }\n\n for (const entry of loadResult.data) {\n const fullPath = path.join(dirPath, entry.name);\n\n if (entry.isDirectory()) {\n const subResults = await this.loadYamlFilesRecursive(fullPath);\n results.push(...subResults);\n } else if (entry.isFile() && (entry.name.endsWith(\".yml\") || entry.name.endsWith(\".yaml\"))) {\n const result = await this.loadFromFile(fullPath);\n results.push(result);\n }\n }\n\n return results;\n }\n}\n\n/**\n * Create a new CategoryStore instance\n */\nexport function createCategoryStore(): CategoryStore {\n return new CategoryStore();\n}\n","import chalk from \"chalk\";\n\n/**\n * Log levels from most to least verbose\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"silent\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\n/**\n * Logger configuration\n */\ninterface LoggerConfig {\n level: LogLevel;\n prefix?: string;\n}\n\n/**\n * Simple logger with colored output\n */\nclass Logger {\n private level: LogLevel = \"info\";\n private prefix: string = \"\";\n\n /**\n * Configure the logger\n */\n configure(config: Partial<LoggerConfig>): void {\n if (config.level !== undefined) {\n this.level = config.level;\n }\n if (config.prefix !== undefined) {\n this.prefix = config.prefix;\n }\n }\n\n /**\n * Check if a log level should be output\n */\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[this.level];\n }\n\n /**\n * Format a message with optional prefix\n */\n private format(message: string): string {\n return this.prefix ? `${this.prefix} ${message}` : message;\n }\n\n /**\n * Debug level logging (gray)\n */\n debug(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"debug\")) {\n console.debug(chalk.gray(this.format(message)), ...args);\n }\n }\n\n /**\n * Info level logging (default color)\n */\n info(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"info\")) {\n console.info(this.format(message), ...args);\n }\n }\n\n /**\n * Warning level logging (yellow)\n */\n warn(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"warn\")) {\n console.warn(chalk.yellow(this.format(message)), ...args);\n }\n }\n\n /**\n * Error level logging (red)\n */\n error(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"error\")) {\n console.error(chalk.red(this.format(message)), ...args);\n }\n }\n\n /**\n * Success message (green)\n */\n success(message: string, ...args: unknown[]): void {\n if (this.shouldLog(\"info\")) {\n console.info(chalk.green(this.format(message)), ...args);\n }\n }\n\n /**\n * Create a child logger with a prefix\n */\n child(prefix: string): Logger {\n const child = new Logger();\n child.level = this.level;\n child.prefix = this.prefix ? `${this.prefix} ${prefix}` : prefix;\n return child;\n }\n}\n\n/**\n * Global logger instance\n */\nexport const logger = new Logger();\n","/**\n * Tree-sitter AST Parser\n *\n * Provides AST parsing and querying capabilities using web-tree-sitter.\n * Supports Python, TypeScript, and JavaScript.\n */\n\nimport { existsSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\n\nimport {\n Parser as TreeSitterParser,\n Language as TreeSitterLanguage,\n Tree as TreeSitterTree,\n Node as TreeSitterNode,\n Query as TreeSitterQuery,\n} from \"web-tree-sitter\";\n\nimport { PinataError, ParseError } from \"../../lib/errors.js\";\nimport { logger } from \"../../lib/logger.js\";\nimport { ok, err } from \"../../lib/result.js\";\n\nimport type { Language } from \"../../categories/schema/index.js\";\nimport type { Result } from \"../../lib/result.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\n/**\n * Map of language to tree-sitter grammar name\n */\nconst LANGUAGE_GRAMMAR_MAP: Record<Language, string | null> = {\n python: \"tree-sitter-python\",\n typescript: \"tree-sitter-typescript\",\n javascript: \"tree-sitter-javascript\",\n go: null, // Not yet supported\n java: null, // Not yet supported\n rust: null, // Not yet supported\n};\n\n/**\n * AST match result\n */\nexport interface AstMatch {\n /** Matched node text */\n text: string;\n /** Node type (e.g., \"call_expression\") */\n nodeType: string;\n /** Starting line (0-indexed) */\n startLine: number;\n /** Ending line (0-indexed) */\n endLine: number;\n /** Starting column (0-indexed) */\n startColumn: number;\n /** Ending column (0-indexed) */\n endColumn: number;\n /** Capture name from the query (e.g., \"@call\") */\n captureName: string;\n /** Child captures from the same match group */\n captures: Map<string, string>;\n}\n\n/**\n * Query match with all captures\n */\ninterface QueryMatch {\n pattern: number;\n captures: Array<{\n name: string;\n node: TreeSitterNode;\n }>;\n}\n\n/**\n * Cached parser instances per language\n */\nconst parserCache = new Map<string, TreeSitterParser>();\n\n/**\n * Cached language instances\n */\nconst languageCache = new Map<string, TreeSitterLanguage>();\n\n/**\n * Whether Parser has been initialized\n */\nlet parserInitialized = false;\n\n/**\n * WASM file locations - tries multiple paths\n * web-tree-sitter uses web-tree-sitter.wasm as the main parser WASM file\n */\nfunction getWasmPaths(): string[] {\n return [\n // Development: relative to project root\n join(process.cwd(), \"node_modules/web-tree-sitter/web-tree-sitter.wasm\"),\n // Built: relative to dist\n join(__dirname, \"../../../node_modules/web-tree-sitter/web-tree-sitter.wasm\"),\n // Alternative locations\n join(__dirname, \"../../wasm/web-tree-sitter.wasm\"),\n join(process.cwd(), \"wasm/web-tree-sitter.wasm\"),\n ];\n}\n\n/**\n * Language WASM file locations\n */\nfunction getLanguageWasmPaths(language: string): string[] {\n const grammarName = `tree-sitter-${language}`;\n const wasmName = `${grammarName}.wasm`;\n\n return [\n // Project wasm directory (recommended)\n join(process.cwd(), \"wasm\", wasmName),\n // src directory\n join(process.cwd(), \"src/core/detection/wasm\", wasmName),\n // Fallback locations\n join(__dirname, \"wasm\", wasmName),\n join(__dirname, \"../../../wasm\", wasmName),\n ];\n}\n\n/**\n * Initialize the tree-sitter Parser\n */\nasync function initializeParser(): Promise<Result<void, PinataError>> {\n if (parserInitialized) {\n return ok(undefined);\n }\n\n const wasmPaths = getWasmPaths();\n let wasmPath: string | null = null;\n\n for (const path of wasmPaths) {\n if (existsSync(path)) {\n wasmPath = path;\n break;\n }\n }\n\n if (!wasmPath) {\n return err(\n new ParseError(\n \"tree-sitter.wasm not found. Run: npm run setup:wasm\",\n \"tree-sitter.wasm\"\n )\n );\n }\n\n try {\n await TreeSitterParser.init({\n locateFile: () => wasmPath,\n });\n parserInitialized = true;\n logger.debug(\"Tree-sitter initialized\");\n return ok(undefined);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to initialize tree-sitter: ${error instanceof Error ? error.message : String(error)}`,\n wasmPath\n )\n );\n }\n}\n\n/**\n * Load a language grammar\n */\nasync function loadLanguage(language: Language): Promise<Result<TreeSitterLanguage, PinataError>> {\n const grammarName = LANGUAGE_GRAMMAR_MAP[language];\n\n if (grammarName === null) {\n return err(\n new ParseError(`Language not supported for AST parsing: ${language}`, language)\n );\n }\n\n // Check cache\n const cached = languageCache.get(language);\n if (cached) {\n return ok(cached);\n }\n\n // Handle TypeScript special case (uses typescript grammar from tree-sitter-typescript)\n const langKey = language === \"typescript\" ? \"typescript\" : language;\n const wasmPaths = getLanguageWasmPaths(langKey);\n\n let wasmPath: string | null = null;\n for (const path of wasmPaths) {\n if (existsSync(path)) {\n wasmPath = path;\n break;\n }\n }\n\n if (!wasmPath) {\n return err(\n new ParseError(\n `Language WASM not found for ${language}. Run: npm run setup:wasm`,\n language\n )\n );\n }\n\n try {\n const lang = await TreeSitterLanguage.load(wasmPath);\n languageCache.set(language, lang);\n logger.debug(`Loaded language: ${language}`);\n return ok(lang);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to load language ${language}: ${error instanceof Error ? error.message : String(error)}`,\n wasmPath\n )\n );\n }\n}\n\n/**\n * Get or create a parser for a specific language\n */\nasync function getParser(language: Language): Promise<Result<TreeSitterParser, PinataError>> {\n // Initialize if needed\n const initResult = await initializeParser();\n if (!initResult.success) {\n return initResult;\n }\n\n // Check cache\n const cached = parserCache.get(language);\n if (cached) {\n return ok(cached);\n }\n\n // Load language\n const langResult = await loadLanguage(language);\n if (!langResult.success) {\n return langResult;\n }\n\n // Create parser\n const parser = new TreeSitterParser();\n parser.setLanguage(langResult.data);\n parserCache.set(language, parser);\n\n return ok(parser);\n}\n\n/**\n * Parse source code into an AST\n */\nexport async function parseSource(\n source: string,\n language: Language\n): Promise<Result<TreeSitterTree, PinataError>> {\n const parserResult = await getParser(language);\n if (!parserResult.success) {\n return parserResult;\n }\n\n try {\n const tree = parserResult.data.parse(source);\n if (!tree) {\n return err(\n new ParseError(\"Failed to parse source: parser returned null\", \"source\")\n );\n }\n return ok(tree);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to parse source: ${error instanceof Error ? error.message : String(error)}`,\n \"source\"\n )\n );\n }\n}\n\n/**\n * Execute a tree-sitter query against an AST\n *\n * Query syntax follows tree-sitter query format:\n * https://tree-sitter.github.io/tree-sitter/using-parsers#pattern-matching-with-queries\n *\n * @example\n * ```typescript\n * // Find all function calls\n * const query = \"(call_expression) @call\";\n *\n * // Find SQL execute with string concatenation\n * const query = `\n * (call_expression\n * function: (attribute\n * attribute: (identifier) @method)\n * arguments: (argument_list\n * (binary_operator) @concat))\n * (#match? @method \"execute|executemany\")\n * @call\n * `;\n * ```\n */\nexport async function executeQuery(\n tree: TreeSitterTree,\n queryString: string,\n language: Language\n): Promise<Result<AstMatch[], PinataError>> {\n const langResult = await loadLanguage(language);\n if (!langResult.success) {\n return langResult;\n }\n\n try {\n // Create query from language\n const query = new TreeSitterQuery(langResult.data, queryString);\n const matches = query.matches(tree.rootNode);\n\n const results: AstMatch[] = [];\n\n for (const match of matches) {\n // Get all captures for this match\n const captureMap = new Map<string, string>();\n for (const capture of match.captures) {\n captureMap.set(capture.name, capture.node.text);\n }\n\n // Create a result for each capture\n for (const capture of match.captures) {\n const node = capture.node;\n results.push({\n text: node.text,\n nodeType: node.type,\n startLine: node.startPosition.row,\n endLine: node.endPosition.row,\n startColumn: node.startPosition.column,\n endColumn: node.endPosition.column,\n captureName: capture.name,\n captures: captureMap,\n });\n }\n }\n\n return ok(results);\n } catch (error) {\n return err(\n new ParseError(\n `Failed to execute query: ${error instanceof Error ? error.message : String(error)}`,\n \"query\"\n )\n );\n }\n}\n\n/**\n * AstPatternMatcher - Executes AST queries against source code\n *\n * Provides a higher-level interface for pattern detection using tree-sitter.\n */\nexport class AstPatternMatcher {\n private readonly sourceCache = new Map<string, TreeSitterTree>();\n private readonly log = logger.child(\"AstPatternMatcher\");\n\n /**\n * Check if AST parsing is available for a language\n */\n isLanguageSupported(language: Language): boolean {\n return LANGUAGE_GRAMMAR_MAP[language] !== null;\n }\n\n /**\n * Get list of supported languages\n */\n getSupportedLanguages(): Language[] {\n return Object.entries(LANGUAGE_GRAMMAR_MAP)\n .filter(([_, grammar]) => grammar !== null)\n .map(([lang]) => lang as Language);\n }\n\n /**\n * Parse source code and cache the AST\n */\n async parse(\n source: string,\n language: Language,\n cacheKey?: string\n ): Promise<Result<TreeSitterTree, PinataError>> {\n // Check cache\n if (cacheKey) {\n const cached = this.sourceCache.get(cacheKey);\n if (cached) {\n return ok(cached);\n }\n }\n\n const result = await parseSource(source, language);\n if (result.success && cacheKey) {\n this.sourceCache.set(cacheKey, result.data);\n }\n\n return result;\n }\n\n /**\n * Execute a query against source code\n *\n * @param source Source code to analyze\n * @param query Tree-sitter query string\n * @param language Programming language\n * @param cacheKey Optional cache key for the parsed AST\n */\n async query(\n source: string,\n query: string,\n language: Language,\n cacheKey?: string\n ): Promise<Result<AstMatch[], PinataError>> {\n const treeResult = await this.parse(source, language, cacheKey);\n if (!treeResult.success) {\n return treeResult;\n }\n\n return executeQuery(treeResult.data, query, language);\n }\n\n /**\n * Execute multiple queries against the same source\n */\n async queryMultiple(\n source: string,\n queries: string[],\n language: Language,\n cacheKey?: string\n ): Promise<Result<AstMatch[][], PinataError>> {\n const treeResult = await this.parse(source, language, cacheKey);\n if (!treeResult.success) {\n return treeResult;\n }\n\n const results: AstMatch[][] = [];\n for (const query of queries) {\n const queryResult = await executeQuery(treeResult.data, query, language);\n if (!queryResult.success) {\n return queryResult;\n }\n results.push(queryResult.data);\n }\n\n return ok(results);\n }\n\n /**\n * Clear the AST cache\n */\n clearCache(): void {\n this.sourceCache.clear();\n }\n\n /**\n * Get cache statistics\n */\n getCacheStats(): { entries: number; languages: Set<string> } {\n return {\n entries: this.sourceCache.size,\n languages: new Set(parserCache.keys()),\n };\n }\n}\n\n/**\n * Create a new AstPatternMatcher instance\n */\nexport function createAstMatcher(): AstPatternMatcher {\n return new AstPatternMatcher();\n}\n\n/**\n * Predefined AST queries for common vulnerability patterns\n */\nexport const COMMON_AST_PATTERNS = {\n // Python: SQL injection via string formatting\n pythonSqlStringFormat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator\n operator: \"%\") @concat))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via f-string\n pythonSqlFString: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (string\n (interpolation)) @fstring))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via concatenation\n pythonSqlConcat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator\n operator: \"+\") @concat))\n (#match? @method \"^execute$|^executemany$\")\n @call\n `,\n\n // Python: SQL injection via .format()\n pythonSqlFormat: `\n (call\n function: (attribute\n attribute: (identifier) @method)\n arguments: (argument_list\n (call\n function: (attribute\n attribute: (identifier) @format_method))))\n (#match? @method \"^execute$|^executemany$\")\n (#match? @format_method \"^format$\")\n @call\n `,\n\n // JavaScript/TypeScript: SQL injection via template literal\n jsSqlTemplateLiteral: `\n (call_expression\n function: (member_expression\n property: (property_identifier) @method)\n arguments: (arguments\n (template_string\n (template_substitution)) @template))\n (#match? @method \"^query$|^execute$|^run$\")\n @call\n `,\n\n // JavaScript/TypeScript: SQL injection via concatenation\n jsSqlConcat: `\n (call_expression\n function: (member_expression\n property: (property_identifier) @method)\n arguments: (arguments\n (binary_expression\n operator: \"+\") @concat))\n (#match? @method \"^query$|^execute$|^run$\")\n @call\n `,\n\n // Python: Command injection via subprocess\n pythonCommandInjection: `\n (call\n function: (attribute\n object: (identifier) @module\n attribute: (identifier) @method)\n arguments: (argument_list\n (binary_operator) @concat))\n (#match? @module \"^subprocess$|^os$\")\n (#match? @method \"^call$|^run$|^Popen$|^system$\")\n @call\n `,\n\n // Python: Path traversal via open\n pythonPathTraversal: `\n (call\n function: (identifier) @func\n arguments: (argument_list\n (binary_operator\n operator: \"+\") @concat))\n (#match? @func \"^open$\")\n @call\n `,\n\n // JavaScript: eval usage\n jsEval: `\n (call_expression\n function: (identifier) @func)\n (#match? @func \"^eval$\")\n @call\n `,\n\n // TypeScript: Any type assertion\n tsAnyAssertion: `\n (as_expression\n type: (type_identifier) @type)\n (#match? @type \"^any$\")\n @assertion\n `,\n} as const;\n\n/**\n * Check if tree-sitter is properly initialized\n */\nexport async function checkTreeSitterSetup(): Promise<Result<{ ready: boolean; languages: Language[] }, PinataError>> {\n const initResult = await initializeParser();\n if (!initResult.success) {\n logger.debug(`Tree-sitter init failed: ${initResult.error.message}`);\n return ok({ ready: false, languages: [] });\n }\n\n const supportedLanguages: Language[] = [];\n for (const lang of [\"python\", \"typescript\", \"javascript\"] as Language[]) {\n const langResult = await loadLanguage(lang);\n if (langResult.success) {\n supportedLanguages.push(lang);\n } else {\n logger.debug(`Failed to load language ${lang}: ${langResult.error.message}`);\n }\n }\n\n return ok({\n ready: supportedLanguages.length > 0,\n languages: supportedLanguages,\n });\n}\n","/**\n * Attack surface discovery\n *\n * AI-powered analysis of codebase structure to find attack surfaces\n * that regex patterns cannot detect: missing auth, IDOR, race conditions,\n * unvalidated inputs, unprotected endpoints.\n *\n * This is Phase 0 of the pipeline -- runs before pattern scanning.\n * Produces findings that feed directly into the TestForge queue.\n */\n\nimport { readFile, readdir, stat } from \"fs/promises\";\nimport { resolve, extname, relative, basename } from \"path\";\nimport { existsSync } from \"fs\";\n\nimport { logger } from \"../../lib/logger.js\";\n\nimport type { Gap } from \"../scanner/types.js\";\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\nexport interface AttackSurfaceMap {\n endpoints: EndpointInfo[];\n dbOperations: DbOperationInfo[];\n authChecks: AuthCheckInfo[];\n stateMutations: StateMutationInfo[];\n findings: AttackSurfaceFinding[];\n}\n\nexport interface EndpointInfo {\n method: string;\n path: string;\n filePath: string;\n lineStart: number;\n hasAuth: boolean;\n middlewareChain: string[];\n}\n\nexport interface DbOperationInfo {\n operation: string;\n filePath: string;\n lineStart: number;\n isParameterized: boolean;\n}\n\nexport interface AuthCheckInfo {\n filePath: string;\n lineStart: number;\n type: string;\n}\n\nexport interface StateMutationInfo {\n filePath: string;\n lineStart: number;\n hasLock: boolean;\n hasTransaction: boolean;\n}\n\nexport interface AttackSurfaceFinding {\n type: \"missing-auth\" | \"race-condition\" | \"missing-rate-limit\";\n description: string;\n filePath: string;\n lineStart: number;\n severity: \"critical\" | \"high\" | \"medium\" | \"low\";\n confidence: \"high\" | \"medium\" | \"low\";\n}\n\nexport interface DiscoveryConfig {\n callAI?: (prompt: string, systemPrompt: string) => Promise<string>;\n maxFiles?: number;\n}\n\n// =============================================================================\n// STATIC DISCOVERY (no AI needed)\n// =============================================================================\n\nconst ROUTE_PATTERNS = {\n express: /\\.(get|post|put|patch|delete|all|use)\\s*\\(\\s*[\"'`]([^\"'`]+)[\"'`]/g,\n fastify: /\\.(get|post|put|patch|delete)\\s*\\(\\s*[\"'`]([^\"'`]+)[\"'`]/g,\n nextjs: /export\\s+(async\\s+)?function\\s+(GET|POST|PUT|PATCH|DELETE)\\b/g,\n flask: /@\\w+\\.route\\s*\\(\\s*[\"']([^\"']+)[\"']/g,\n django: /path\\s*\\(\\s*[\"']([^\"']+)[\"']/g,\n fastapi: /@\\w+\\.(get|post|put|patch|delete)\\s*\\(\\s*[\"']([^\"']+)[\"']/g,\n};\n\nconst AUTH_MIDDLEWARE_PATTERNS = [\n /\\b(requireAuth|isAuthenticated|authenticate|authMiddleware|protect|ensureLoggedIn|passport\\.authenticate|verifyToken|requireLogin)\\b/,\n /\\b(auth|authentication|authorization)\\s*\\(/,\n /\\b(jwt|bearer|token)\\s*\\(/i,\n];\n\nconst DB_OPERATION_PATTERNS = [\n /\\.(query|execute|run|all|get|find|findOne|findMany|create|update|delete|insert|upsert|remove)\\s*\\(/,\n /\\b(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\\b/,\n];\n\nconst RATE_LIMIT_PATTERNS = [\n /rate[-_]?limit|rateLimiter|throttle|RateLimiterMemory|slowDown/i,\n];\n\nconst CONCURRENCY_GUARD_PATTERNS = [\n /\\b(transaction|BEGIN|COMMIT|ROLLBACK|LOCK|FOR UPDATE|serializable)\\b/i,\n /\\b(mutex|semaphore|lock|atomic|synchronized)\\b/i,\n /\\bidempotency[_-]?key\\b/i,\n];\n\nconst log = logger.child(\"AttackSurface\");\n\n/**\n * Discover attack surfaces using static analysis (no AI).\n * Scans route definitions, auth middleware, DB operations, and state mutations.\n */\nexport async function discoverAttackSurface(\n projectRoot: string,\n config: DiscoveryConfig = {}\n): Promise<AttackSurfaceMap> {\n const maxFiles = config.maxFiles ?? 200;\n const endpoints: EndpointInfo[] = [];\n const dbOperations: DbOperationInfo[] = [];\n const authChecks: AuthCheckInfo[] = [];\n const stateMutations: StateMutationInfo[] = [];\n const findings: AttackSurfaceFinding[] = [];\n\n // Find source files\n const sourceFiles = await findSourceFiles(projectRoot, maxFiles);\n log.info(`Scanning ${sourceFiles.length} files for attack surface`);\n\n // Check for rate limiting at the project level\n const hasRateLimiting = await projectHasRateLimiting(projectRoot);\n\n for (const filePath of sourceFiles) {\n try {\n const content = await readFile(filePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const relPath = relative(projectRoot, filePath);\n\n // Find route definitions\n for (const [_framework, pattern] of Object.entries(ROUTE_PATTERNS)) {\n const regex = new RegExp(pattern.source, pattern.flags);\n let match;\n while ((match = regex.exec(content)) !== null) {\n const lineStart = content.slice(0, match.index).split(\"\\n\").length;\n\n // Check surrounding context for auth middleware\n const contextStart = Math.max(0, lineStart - 10);\n const contextEnd = Math.min(lines.length, lineStart + 5);\n const context = lines.slice(contextStart, contextEnd).join(\"\\n\");\n\n const hasAuth = AUTH_MIDDLEWARE_PATTERNS.some((p) => p.test(context));\n const method = (match[1] ?? match[2] ?? \"unknown\").toUpperCase();\n const path = match[2] ?? match[1] ?? \"/unknown\";\n\n endpoints.push({\n method,\n path,\n filePath: relPath,\n lineStart,\n hasAuth,\n middlewareChain: [],\n });\n\n // Flag unprotected state-changing endpoints\n if (!hasAuth && [\"POST\", \"PUT\", \"PATCH\", \"DELETE\"].includes(method)) {\n findings.push({\n type: \"missing-auth\",\n description: `${method} ${path} has no authentication middleware`,\n filePath: relPath,\n lineStart,\n severity: \"critical\",\n confidence: \"medium\",\n });\n }\n }\n }\n\n // Find DB operations\n for (const pattern of DB_OPERATION_PATTERNS) {\n const regex = new RegExp(pattern.source, \"gm\");\n let match;\n while ((match = regex.exec(content)) !== null) {\n const lineStart = content.slice(0, match.index).split(\"\\n\").length;\n const lineContent = lines[lineStart - 1] ?? \"\";\n\n const isParameterized = /\\$\\d|\\?\\s*,|\\?\\s*\\)|\\bparams\\b|:\\w+/.test(lineContent);\n\n dbOperations.push({\n operation: match[0].slice(0, 50),\n filePath: relPath,\n lineStart,\n isParameterized,\n });\n }\n }\n\n // Find state mutations without concurrency guards\n const hasConcurrencyGuards = CONCURRENCY_GUARD_PATTERNS.some((p) => p.test(content));\n if (!hasConcurrencyGuards) {\n // ORM-style writes only: exclude Map/Set .delete/.remove which dominate false positives\n const writeOps = /\\.(update|save|create|insert|upsert|increment|decrement)\\s*\\(/g;\n let match;\n while ((match = writeOps.exec(content)) !== null) {\n const lineStart = content.slice(0, match.index).split(\"\\n\").length;\n stateMutations.push({\n filePath: relPath,\n lineStart,\n hasLock: false,\n hasTransaction: false,\n });\n }\n }\n\n // Find auth-related code\n for (const pattern of AUTH_MIDDLEWARE_PATTERNS) {\n const regex = new RegExp(pattern.source, \"gm\");\n let match;\n while ((match = regex.exec(content)) !== null) {\n const lineStart = content.slice(0, match.index).split(\"\\n\").length;\n authChecks.push({\n filePath: relPath,\n lineStart,\n type: match[0],\n });\n }\n }\n } catch {\n // Skip files that can't be read\n }\n }\n\n // Flag endpoints without rate limiting\n if (!hasRateLimiting && endpoints.length > 0) {\n const authEndpoints = endpoints.filter((e) =>\n e.path.includes(\"login\") || e.path.includes(\"auth\") || e.path.includes(\"signin\")\n );\n for (const ep of authEndpoints) {\n findings.push({\n type: \"missing-rate-limit\",\n description: `Auth endpoint ${ep.method} ${ep.path} has no rate limiting`,\n filePath: ep.filePath,\n lineStart: ep.lineStart,\n severity: \"high\",\n confidence: \"medium\",\n });\n }\n }\n\n // Flag race condition candidates per file (repo-wide counts mis-attribute the first file scanned)\n const byFile = new Map<string, typeof stateMutations>();\n for (const m of stateMutations) {\n const list = byFile.get(m.filePath) ?? [];\n list.push(m);\n byFile.set(m.filePath, list);\n }\n for (const [filePath, mutations] of byFile) {\n if (mutations.length > 3) {\n const first = mutations[0];\n findings.push({\n type: \"race-condition\",\n description: `${mutations.length} state mutations in this file without concurrency guards (transactions, locks, idempotency keys)`,\n filePath,\n lineStart: first?.lineStart ?? 0,\n severity: \"high\",\n confidence: \"low\",\n });\n }\n }\n\n log.info(\n `Discovery complete: ${endpoints.length} endpoints, ${dbOperations.length} DB ops, ` +\n `${findings.length} findings`\n );\n\n return { endpoints, dbOperations, authChecks, stateMutations, findings };\n}\n\n/**\n * Convert attack surface findings into Gap objects for the scanner pipeline\n */\nexport function findingsToGaps(\n findings: AttackSurfaceFinding[],\n projectRoot: string\n): Gap[] {\n return findings.map((f, i) => ({\n categoryId: `discovery-${f.type}`,\n categoryName: formatFindingType(f.type),\n domain: f.type === \"missing-auth\" ? \"security\" as const : f.type === \"missing-rate-limit\" ? \"security\" as const : \"concurrency\" as const,\n level: \"integration\" as const,\n priority: f.severity === \"critical\" ? \"P0\" as const : \"P1\" as const,\n severity: f.severity,\n confidence: f.confidence,\n filePath: resolve(projectRoot, f.filePath),\n lineStart: f.lineStart,\n lineEnd: f.lineStart,\n columnStart: 0,\n columnEnd: 0,\n codeSnippet: f.description,\n patternId: `discovery-${f.type}-${i}`,\n patternType: \"semantic\" as const,\n priorityScore: f.severity === \"critical\" ? 12 : f.severity === \"high\" ? 9 : 4,\n status: \"pending\" as const,\n }));\n}\n\n// =============================================================================\n// HELPERS\n// =============================================================================\n\nfunction formatFindingType(type: AttackSurfaceFinding[\"type\"]): string {\n const labels: Record<string, string> = {\n \"missing-auth\": \"Missing Authentication\",\n \"idor\": \"Insecure Direct Object Reference\",\n \"race-condition\": \"Potential Race Condition\",\n \"unvalidated-input\": \"Unvalidated Input\",\n \"missing-rate-limit\": \"Missing Rate Limiting\",\n };\n return labels[type] ?? type;\n}\n\nasync function findSourceFiles(projectRoot: string, maxFiles: number): Promise<string[]> {\n const files: string[] = [];\n const extensions = new Set([\".ts\", \".tsx\", \".js\", \".jsx\", \".py\", \".go\"]);\n const excludeDirs = new Set([\n \"node_modules\", \".git\", \"dist\", \"build\", \"out\", \".next\", \"__pycache__\",\n \"venv\", \".venv\", \"coverage\", \".nyc_output\",\n \"tests\", \"test\", \"__tests__\", \"spec\", \"fixtures\", \"corpus\",\n \"benchmarks\", \"scripts\",\n ]);\n\n async function walk(dir: string, depth: number): Promise<void> {\n if (depth > 10 || files.length >= maxFiles) return;\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n for (const entry of entries) {\n if (files.length >= maxFiles) return;\n if (entry.isDirectory()) {\n if (!excludeDirs.has(entry.name) && !entry.name.startsWith(\".\")) {\n await walk(resolve(dir, entry.name), depth + 1);\n }\n } else if (entry.isFile() && extensions.has(extname(entry.name).toLowerCase())) {\n files.push(resolve(dir, entry.name));\n }\n }\n } catch { /* skip unreadable dirs */ }\n }\n\n await walk(projectRoot, 0);\n return files;\n}\n\nasync function projectHasRateLimiting(projectRoot: string): Promise<boolean> {\n const pkgPath = resolve(projectRoot, \"package.json\");\n if (!existsSync(pkgPath)) return false;\n try {\n const pkg = JSON.parse(await readFile(pkgPath, \"utf-8\")) as Record<string, unknown>;\n const allDeps = {\n ...(pkg[\"dependencies\"] as Record<string, string> | undefined),\n ...(pkg[\"devDependencies\"] as Record<string, string> | undefined),\n };\n return RATE_LIMIT_PATTERNS.some((p) =>\n Object.keys(allDeps).some((dep) => p.test(dep))\n );\n } catch {\n return false;\n }\n}\n","/**\n * Core analysis engine\n *\n * This module contains:\n * - detection/ - Pattern matching against categories\n * - scanner/ - Codebase analysis orchestration\n * - ingestion/ - Code parsing and AST extraction (coming soon)\n * - generation/ - Test code generation (coming soon)\n */\n\nexport const VERSION = \"0.4.0\";\n\n// Detection module\nexport {\n PatternMatcher,\n createPatternMatcher,\n detectLanguage,\n getSupportedExtensions,\n isExtensionSupported,\n type PatternMatcherOptions,\n type ScanOptions,\n type PatternMatch,\n type FileScanResult,\n type AggregatedResults,\n} from \"./detection/index.js\";\n\n// Scanner module\nexport {\n Scanner,\n createScanner,\n SEVERITY_WEIGHTS,\n CONFIDENCE_WEIGHTS,\n PRIORITY_WEIGHTS,\n DEFAULT_TEST_PATTERNS,\n type ScannerOptions,\n type ScanResult,\n type Gap,\n type GapStatus,\n type DomainCoverage,\n type CoverageMetrics,\n type FileStats,\n type PinataScore,\n type ScanSummary,\n} from \"./scanner/index.js\";\n\n// Discovery module\nexport {\n discoverAttackSurface,\n findingsToGaps,\n type AttackSurfaceMap,\n type AttackSurfaceFinding,\n type EndpointInfo,\n type DiscoveryConfig,\n} from \"./discovery/index.js\";\n","/**\n * AI Service Implementation\n *\n * Provides a unified interface for AI completions across providers.\n * Supports Anthropic Claude and OpenAI GPT models.\n */\n\nimport type {\n AIConfig,\n AIProvider,\n AIResponse,\n CompletionRequest,\n} from \"./types.js\";\n\nconst DEFAULT_CONFIG: Required<AIConfig> = {\n provider: \"anthropic\",\n apiKey: \"\",\n model: \"claude-opus-4-8\",\n maxTokens: 1024,\n temperature: 0.3,\n timeoutMs: 30000,\n};\n\nconst PROVIDER_MODELS: Record<AIProvider, string> = {\n anthropic: \"claude-opus-4-8\",\n openai: \"gpt-4o\",\n mock: \"mock-model\",\n};\n\nconst PROVIDER_ENDPOINTS: Record<AIProvider, string> = {\n anthropic: \"https://api.anthropic.com/v1/messages\",\n openai: \"https://api.openai.com/v1/chat/completions\",\n mock: \"\",\n};\n\n/**\n * AI Service for generating completions\n */\nexport class AIService {\n private readonly config: Required<AIConfig>;\n\n constructor(config: Partial<AIConfig> = {}) {\n this.config = {\n ...DEFAULT_CONFIG,\n ...config,\n apiKey: config.apiKey ?? this.getApiKeyFromEnv(config.provider ?? \"anthropic\"),\n model: config.model ?? PROVIDER_MODELS[config.provider ?? \"anthropic\"],\n };\n }\n\n /**\n * Get API key from environment variable\n * For config file support, use the sync version below\n */\n private getApiKeyFromEnv(provider: AIProvider): string {\n if (provider === \"mock\") return \"mock-key\";\n\n const envVar = provider === \"anthropic\" ? \"ANTHROPIC_API_KEY\" : \"OPENAI_API_KEY\";\n const envValue = process.env[envVar];\n if (envValue !== undefined && envValue.length > 0) {\n return envValue;\n }\n\n // Try sync config file read (works in Node.js)\n return this.getApiKeyFromConfig(provider);\n }\n\n /**\n * Read API key from config file synchronously\n * Uses require() for sync file access in constructor context\n */\n private getApiKeyFromConfig(provider: AIProvider): string {\n try {\n /* eslint-disable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */\n const { existsSync, readFileSync } = require(\"node:fs\") as typeof import(\"fs\");\n const { homedir } = require(\"node:os\") as typeof import(\"os\");\n const { join } = require(\"node:path\") as typeof import(\"path\");\n /* eslint-enable @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires */\n\n const configPath = join(homedir(), \".pinata\", \"config.json\");\n if (!existsSync(configPath)) {\n return \"\";\n }\n\n const content = readFileSync(configPath, \"utf-8\");\n const config = JSON.parse(content) as {\n anthropicApiKey?: string;\n openaiApiKey?: string;\n };\n\n return (provider === \"anthropic\" ? config.anthropicApiKey : config.openaiApiKey) ?? \"\";\n } catch {\n return \"\";\n }\n }\n\n /**\n * Check if the service is configured with an API key\n */\n isConfigured(): boolean {\n return this.config.provider === \"mock\" || this.config.apiKey.length > 0;\n }\n\n /**\n * Get the current provider\n */\n getProvider(): AIProvider {\n return this.config.provider;\n }\n\n /**\n * Generate a completion\n */\n async complete(request: CompletionRequest): Promise<AIResponse<string>> {\n const startTime = Date.now();\n\n if (!this.isConfigured()) {\n return {\n success: false,\n error: `API key not configured for ${this.config.provider}. Set ${this.config.provider === \"anthropic\" ? \"ANTHROPIC_API_KEY\" : \"OPENAI_API_KEY\"} environment variable.`,\n durationMs: Date.now() - startTime,\n };\n }\n\n if (this.config.provider === \"mock\") {\n return this.mockComplete(request, startTime);\n }\n\n try {\n const response = await this.callProvider(request);\n return {\n success: true,\n data: response.content,\n usage: response.usage,\n durationMs: Date.now() - startTime,\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n durationMs: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Generate a JSON completion (parses response as JSON)\n */\n async completeJSON<T>(request: CompletionRequest): Promise<AIResponse<T>> {\n const response = await this.complete({\n ...request,\n messages: [\n ...request.messages,\n {\n role: \"user\",\n content: \"\\n\\nRespond with valid JSON only. No markdown, no explanation.\",\n },\n ],\n });\n\n if (!response.success || response.data === undefined) {\n return {\n success: false,\n error: response.error ?? \"No response data\",\n durationMs: response.durationMs,\n };\n }\n\n try {\n // Extract JSON from response (handle markdown code blocks)\n let jsonStr = response.data;\n const jsonMatch = jsonStr.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (jsonMatch) {\n jsonStr = jsonMatch[1] ?? jsonStr;\n }\n\n // Try to find JSON object or array\n const objectMatch = jsonStr.match(/\\{[\\s\\S]*\\}/);\n const arrayMatch = jsonStr.match(/\\[[\\s\\S]*\\]/);\n jsonStr = objectMatch?.[0] ?? arrayMatch?.[0] ?? jsonStr;\n\n const parsed = JSON.parse(jsonStr.trim()) as T;\n const result: AIResponse<T> = {\n success: true,\n data: parsed,\n durationMs: response.durationMs,\n };\n if (response.usage) {\n result.usage = response.usage;\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: `Failed to parse JSON response: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n durationMs: response.durationMs,\n };\n }\n }\n\n /**\n * Call the AI provider API\n */\n private async callProvider(request: CompletionRequest): Promise<{\n content: string;\n usage: { inputTokens: number; outputTokens: number };\n }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeoutMs);\n\n try {\n if (this.config.provider === \"anthropic\") {\n return await this.callAnthropic(request, controller.signal);\n } else {\n return await this.callOpenAI(request, controller.signal);\n }\n } finally {\n clearTimeout(timeout);\n }\n }\n\n /**\n * Call Anthropic API\n */\n private async callAnthropic(\n request: CompletionRequest,\n signal: AbortSignal\n ): Promise<{ content: string; usage: { inputTokens: number; outputTokens: number } }> {\n const messages = request.messages.filter((m) => m.role !== \"system\");\n\n const response = await fetch(PROVIDER_ENDPOINTS.anthropic, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-api-key\": this.config.apiKey,\n \"anthropic-version\": \"2023-06-01\",\n },\n body: JSON.stringify({\n model: this.config.model,\n max_tokens: request.maxTokens ?? this.config.maxTokens,\n temperature: request.temperature ?? this.config.temperature,\n system: request.systemPrompt,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n }),\n signal,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{ text: string }>;\n usage: { input_tokens: number; output_tokens: number };\n };\n\n return {\n content: data.content[0]?.text ?? \"\",\n usage: {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n },\n };\n }\n\n /**\n * Call OpenAI API\n */\n private async callOpenAI(\n request: CompletionRequest,\n signal: AbortSignal\n ): Promise<{ content: string; usage: { inputTokens: number; outputTokens: number } }> {\n const messages: Array<{ role: string; content: string }> = [];\n\n if (request.systemPrompt !== undefined && request.systemPrompt.length > 0) {\n messages.push({ role: \"system\", content: request.systemPrompt });\n }\n\n for (const m of request.messages) {\n messages.push({ role: m.role, content: m.content });\n }\n\n const response = await fetch(PROVIDER_ENDPOINTS.openai, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({\n model: this.config.model,\n max_tokens: request.maxTokens ?? this.config.maxTokens,\n temperature: request.temperature ?? this.config.temperature,\n messages,\n }),\n signal,\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} - ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{ message: { content: string } }>;\n usage: { prompt_tokens: number; completion_tokens: number };\n };\n\n return {\n content: data.choices[0]?.message.content ?? \"\",\n usage: {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n },\n };\n }\n\n /**\n * Mock completion for testing\n */\n private mockComplete(request: CompletionRequest, startTime: number): AIResponse<string> {\n const lastMessage = request.messages[request.messages.length - 1];\n const content = lastMessage?.content ?? \"\";\n\n // Generate mock responses based on content\n let response = \"Mock AI response\";\n\n if (content.includes(\"explain\") || content.includes(\"explanation\")) {\n response = JSON.stringify({\n summary: \"This code pattern may introduce a security vulnerability.\",\n explanation: \"The detected pattern suggests potential security risk.\",\n risk: \"An attacker could exploit this vulnerability to compromise the system.\",\n remediation: \"Use parameterized queries or proper input validation.\",\n safeExample: \"cursor.execute('SELECT * FROM users WHERE id = ?', (user_id,))\",\n });\n } else if (content.includes(\"variable\") || content.includes(\"template\")) {\n response = JSON.stringify({\n suggestions: [\n {\n name: \"className\",\n value: \"UserService\",\n reasoning: \"Based on the file name and context\",\n confidence: 0.8,\n },\n {\n name: \"functionName\",\n value: \"get_user\",\n reasoning: \"Extracted from the code snippet\",\n confidence: 0.9,\n },\n ],\n });\n } else if (content.includes(\"pattern\") || content.includes(\"regex\")) {\n response = JSON.stringify({\n suggestions: [\n {\n id: \"custom-sql-pattern\",\n pattern: \"execute\\\\s*\\\\(.*\\\\+\",\n description: \"Detects SQL execution with string concatenation\",\n confidence: \"medium\",\n matchExample: \"cursor.execute(query + user_input)\",\n safeExample: \"cursor.execute(query, (user_input,))\",\n reasoning: \"String concatenation in SQL queries is a common injection vector\",\n },\n ],\n });\n }\n\n return {\n success: true,\n data: response,\n usage: { inputTokens: 100, outputTokens: 50 },\n durationMs: Date.now() - startTime,\n };\n }\n}\n\n/**\n * Create an AI service instance\n */\nexport function createAIService(config?: Partial<AIConfig>): AIService {\n return new AIService(config);\n}\n","/**\n * Gap Explainer\n *\n * Uses AI to generate natural language explanations of detected gaps.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, GapExplanation } from \"./types.js\";\nimport type { Category } from \"../categories/schema/index.js\";\nimport type { Gap } from \"../core/scanner/types.js\";\n\nconst SYSTEM_PROMPT = `You are a security expert explaining code vulnerabilities to developers.\nYour explanations should be:\n- Clear and actionable\n- Focused on the specific code pattern\n- Include concrete remediation steps\n- Reference relevant security standards (OWASP, CWE) when applicable\n\nAlways respond with valid JSON matching this structure:\n{\n \"summary\": \"1-2 sentence summary\",\n \"explanation\": \"Detailed explanation of the vulnerability\",\n \"risk\": \"What an attacker could do if this is exploited\",\n \"remediation\": \"Step-by-step instructions to fix\",\n \"safeExample\": \"Code example showing the safe pattern\",\n \"references\": [\"optional array of CVE/CWE/OWASP references\"]\n}`;\n\n/**\n * Explain a single gap\n */\nexport async function explainGap(\n gap: Gap,\n category?: Category,\n config?: Partial<AIConfig>\n): Promise<AIResponse<GapExplanation>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n return {\n success: false,\n error: \"AI service not configured\",\n durationMs: 0,\n };\n }\n\n const prompt = buildExplainPrompt(gap, category);\n\n const response = await ai.completeJSON<GapExplanation>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 1024,\n temperature: 0.3,\n });\n\n return response;\n}\n\n/**\n * Explain multiple gaps in batch\n */\nexport async function explainGaps(\n gaps: Gap[],\n categories?: Map<string, Category>,\n config?: Partial<AIConfig>\n): Promise<Map<string, AIResponse<GapExplanation>>> {\n const results = new Map<string, AIResponse<GapExplanation>>();\n\n // Process in parallel with concurrency limit\n const BATCH_SIZE = 5;\n\n for (let i = 0; i < gaps.length; i += BATCH_SIZE) {\n const batch = gaps.slice(i, i + BATCH_SIZE);\n const promises = batch.map(async (gap) => {\n const category = categories?.get(gap.categoryId);\n const result = await explainGap(gap, category, config);\n return { key: `${gap.filePath}:${gap.lineStart}:${gap.categoryId}`, result };\n });\n\n const batchResults = await Promise.all(promises);\n for (const { key, result } of batchResults) {\n results.set(key, result);\n }\n }\n\n return results;\n}\n\n/**\n * Build the explanation prompt for a gap\n */\nfunction buildExplainPrompt(gap: Gap, category?: Category): string {\n const parts: string[] = [];\n\n parts.push(`Explain this security finding:\\n`);\n\n parts.push(`**Category:** ${gap.categoryName} (${gap.categoryId})`);\n parts.push(`**Severity:** ${gap.severity}`);\n parts.push(`**Confidence:** ${gap.confidence}`);\n parts.push(`**File:** ${gap.filePath}`);\n parts.push(`**Line:** ${gap.lineStart}`);\n\n if (gap.codeSnippet) {\n parts.push(`\\n**Code:**\\n\\`\\`\\`\\n${gap.codeSnippet}\\n\\`\\`\\``);\n }\n\n parts.push(`\\n**Pattern:** ${gap.patternId}`);\n parts.push(`**Detection Type:** ${gap.patternType}`);\n\n if (category) {\n parts.push(`\\n**Category Description:** ${category.description}`);\n\n if (category.cves && category.cves.length > 0) {\n parts.push(`**Related CVEs:** ${category.cves.join(\", \")}`);\n }\n\n if (category.references && category.references.length > 0) {\n parts.push(`**References:** ${category.references.slice(0, 3).join(\", \")}`);\n }\n }\n\n parts.push(`\\nProvide a clear, actionable explanation for a developer.`);\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Generate a quick summary without AI (fallback)\n */\nexport function generateFallbackExplanation(gap: Gap): GapExplanation {\n const summaries: Record<string, string> = {\n \"sql-injection\": \"SQL query constructed with user input may allow injection attacks.\",\n \"xss\": \"User input rendered without escaping may allow script injection.\",\n \"command-injection\": \"Shell command constructed with user input may allow command execution.\",\n \"path-traversal\": \"File path constructed with user input may allow directory traversal.\",\n \"hardcoded-secrets\": \"Sensitive credentials found in source code.\",\n \"deserialization\": \"Untrusted data deserialization may allow code execution.\",\n \"ssrf\": \"Server-side request with user-controlled URL may allow internal access.\",\n \"xxe\": \"XML parser may be vulnerable to external entity injection.\",\n \"csrf\": \"State-changing request lacks CSRF protection.\",\n \"ldap-injection\": \"LDAP query constructed with user input may allow injection.\",\n };\n\n const remediations: Record<string, string> = {\n \"sql-injection\": \"Use parameterized queries or prepared statements. Never concatenate user input into SQL strings.\",\n \"xss\": \"Escape all user input before rendering in HTML. Use framework auto-escaping features.\",\n \"command-injection\": \"Avoid shell execution with user input. Use allowlists and subprocess arrays instead of shell strings.\",\n \"path-traversal\": \"Validate and sanitize file paths. Use path.resolve() and verify the result is within allowed directories.\",\n \"hardcoded-secrets\": \"Move secrets to environment variables or a secrets manager. Never commit credentials to source control.\",\n \"deserialization\": \"Avoid deserializing untrusted data. If necessary, use safe formats like JSON instead of pickle/yaml.\",\n \"ssrf\": \"Validate and allowlist URLs. Block private IP ranges and localhost.\",\n \"xxe\": \"Disable external entity processing in XML parser configuration.\",\n \"csrf\": \"Implement CSRF tokens for all state-changing requests.\",\n \"ldap-injection\": \"Escape special LDAP characters in user input. Use parameterized LDAP queries.\",\n };\n\n const summary = summaries[gap.categoryId] ?? `Potential ${gap.categoryName} vulnerability detected.`;\n const remediation = remediations[gap.categoryId] ?? `Review the code for security issues and apply appropriate fixes.`;\n\n return {\n summary,\n explanation: `The pattern \"${gap.patternId}\" detected a potential ${gap.categoryName} vulnerability at line ${gap.lineStart}. This type of issue has ${gap.severity} severity and was detected with ${gap.confidence} confidence.`,\n risk: `If exploited, this vulnerability could compromise the security of the application. Severity: ${gap.severity}.`,\n remediation,\n references: [],\n };\n}\n","/**\n * AI Template Variable Filler\n *\n * Uses AI to intelligently fill template variables based on context.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, VariableSuggestion } from \"./types.js\";\nimport type { TemplateVariable } from \"../categories/schema/index.js\";\nimport type { Gap } from \"../core/scanner/types.js\";\n\nconst SYSTEM_PROMPT = `You are an expert at analyzing code and extracting meaningful variable values for test generation.\nGiven a code snippet and a list of template variables, suggest appropriate values for each variable.\n\nFor each variable, analyze:\n1. The code snippet to extract relevant information (class names, function names, etc.)\n2. The variable description to understand what's needed\n3. The variable type to ensure correct formatting\n\nAlways respond with valid JSON matching this structure:\n{\n \"suggestions\": [\n {\n \"name\": \"variableName\",\n \"value\": \"suggested value\",\n \"reasoning\": \"why this value was chosen\",\n \"confidence\": 0.0-1.0\n }\n ]\n}\n\nFor arrays, use: \"value\": [\"item1\", \"item2\"]\nFor booleans, use: \"value\": true or \"value\": false\nFor numbers, use: \"value\": 42`;\n\nexport interface VariableFillRequest {\n /** Code snippet for context */\n codeSnippet: string;\n /** File path for additional context */\n filePath: string;\n /** Template variables to fill */\n variables: TemplateVariable[];\n /** Optional gap information */\n gap?: Gap;\n /** Any pre-filled values to exclude */\n existingValues?: Record<string, unknown>;\n}\n\nexport interface VariableFillResult {\n /** Suggested values for each variable */\n suggestions: Map<string, VariableSuggestion>;\n /** Variables that couldn't be filled */\n unfilled: string[];\n /** Merged values (suggestions + existing) */\n values: Record<string, unknown>;\n}\n\n/**\n * Suggest variable values for a template\n */\nexport async function suggestVariables(\n request: VariableFillRequest,\n config?: Partial<AIConfig>\n): Promise<AIResponse<VariableFillResult>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n // Fall back to rule-based extraction\n return {\n success: true,\n data: extractVariablesFromCode(request),\n durationMs: 0,\n };\n }\n\n const prompt = buildVariablePrompt(request);\n const startTime = Date.now();\n\n const response = await ai.completeJSON<{ suggestions: VariableSuggestion[] }>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 1024,\n temperature: 0.2,\n });\n\n if (!response.success || !response.data) {\n // Fall back to rule-based extraction\n return {\n success: true,\n data: extractVariablesFromCode(request),\n durationMs: Date.now() - startTime,\n };\n }\n\n // Process AI suggestions\n const suggestions = new Map<string, VariableSuggestion>();\n const unfilled: string[] = [];\n const values: Record<string, unknown> = { ...request.existingValues };\n\n const suggestionsList = response.data.suggestions ?? [];\n for (const suggestion of suggestionsList) {\n suggestions.set(suggestion.name, suggestion);\n if (!(suggestion.name in values)) {\n values[suggestion.name] = suggestion.value;\n }\n }\n\n // Check for unfilled variables\n for (const variable of request.variables) {\n if (!suggestions.has(variable.name) && !(variable.name in values)) {\n if (variable.defaultValue !== undefined) {\n values[variable.name] = variable.defaultValue;\n } else {\n unfilled.push(variable.name);\n }\n }\n }\n\n const result: AIResponse<VariableFillResult> = {\n success: true,\n data: { suggestions, unfilled, values },\n durationMs: response.durationMs,\n };\n\n if (response.usage) {\n result.usage = response.usage;\n }\n\n return result;\n}\n\n/**\n * Build the prompt for variable suggestion\n */\nfunction buildVariablePrompt(request: VariableFillRequest): string {\n const parts: string[] = [];\n\n parts.push(\"Analyze this code and suggest values for the template variables:\\n\");\n\n parts.push(\"**Code:**\");\n parts.push(\"```\");\n parts.push(request.codeSnippet);\n parts.push(\"```\\n\");\n\n parts.push(`**File:** ${request.filePath}\\n`);\n\n if (request.gap) {\n parts.push(`**Category:** ${request.gap.categoryName}`);\n parts.push(`**Line:** ${request.gap.lineStart}\\n`);\n }\n\n parts.push(\"**Variables to fill:**\");\n for (const variable of request.variables) {\n const required = variable.required ? \" (required)\" : \" (optional)\";\n const defaultVal = variable.defaultValue !== undefined\n ? ` [default: ${JSON.stringify(variable.defaultValue)}]`\n : \"\";\n parts.push(`- ${variable.name} (${variable.type})${required}${defaultVal}: ${variable.description}`);\n }\n\n if (request.existingValues && Object.keys(request.existingValues).length > 0) {\n parts.push(\"\\n**Already provided:**\");\n for (const [name, value] of Object.entries(request.existingValues)) {\n parts.push(`- ${name}: ${JSON.stringify(value)}`);\n }\n }\n\n parts.push(\"\\nExtract appropriate values from the code context.\");\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Rule-based variable extraction (fallback when AI is not available)\n */\nfunction extractVariablesFromCode(request: VariableFillRequest): VariableFillResult {\n const suggestions = new Map<string, VariableSuggestion>();\n const unfilled: string[] = [];\n const values: Record<string, unknown> = { ...request.existingValues };\n\n const code = request.codeSnippet;\n const filePath = request.filePath;\n\n for (const variable of request.variables) {\n if (variable.name in values) continue;\n\n let value: unknown = undefined;\n let reasoning = \"\";\n let confidence = 0;\n\n switch (variable.name.toLowerCase()) {\n case \"classname\":\n case \"class_name\": {\n // Extract class name from code or file\n const classMatch = code.match(/class\\s+(\\w+)/);\n if (classMatch) {\n value = classMatch[1];\n reasoning = \"Extracted from class definition in code\";\n confidence = 0.9;\n } else {\n // Try to infer from file name\n const fileName = filePath.split(\"/\").pop()?.replace(/\\.\\w+$/, \"\") ?? \"\";\n value = toPascalCase(fileName);\n reasoning = \"Inferred from file name\";\n confidence = 0.6;\n }\n break;\n }\n\n case \"functionname\":\n case \"function_name\":\n case \"methodname\": {\n // Extract function name from code\n const funcMatch = code.match(/(?:def|function|async function)\\s+(\\w+)/);\n if (funcMatch) {\n value = funcMatch[1];\n reasoning = \"Extracted from function definition\";\n confidence = 0.9;\n }\n break;\n }\n\n case \"modulepath\":\n case \"module_path\": {\n // Convert file path to module path\n value = filePath\n .replace(/\\.[jt]sx?$/, \"\")\n .replace(/\\.py$/, \"\")\n .replace(/\\//g, \".\")\n .replace(/^\\.+/, \"\");\n reasoning = \"Derived from file path\";\n confidence = 0.7;\n break;\n }\n\n case \"tablename\":\n case \"table_name\": {\n // Look for table name in SQL\n const tableMatch = code.match(/(?:FROM|INTO|UPDATE)\\s+(\\w+)/i);\n if (tableMatch) {\n value = tableMatch[1];\n reasoning = \"Extracted from SQL statement\";\n confidence = 0.8;\n } else {\n value = \"users\";\n reasoning = \"Default table name\";\n confidence = 0.3;\n }\n break;\n }\n\n case \"exceptionclass\":\n case \"exception_class\": {\n value = \"ValueError\";\n reasoning = \"Common exception for input validation\";\n confidence = 0.5;\n break;\n }\n\n case \"dbclient\":\n case \"db_client\": {\n // Look for database client variable\n const clientMatch = code.match(/(db|conn|connection|client|cursor)\\s*[=.]/i);\n if (clientMatch) {\n value = clientMatch[1];\n reasoning = \"Extracted from code\";\n confidence = 0.7;\n } else {\n value = \"db\";\n reasoning = \"Default database client name\";\n confidence = 0.4;\n }\n break;\n }\n\n case \"functioncall\":\n case \"function_call\": {\n const funcName = values[\"functionName\"] ?? values[\"function_name\"];\n if (typeof funcName === \"string\" && funcName.length > 0) {\n value = `${funcName}(user_input)`;\n reasoning = \"Constructed from function name\";\n confidence = 0.6;\n }\n break;\n }\n\n case \"fixtures\": {\n value = \"db_session\";\n reasoning = \"Common pytest fixture\";\n confidence = 0.5;\n break;\n }\n\n default:\n // Use default value if available\n if (variable.defaultValue !== undefined) {\n value = variable.defaultValue;\n reasoning = \"Using default value\";\n confidence = 1.0;\n }\n }\n\n if (value !== undefined) {\n suggestions.set(variable.name, {\n name: variable.name,\n value: value as string | number | boolean | string[],\n reasoning,\n confidence,\n });\n values[variable.name] = value;\n } else if (variable.required) {\n unfilled.push(variable.name);\n }\n }\n\n return { suggestions, unfilled, values };\n}\n\n/**\n * Convert string to PascalCase\n */\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n","/**\n * AI Pattern Suggester\n *\n * Uses AI to suggest new detection patterns based on code samples.\n */\n\nimport { createAIService } from \"./service.js\";\n\nimport type { AIConfig, AIResponse, PatternSuggestion } from \"./types.js\";\n\nconst SYSTEM_PROMPT = `You are an expert at creating regex patterns for detecting security vulnerabilities in code.\nGiven vulnerable code samples, generate regex patterns that will detect similar vulnerabilities.\n\nYour patterns should:\n1. Be specific enough to avoid false positives\n2. Be general enough to catch variations\n3. Use standard regex syntax (no lookbehind for compatibility)\n4. Include examples of what matches and what doesn't\n\nAlways respond with valid JSON matching this structure:\n{\n \"suggestions\": [\n {\n \"id\": \"pattern-id-kebab-case\",\n \"pattern\": \"regex pattern here\",\n \"description\": \"What this pattern detects\",\n \"confidence\": \"high|medium|low\",\n \"matchExample\": \"code that should match\",\n \"safeExample\": \"similar code that should NOT match\",\n \"reasoning\": \"Why this pattern works\"\n }\n ]\n}\n\nImportant:\n- Escape backslashes properly for JSON (use \\\\\\\\s not \\\\s)\n- Test your patterns mentally against the examples\n- Prefer simpler patterns that are less likely to cause ReDoS`;\n\nexport interface PatternSuggestionRequest {\n /** Category to suggest patterns for */\n category: string;\n /** Vulnerable code samples */\n vulnerableCode: string[];\n /** Safe code samples (to avoid matching) */\n safeCode?: string[];\n /** Language of the code */\n language: string;\n /** Existing patterns to avoid duplicating */\n existingPatterns?: string[];\n /** Maximum number of suggestions */\n maxSuggestions?: number;\n}\n\nexport interface PatternSuggestionResult {\n /** Suggested patterns */\n suggestions: PatternSuggestion[];\n /** Patterns that were tested but had issues */\n rejected: Array<{\n pattern: string;\n reason: string;\n }>;\n}\n\n/**\n * Suggest patterns based on code samples\n */\nexport async function suggestPatterns(\n request: PatternSuggestionRequest,\n config?: Partial<AIConfig>\n): Promise<AIResponse<PatternSuggestionResult>> {\n const ai = createAIService(config);\n\n if (!ai.isConfigured()) {\n return {\n success: false,\n error: \"AI service not configured. Set ANTHROPIC_API_KEY or OPENAI_API_KEY.\",\n durationMs: 0,\n };\n }\n\n const prompt = buildPatternPrompt(request);\n\n const response = await ai.completeJSON<{ suggestions: PatternSuggestion[] }>({\n systemPrompt: SYSTEM_PROMPT,\n messages: [{ role: \"user\", content: prompt }],\n maxTokens: 2048,\n temperature: 0.3,\n });\n\n if (!response.success || !response.data) {\n return {\n success: false,\n error: response.error ?? \"Failed to generate patterns\",\n durationMs: response.durationMs,\n };\n }\n\n // Validate and test each pattern\n const validated = validatePatterns(\n response.data.suggestions ?? [],\n request.vulnerableCode,\n request.safeCode ?? []\n );\n\n const result: AIResponse<PatternSuggestionResult> = {\n success: true,\n data: validated,\n durationMs: response.durationMs,\n };\n\n if (response.usage) {\n result.usage = response.usage;\n }\n\n return result;\n}\n\n/**\n * Build the prompt for pattern suggestion\n */\nfunction buildPatternPrompt(request: PatternSuggestionRequest): string {\n const parts: string[] = [];\n\n parts.push(`Generate regex patterns to detect ${request.category} vulnerabilities in ${request.language} code.\\n`);\n\n parts.push(\"**Vulnerable code samples (patterns SHOULD match these):**\");\n for (let i = 0; i < request.vulnerableCode.length; i++) {\n parts.push(`\\nExample ${i + 1}:`);\n parts.push(\"```\");\n parts.push(request.vulnerableCode[i] ?? \"\");\n parts.push(\"```\");\n }\n\n if (request.safeCode && request.safeCode.length > 0) {\n parts.push(\"\\n**Safe code samples (patterns should NOT match these):**\");\n for (let i = 0; i < request.safeCode.length; i++) {\n parts.push(`\\nSafe ${i + 1}:`);\n parts.push(\"```\");\n parts.push(request.safeCode[i] ?? \"\");\n parts.push(\"```\");\n }\n }\n\n if (request.existingPatterns && request.existingPatterns.length > 0) {\n parts.push(\"\\n**Existing patterns (avoid duplicating):**\");\n for (const pattern of request.existingPatterns) {\n parts.push(`- ${pattern}`);\n }\n }\n\n parts.push(`\\nGenerate up to ${request.maxSuggestions ?? 3} distinct patterns.`);\n parts.push(\"Focus on patterns that will have high precision (low false positives).\");\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Validate patterns against test samples\n */\nfunction validatePatterns(\n suggestions: PatternSuggestion[],\n vulnerableCode: string[],\n safeCode: string[]\n): PatternSuggestionResult {\n const validated: PatternSuggestion[] = [];\n const rejected: Array<{ pattern: string; reason: string }> = [];\n\n for (const suggestion of suggestions) {\n try {\n // Test if pattern compiles\n const regex = new RegExp(suggestion.pattern, \"gm\");\n\n // Test against vulnerable samples\n let matchCount = 0;\n for (const code of vulnerableCode) {\n regex.lastIndex = 0;\n if (regex.test(code)) {\n matchCount++;\n }\n }\n\n // Test against safe samples\n let falsePositives = 0;\n for (const code of safeCode) {\n regex.lastIndex = 0;\n if (regex.test(code)) {\n falsePositives++;\n }\n }\n\n // Check for ReDoS potential (simple heuristic)\n if (hasRedosPotential(suggestion.pattern)) {\n rejected.push({\n pattern: suggestion.pattern,\n reason: \"Pattern may be vulnerable to ReDoS\",\n });\n continue;\n }\n\n // Accept if it matches at least some vulnerable code\n if (matchCount > 0) {\n // Adjust confidence based on actual results\n if (falsePositives > 0 && suggestion.confidence === \"high\") {\n suggestion.confidence = \"medium\";\n }\n if (matchCount < vulnerableCode.length / 2 && suggestion.confidence === \"high\") {\n suggestion.confidence = \"medium\";\n }\n validated.push(suggestion);\n } else {\n rejected.push({\n pattern: suggestion.pattern,\n reason: `Pattern did not match any vulnerable samples (0/${vulnerableCode.length})`,\n });\n }\n } catch (error) {\n rejected.push({\n pattern: suggestion.pattern,\n reason: `Invalid regex: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n });\n }\n }\n\n return { suggestions: validated, rejected };\n}\n\n/**\n * Check for potential ReDoS patterns (simple heuristic)\n */\nfunction hasRedosPotential(pattern: string): boolean {\n // Check for nested quantifiers like (a+)+ or (a*)*\n if (/\\([^)]*[+*][^)]*\\)[+*]/.test(pattern)) {\n return true;\n }\n\n // Check for overlapping alternations with quantifiers\n if (/\\([^)]*\\|[^)]*\\)[+*]/.test(pattern)) {\n // More specific check for dangerous patterns\n const alternationMatch = pattern.match(/\\(([^)]+)\\)/g);\n if (alternationMatch) {\n for (const alt of alternationMatch) {\n // Check if alternation branches can match same input\n if (/\\w+\\|\\w*\\w/.test(alt) && /[+*]/.test(alt)) {\n return true;\n }\n }\n }\n }\n\n return false;\n}\n\n/**\n * Format a pattern suggestion as YAML for adding to category definitions\n */\nexport function formatPatternAsYaml(suggestion: PatternSuggestion, language: string): string {\n // Escape the pattern for YAML\n const escapedPattern = suggestion.pattern\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"');\n\n return ` - id: ${suggestion.id}\n type: regex\n language: ${language}\n pattern: \"${escapedPattern}\"\n confidence: ${suggestion.confidence}\n description: ${suggestion.description}`;\n}\n\n/**\n * Suggest patterns from missed vulnerabilities (for improving detection)\n */\nexport async function suggestPatternsFromMissed(\n category: string,\n missedCode: string[],\n detectedCode: string[],\n language: string,\n config?: Partial<AIConfig>\n): Promise<AIResponse<PatternSuggestionResult>> {\n // The missed code is what we WANT to detect\n // The detected code can help understand what patterns we already catch\n return suggestPatterns(\n {\n category,\n vulnerableCode: missedCode,\n safeCode: [], // We don't have safe code in this context\n language,\n maxSuggestions: 5,\n },\n config\n );\n}\n"]}
|