ai-warden 0.2.1 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-warden",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "AI security scanner - Detect prompt injection attacks before they reach production",
5
5
  "main": "src/scanner.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -8,6 +8,7 @@
8
8
  const fs = require('fs');
9
9
  const path = require('path');
10
10
  const scanner = require('./scanner');
11
+ const fileClassifier = require('./fileClassifier');
11
12
 
12
13
  const args = process.argv.slice(2);
13
14
  const command = args[0];
@@ -82,10 +83,23 @@ function scanCommand(targetPath, options = {}) {
82
83
 
83
84
  files.forEach(file => {
84
85
  try {
86
+ // Check if file should be skipped
87
+ if (fileClassifier.shouldSkipFile(file)) {
88
+ if (options.verbose) {
89
+ console.log(`⏭️ ${path.relative(process.cwd(), file)} - Skipped`);
90
+ }
91
+ return;
92
+ }
93
+
85
94
  const content = fs.readFileSync(file, 'utf-8');
95
+ const fileType = fileClassifier.classifyFile(file);
96
+ const baseThreshold = options.mode === 'strict' ? 75 : options.mode === 'permissive' ? 250 : 150;
97
+ const adjustedThreshold = fileClassifier.getAdjustedThreshold(fileType, baseThreshold);
98
+
86
99
  const result = scanner.scan(content, {
87
100
  mode: options.mode || 'balanced',
88
- context: 'general',
101
+ threshold: adjustedThreshold,
102
+ context: fileClassifier.getFileContext(file),
89
103
  verbose: options.verbose
90
104
  });
91
105
 
@@ -0,0 +1,146 @@
1
+ /**
2
+ * File Classifier
3
+ * Determines if a file should be scanned differently based on its type/purpose
4
+ */
5
+
6
+ const path = require('path');
7
+
8
+ // Files that should be completely skipped
9
+ const SKIP_PATTERNS = [
10
+ /node_modules/,
11
+ /\.git/,
12
+ /\.vscode/,
13
+ /\.idea/,
14
+ /dist\//,
15
+ /build\//,
16
+ /coverage\//,
17
+ /\.min\.js$/,
18
+ /\.bundle\.js$/,
19
+ /package-lock\.json$/,
20
+ /yarn\.lock$/
21
+ ];
22
+
23
+ // Documentation files (lower threshold, whitelist common patterns)
24
+ const DOCUMENTATION_PATTERNS = [
25
+ /\.md$/,
26
+ /\.txt$/,
27
+ /README/i,
28
+ /CHANGELOG/i,
29
+ /LICENSE/i,
30
+ /CONTRIBUTING/i,
31
+ /docs?\//i,
32
+ /examples?\//i
33
+ ];
34
+
35
+ // Test files (lower threshold)
36
+ const TEST_PATTERNS = [
37
+ /\.test\.(js|ts|jsx|tsx|py|java)$/,
38
+ /\.spec\.(js|ts|jsx|tsx|py|java)$/,
39
+ /__tests__\//,
40
+ /tests?\//,
41
+ /test\//,
42
+ /spec\//,
43
+ /\.test$/,
44
+ /\.spec$/
45
+ ];
46
+
47
+ // API specification files (very permissive, lots of example data)
48
+ const API_SPEC_PATTERNS = [
49
+ /swagger\.(yaml|yml|json)$/,
50
+ /openapi\.(yaml|yml|json)$/,
51
+ /api-spec/i,
52
+ /postman/i
53
+ ];
54
+
55
+ // Configuration files (usually safe)
56
+ const CONFIG_PATTERNS = [
57
+ /\.(json|yaml|yml|toml|ini|conf)$/,
58
+ /\.config\.(js|ts)$/,
59
+ /\.rc$/
60
+ ];
61
+
62
+ /**
63
+ * Classify a file based on its path
64
+ * Returns: 'skip' | 'documentation' | 'test' | 'api-spec' | 'config' | 'code'
65
+ */
66
+ function classifyFile(filePath) {
67
+ const normalized = path.normalize(filePath);
68
+
69
+ // Check if should be skipped entirely
70
+ if (SKIP_PATTERNS.some(pattern => pattern.test(normalized))) {
71
+ return 'skip';
72
+ }
73
+
74
+ // Check documentation
75
+ if (DOCUMENTATION_PATTERNS.some(pattern => pattern.test(normalized))) {
76
+ return 'documentation';
77
+ }
78
+
79
+ // Check test files
80
+ if (TEST_PATTERNS.some(pattern => pattern.test(normalized))) {
81
+ return 'test';
82
+ }
83
+
84
+ // Check API specs
85
+ if (API_SPEC_PATTERNS.some(pattern => pattern.test(normalized))) {
86
+ return 'api-spec';
87
+ }
88
+
89
+ // Check config files
90
+ if (CONFIG_PATTERNS.some(pattern => pattern.test(normalized))) {
91
+ return 'config';
92
+ }
93
+
94
+ // Default: treat as code
95
+ return 'code';
96
+ }
97
+
98
+ /**
99
+ * Get adjusted threshold based on file type
100
+ */
101
+ function getAdjustedThreshold(fileType, baseThreshold) {
102
+ const multipliers = {
103
+ 'skip': 0, // Will be skipped anyway
104
+ 'documentation': 4.0, // Very permissive (600 for balanced mode)
105
+ 'test': 3.5, // Very permissive (525 for balanced) - test data often triggers patterns
106
+ 'api-spec': 5.0, // Extremely permissive (750 for balanced)
107
+ 'config': 2.0, // Permissive (300 for balanced)
108
+ 'code': 1.0 // Normal threshold
109
+ };
110
+
111
+ return Math.floor(baseThreshold * (multipliers[fileType] || 1.0));
112
+ }
113
+
114
+ /**
115
+ * Should we skip scanning this file entirely?
116
+ */
117
+ function shouldSkipFile(filePath) {
118
+ return classifyFile(filePath) === 'skip';
119
+ }
120
+
121
+ /**
122
+ * Get context string for better pattern matching
123
+ */
124
+ function getFileContext(filePath) {
125
+ const fileType = classifyFile(filePath);
126
+
127
+ const contextMap = {
128
+ 'documentation': 'documentation',
129
+ 'test': 'test',
130
+ 'api-spec': 'api-spec',
131
+ 'config': 'config',
132
+ 'code': 'general'
133
+ };
134
+
135
+ return contextMap[fileType] || 'general';
136
+ }
137
+
138
+ module.exports = {
139
+ classifyFile,
140
+ getAdjustedThreshold,
141
+ shouldSkipFile,
142
+ getFileContext,
143
+ DOCUMENTATION_PATTERNS,
144
+ TEST_PATTERNS,
145
+ API_SPEC_PATTERNS
146
+ };