@euconform/core 1.0.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/evidence/bundle.d.ts +23 -0
  4. package/dist/evidence/bundle.d.ts.map +1 -0
  5. package/dist/evidence/bundle.js +44 -0
  6. package/dist/evidence/compliance-evaluation.d.ts +12 -0
  7. package/dist/evidence/compliance-evaluation.d.ts.map +1 -0
  8. package/dist/evidence/compliance-evaluation.js +78 -0
  9. package/dist/evidence/hash.d.ts +2 -0
  10. package/dist/evidence/hash.d.ts.map +1 -0
  11. package/dist/evidence/hash.js +4 -0
  12. package/dist/evidence/index.d.ts +13 -0
  13. package/dist/evidence/index.d.ts.map +1 -0
  14. package/dist/evidence/index.js +11 -0
  15. package/dist/evidence/markdown.d.ts +9 -0
  16. package/dist/evidence/markdown.d.ts.map +1 -0
  17. package/dist/evidence/markdown.js +169 -0
  18. package/dist/evidence/output.d.ts +13 -0
  19. package/dist/evidence/output.d.ts.map +1 -0
  20. package/dist/evidence/output.js +547 -0
  21. package/dist/evidence/types.d.ts +230 -0
  22. package/dist/evidence/types.d.ts.map +1 -0
  23. package/dist/evidence/types.js +7 -0
  24. package/dist/evidence/validate.d.ts +8 -0
  25. package/dist/evidence/validate.d.ts.map +1 -0
  26. package/dist/evidence/validate.js +175 -0
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/inference/ollama-client.d.ts +3 -0
  31. package/dist/inference/ollama-client.d.ts.map +1 -1
  32. package/dist/inference/ollama-client.js +69 -71
  33. package/dist/legal-checks/annex-iv-report.d.ts +3 -0
  34. package/dist/legal-checks/annex-iv-report.d.ts.map +1 -1
  35. package/dist/legal-checks/annex-iv-report.js +1 -0
  36. package/dist/legal-checks/deadline-timeline.d.ts +57 -0
  37. package/dist/legal-checks/deadline-timeline.d.ts.map +1 -0
  38. package/dist/legal-checks/deadline-timeline.js +265 -0
  39. package/dist/legal-checks/gap-analysis.d.ts +48 -0
  40. package/dist/legal-checks/gap-analysis.d.ts.map +1 -0
  41. package/dist/legal-checks/gap-analysis.js +397 -0
  42. package/dist/legal-checks/gpai-classifier.d.ts +49 -0
  43. package/dist/legal-checks/gpai-classifier.d.ts.map +1 -0
  44. package/dist/legal-checks/gpai-classifier.js +197 -0
  45. package/dist/legal-checks/index.d.ts +6 -0
  46. package/dist/legal-checks/index.d.ts.map +1 -1
  47. package/dist/legal-checks/index.js +3 -0
  48. package/dist/scanner/aggregator.d.ts +7 -0
  49. package/dist/scanner/aggregator.d.ts.map +1 -0
  50. package/dist/scanner/aggregator.js +200 -0
  51. package/dist/scanner/detectors/ai-framework-detector.d.ts +3 -0
  52. package/dist/scanner/detectors/ai-framework-detector.d.ts.map +1 -0
  53. package/dist/scanner/detectors/ai-framework-detector.js +74 -0
  54. package/dist/scanner/detectors/ai-provider-detector.d.ts +3 -0
  55. package/dist/scanner/detectors/ai-provider-detector.d.ts.map +1 -0
  56. package/dist/scanner/detectors/ai-provider-detector.js +100 -0
  57. package/dist/scanner/detectors/compliance-detector.d.ts +3 -0
  58. package/dist/scanner/detectors/compliance-detector.d.ts.map +1 -0
  59. package/dist/scanner/detectors/compliance-detector.js +201 -0
  60. package/dist/scanner/detectors/config-detector.d.ts +3 -0
  61. package/dist/scanner/detectors/config-detector.d.ts.map +1 -0
  62. package/dist/scanner/detectors/config-detector.js +248 -0
  63. package/dist/scanner/detectors/framework-detector.d.ts +3 -0
  64. package/dist/scanner/detectors/framework-detector.d.ts.map +1 -0
  65. package/dist/scanner/detectors/framework-detector.js +141 -0
  66. package/dist/scanner/detectors/index.d.ts +8 -0
  67. package/dist/scanner/detectors/index.d.ts.map +1 -0
  68. package/dist/scanner/detectors/index.js +37 -0
  69. package/dist/scanner/detectors/local-inference-detector.d.ts +3 -0
  70. package/dist/scanner/detectors/local-inference-detector.d.ts.map +1 -0
  71. package/dist/scanner/detectors/local-inference-detector.js +93 -0
  72. package/dist/scanner/detectors/markdown-detector.d.ts +3 -0
  73. package/dist/scanner/detectors/markdown-detector.d.ts.map +1 -0
  74. package/dist/scanner/detectors/markdown-detector.js +139 -0
  75. package/dist/scanner/detectors/package-json-detector.d.ts +3 -0
  76. package/dist/scanner/detectors/package-json-detector.d.ts.map +1 -0
  77. package/dist/scanner/detectors/package-json-detector.js +166 -0
  78. package/dist/scanner/detectors/rag-detector.d.ts +3 -0
  79. package/dist/scanner/detectors/rag-detector.d.ts.map +1 -0
  80. package/dist/scanner/detectors/rag-detector.js +132 -0
  81. package/dist/scanner/detectors/shared.d.ts +18 -0
  82. package/dist/scanner/detectors/shared.d.ts.map +1 -0
  83. package/dist/scanner/detectors/shared.js +36 -0
  84. package/dist/scanner/discovery.d.ts +14 -0
  85. package/dist/scanner/discovery.d.ts.map +1 -0
  86. package/dist/scanner/discovery.js +235 -0
  87. package/dist/scanner/index.d.ts +9 -0
  88. package/dist/scanner/index.d.ts.map +1 -0
  89. package/dist/scanner/index.js +8 -0
  90. package/package.json +6 -3
  91. package/src/evidence/bundle.ts +65 -0
  92. package/src/evidence/compliance-evaluation.ts +114 -0
  93. package/src/evidence/hash.ts +5 -0
  94. package/src/evidence/index.ts +51 -0
  95. package/src/evidence/markdown.ts +226 -0
  96. package/src/evidence/output.ts +717 -0
  97. package/src/evidence/types.ts +329 -0
  98. package/src/evidence/validate.ts +270 -0
  99. package/src/index.ts +25 -0
  100. package/src/inference/ollama-client.ts +93 -86
  101. package/src/legal-checks/annex-iv-report.ts +4 -0
  102. package/src/legal-checks/deadline-timeline.ts +313 -0
  103. package/src/legal-checks/gap-analysis.ts +454 -0
  104. package/src/legal-checks/gpai-classifier.ts +281 -0
  105. package/src/legal-checks/index.ts +33 -0
  106. package/src/scanner/aggregator.ts +258 -0
  107. package/src/scanner/detectors/ai-framework-detector.ts +94 -0
  108. package/src/scanner/detectors/ai-provider-detector.ts +135 -0
  109. package/src/scanner/detectors/compliance-detector.ts +232 -0
  110. package/src/scanner/detectors/config-detector.ts +316 -0
  111. package/src/scanner/detectors/framework-detector.ts +163 -0
  112. package/src/scanner/detectors/index.ts +40 -0
  113. package/src/scanner/detectors/local-inference-detector.ts +124 -0
  114. package/src/scanner/detectors/markdown-detector.ts +176 -0
  115. package/src/scanner/detectors/package-json-detector.ts +202 -0
  116. package/src/scanner/detectors/rag-detector.ts +162 -0
  117. package/src/scanner/detectors/shared.ts +45 -0
  118. package/src/scanner/discovery.ts +290 -0
  119. package/src/scanner/index.ts +9 -0
  120. package/tests/evidence/bundle.test.ts +128 -0
  121. package/tests/evidence/ecef-schemas.test.ts +316 -0
  122. package/tests/evidence/hash.test.ts +25 -0
  123. package/tests/evidence/markdown.test.ts +92 -0
  124. package/tests/evidence/output.test.ts +203 -0
  125. package/tests/fixtures/compliance-good/README.md +14 -0
  126. package/tests/fixtures/compliance-good/lib/ai-service.ts +17 -0
  127. package/tests/fixtures/compliance-good/lib/review-flow.ts +11 -0
  128. package/tests/fixtures/compliance-good/package.json +10 -0
  129. package/tests/fixtures/compliance-good/tests/bias-check.test.ts +13 -0
  130. package/tests/fixtures/nextjs-openai/README.md +5 -0
  131. package/tests/fixtures/nextjs-openai/app/page.tsx +11 -0
  132. package/tests/fixtures/nextjs-openai/package.json +9 -0
  133. package/tests/fixtures/ollama-rag/.env.example +2 -0
  134. package/tests/fixtures/ollama-rag/docker-compose.yml +9 -0
  135. package/tests/fixtures/ollama-rag/package.json +9 -0
  136. package/tests/fixtures/ollama-rag/server.ts +21 -0
  137. package/tests/fixtures/plain-webapp/README.md +3 -0
  138. package/tests/fixtures/plain-webapp/index.js +5 -0
  139. package/tests/fixtures/plain-webapp/package.json +8 -0
  140. package/tests/gpai-classifier.test.ts +125 -0
  141. package/tests/gpai-timeline.test.ts +55 -0
  142. package/tests/scanner/aggregator.test.ts +122 -0
  143. package/tests/scanner/detectors.test.ts +274 -0
  144. package/tests/scanner/discovery.test.ts +87 -0
  145. package/vitest.config.ts +1 -0
  146. package/.turbo/turbo-check-types.log +0 -4
  147. package/.turbo/turbo-test.log +0 -364
  148. package/coverage/base.css +0 -224
  149. package/coverage/block-navigation.js +0 -87
  150. package/coverage/clover.xml +0 -3282
  151. package/coverage/coverage-final.json +0 -20
  152. package/coverage/favicon.png +0 -0
  153. package/coverage/index.html +0 -161
  154. package/coverage/prettify.css +0 -1
  155. package/coverage/prettify.js +0 -2
  156. package/coverage/sort-arrow-sprite.png +0 -0
  157. package/coverage/sorter.js +0 -210
  158. package/coverage/src/fairness-metrics.ts.html +0 -1579
  159. package/coverage/src/index.html +0 -161
  160. package/coverage/src/index.ts.html +0 -535
  161. package/coverage/src/inference/browser-inference.ts.html +0 -859
  162. package/coverage/src/inference/capability-detection.ts.html +0 -2227
  163. package/coverage/src/inference/index.html +0 -176
  164. package/coverage/src/inference/index.ts.html +0 -553
  165. package/coverage/src/inference/inference-factory.ts.html +0 -751
  166. package/coverage/src/inference/ollama-client.ts.html +0 -1627
  167. package/coverage/src/legal-checks/annex-iv-report.ts.html +0 -556
  168. package/coverage/src/legal-checks/bias-metrics.ts.html +0 -1855
  169. package/coverage/src/legal-checks/data-governance.ts.html +0 -529
  170. package/coverage/src/legal-checks/human-oversight-logging.ts.html +0 -490
  171. package/coverage/src/legal-checks/index.html +0 -206
  172. package/coverage/src/legal-checks/index.ts.html +0 -250
  173. package/coverage/src/legal-checks/risk-classifier.ts.html +0 -940
  174. package/coverage/src/legal-checks/robustness-transparency.ts.html +0 -571
  175. package/coverage/src/metrics/crows-pairs-bias.ts.html +0 -820
  176. package/coverage/src/metrics/index.html +0 -146
  177. package/coverage/src/metrics/index.ts.html +0 -151
  178. package/coverage/src/metrics/stereotype-bias.ts.html +0 -886
  179. package/coverage/src/risk-engine.ts.html +0 -1660
  180. package/coverage/src/types.ts.html +0 -547
  181. package/dist/legal-checks/disclaimer.d.ts +0 -2
  182. package/dist/legal-checks/disclaimer.d.ts.map +0 -1
  183. package/dist/legal-checks/disclaimer.js +0 -1
@@ -0,0 +1,248 @@
1
+ const envKeyRules = [
2
+ {
3
+ id: "ai-provider-openai",
4
+ name: "OpenAI API key",
5
+ category: "ai-provider",
6
+ pattern: /^OPENAI_API_KEY\b/,
7
+ confidence: "high",
8
+ },
9
+ {
10
+ id: "ai-provider-anthropic",
11
+ name: "Anthropic API key",
12
+ category: "ai-provider",
13
+ pattern: /^ANTHROPIC_API_KEY\b/,
14
+ confidence: "high",
15
+ },
16
+ {
17
+ id: "ai-provider-azure-openai",
18
+ name: "Azure OpenAI key",
19
+ category: "ai-provider",
20
+ pattern: /^AZURE_OPENAI_/,
21
+ confidence: "high",
22
+ },
23
+ {
24
+ id: "ai-provider-google-ai",
25
+ name: "Google AI key",
26
+ category: "ai-provider",
27
+ pattern: /^(?:GOOGLE_AI_API_KEY|GEMINI_API_KEY)\b/,
28
+ confidence: "high",
29
+ },
30
+ {
31
+ id: "ai-provider-cohere",
32
+ name: "Cohere API key",
33
+ category: "ai-provider",
34
+ pattern: /^COHERE_API_KEY\b/,
35
+ confidence: "high",
36
+ },
37
+ {
38
+ id: "ai-provider-replicate",
39
+ name: "Replicate API token",
40
+ category: "ai-provider",
41
+ pattern: /^REPLICATE_API_TOKEN\b/,
42
+ confidence: "high",
43
+ },
44
+ {
45
+ id: "ai-provider-huggingface",
46
+ name: "HuggingFace token",
47
+ category: "ai-provider",
48
+ pattern: /^HUGGINGFACE_TOKEN\b|^HF_TOKEN\b/,
49
+ confidence: "high",
50
+ },
51
+ {
52
+ id: "local-inference-ollama",
53
+ name: "Ollama host config",
54
+ category: "local-inference",
55
+ pattern: /^OLLAMA_HOST\b|^OLLAMA_BASE_URL\b/,
56
+ confidence: "high",
57
+ },
58
+ {
59
+ id: "rag-pinecone",
60
+ name: "Pinecone API key",
61
+ category: "rag",
62
+ pattern: /^PINECONE_API_KEY\b/,
63
+ confidence: "high",
64
+ },
65
+ {
66
+ id: "rag-weaviate",
67
+ name: "Weaviate config",
68
+ category: "rag",
69
+ pattern: /^WEAVIATE_/,
70
+ confidence: "high",
71
+ },
72
+ {
73
+ id: "rag-chroma",
74
+ name: "ChromaDB config",
75
+ category: "rag",
76
+ pattern: /^CHROMA_/,
77
+ confidence: "high",
78
+ },
79
+ ];
80
+ const dockerServiceRules = [
81
+ {
82
+ id: "local-inference-ollama-docker",
83
+ name: "Ollama Docker service",
84
+ category: "local-inference",
85
+ pattern: /\bollama\/ollama\b|image:\s*ollama/,
86
+ confidence: "high",
87
+ },
88
+ {
89
+ id: "rag-chromadb-docker",
90
+ name: "ChromaDB Docker service",
91
+ category: "rag",
92
+ pattern: /\bchromadb\/chroma\b|image:\s*chroma/,
93
+ confidence: "high",
94
+ },
95
+ {
96
+ id: "rag-weaviate-docker",
97
+ name: "Weaviate Docker service",
98
+ category: "rag",
99
+ pattern: /\bsemitechnologies\/weaviate\b|image:\s*weaviate/,
100
+ confidence: "high",
101
+ },
102
+ {
103
+ id: "rag-redis-vector",
104
+ name: "Redis with vector module",
105
+ category: "rag",
106
+ pattern: /redis\/redis-stack|redisearch|redis-stack-server/,
107
+ confidence: "high",
108
+ },
109
+ {
110
+ id: "rag-qdrant-docker",
111
+ name: "Qdrant Docker service",
112
+ category: "rag",
113
+ pattern: /\bqdrant\/qdrant\b|image:\s*qdrant/,
114
+ confidence: "high",
115
+ },
116
+ ];
117
+ const dockerfileRules = [
118
+ {
119
+ id: "local-inference-pip-ai",
120
+ name: "AI pip packages in Dockerfile",
121
+ category: "local-inference",
122
+ pattern: /pip\s+install\s+.*\b(?:torch|tensorflow|transformers|langchain|llama[-_]?cpp|vllm|onnxruntime)\b/,
123
+ confidence: "high",
124
+ },
125
+ {
126
+ id: "local-inference-model-download",
127
+ name: "Model download in Dockerfile",
128
+ category: "local-inference",
129
+ pattern: /\b(?:huggingface-cli\s+download|wget\s+.*(?:\.gguf|\.safetensors|\.bin)|COPY\s+.*(?:model|weights))\b/i,
130
+ confidence: "high",
131
+ },
132
+ ];
133
+ // ---------------------------------------------------------------------------
134
+ // File matching helpers
135
+ // ---------------------------------------------------------------------------
136
+ function isEnvExample(relativePath) {
137
+ const basename = relativePath.split("/").pop() ?? "";
138
+ return /^\.env\.(?:example|sample)$/.test(basename);
139
+ }
140
+ function isDockerCompose(relativePath) {
141
+ const basename = relativePath.split("/").pop() ?? "";
142
+ return /^docker-compose/.test(basename);
143
+ }
144
+ function isDockerfile(relativePath) {
145
+ const basename = relativePath.split("/").pop() ?? "";
146
+ return /^Dockerfile/.test(basename);
147
+ }
148
+ // ---------------------------------------------------------------------------
149
+ // Detector
150
+ // ---------------------------------------------------------------------------
151
+ export function detectConfig(ctx) {
152
+ const { file } = ctx;
153
+ const signals = [];
154
+ const lines = ctx.lines;
155
+ if (isEnvExample(file.relativePath)) {
156
+ detectEnvKeys(file.relativePath, lines, signals);
157
+ }
158
+ else if (isDockerCompose(file.relativePath)) {
159
+ detectDockerServices(file.relativePath, lines, signals);
160
+ }
161
+ else if (isDockerfile(file.relativePath)) {
162
+ detectDockerfilePatterns(file.relativePath, lines, signals);
163
+ }
164
+ return signals;
165
+ }
166
+ function extractEnvVarName(rawLine) {
167
+ const line = rawLine.trim();
168
+ if (!line || line.startsWith("#"))
169
+ return null;
170
+ const eqIndex = line.indexOf("=");
171
+ return eqIndex >= 0 ? line.slice(0, eqIndex).trim() : line.trim();
172
+ }
173
+ function detectEnvKeys(relativePath, lines, signals) {
174
+ for (const rule of envKeyRules) {
175
+ const evidence = [];
176
+ for (let i = 0; i < lines.length; i++) {
177
+ const varName = extractEnvVarName(lines[i] ?? "");
178
+ if (varName && rule.pattern.test(varName)) {
179
+ evidence.push({ file: relativePath, line: i + 1, snippet: varName });
180
+ }
181
+ }
182
+ if (evidence.length > 0) {
183
+ signals.push({
184
+ id: rule.id,
185
+ name: rule.name,
186
+ category: rule.category,
187
+ confidence: rule.confidence,
188
+ evidence,
189
+ });
190
+ }
191
+ }
192
+ }
193
+ function detectDockerServices(relativePath, lines, signals) {
194
+ for (const rule of dockerServiceRules) {
195
+ const evidence = [];
196
+ for (let i = 0; i < lines.length; i++) {
197
+ const line = lines[i];
198
+ if (!line)
199
+ continue;
200
+ if (rule.pattern.test(line)) {
201
+ evidence.push({
202
+ file: relativePath,
203
+ line: i + 1,
204
+ snippet: line.trim().slice(0, 120),
205
+ });
206
+ if (evidence.length >= 3)
207
+ break;
208
+ }
209
+ }
210
+ if (evidence.length > 0) {
211
+ signals.push({
212
+ id: rule.id,
213
+ name: rule.name,
214
+ category: rule.category,
215
+ confidence: rule.confidence,
216
+ evidence,
217
+ });
218
+ }
219
+ }
220
+ }
221
+ function detectDockerfilePatterns(relativePath, lines, signals) {
222
+ for (const rule of dockerfileRules) {
223
+ const evidence = [];
224
+ for (let i = 0; i < lines.length; i++) {
225
+ const line = lines[i];
226
+ if (!line)
227
+ continue;
228
+ if (rule.pattern.test(line)) {
229
+ evidence.push({
230
+ file: relativePath,
231
+ line: i + 1,
232
+ snippet: line.trim().slice(0, 120),
233
+ });
234
+ if (evidence.length >= 3)
235
+ break;
236
+ }
237
+ }
238
+ if (evidence.length > 0) {
239
+ signals.push({
240
+ id: rule.id,
241
+ name: rule.name,
242
+ category: rule.category,
243
+ confidence: rule.confidence,
244
+ evidence,
245
+ });
246
+ }
247
+ }
248
+ }
@@ -0,0 +1,3 @@
1
+ import type { DetectedSignal, DetectorContext } from "../../evidence/types";
2
+ export declare function detectFrameworks(ctx: DetectorContext): DetectedSignal[];
3
+ //# sourceMappingURL=framework-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-detector.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/framework-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAwH9B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CAqCvE"}
@@ -0,0 +1,141 @@
1
+ import { EXTENDED_EXTENSIONS } from "./shared";
2
+ const rules = [
3
+ // Frameworks
4
+ {
5
+ name: "nextjs",
6
+ category: "framework",
7
+ configPattern: /^next\.config\./,
8
+ importPattern: /\bfrom\s+['"]next[\/'"]|\brequire\(\s*['"]next['"]\)/,
9
+ configConfidence: "high",
10
+ importConfidence: "medium",
11
+ },
12
+ {
13
+ name: "react",
14
+ category: "framework",
15
+ importPattern: /\bfrom\s+['"]react['"]|\brequire\(\s*['"]react['"]\)/,
16
+ configConfidence: "high",
17
+ importConfidence: "medium",
18
+ },
19
+ {
20
+ name: "express",
21
+ category: "framework",
22
+ importPattern: /\bfrom\s+['"]express['"]|\brequire\(\s*['"]express['"]\)/,
23
+ configConfidence: "high",
24
+ importConfidence: "medium",
25
+ },
26
+ {
27
+ name: "fastify",
28
+ category: "framework",
29
+ importPattern: /\bfrom\s+['"]fastify['"]|\brequire\(\s*['"]fastify['"]\)/,
30
+ configConfidence: "high",
31
+ importConfidence: "medium",
32
+ },
33
+ {
34
+ name: "nestjs",
35
+ category: "framework",
36
+ importPattern: /\bfrom\s+['"]@nestjs\/|\brequire\(\s*['"]@nestjs\//,
37
+ configConfidence: "high",
38
+ importConfidence: "medium",
39
+ },
40
+ {
41
+ name: "hono",
42
+ category: "framework",
43
+ importPattern: /\bfrom\s+['"]hono['"]|\brequire\(\s*['"]hono['"]\)/,
44
+ configConfidence: "high",
45
+ importConfidence: "medium",
46
+ },
47
+ {
48
+ name: "elysia",
49
+ category: "framework",
50
+ importPattern: /\bfrom\s+['"]elysia['"]|\brequire\(\s*['"]elysia['"]\)/,
51
+ configConfidence: "high",
52
+ importConfidence: "medium",
53
+ },
54
+ {
55
+ name: "vite",
56
+ category: "framework",
57
+ configPattern: /^vite\.config\./,
58
+ importPattern: /\bfrom\s+['"]vite['"]|\brequire\(\s*['"]vite['"]\)/,
59
+ configConfidence: "high",
60
+ importConfidence: "medium",
61
+ },
62
+ // Runtimes
63
+ {
64
+ name: "nodejs",
65
+ category: "runtime",
66
+ importPattern: /\bfrom\s+['"]node:(?:fs|http|path|crypto|stream)['"]|\bfrom\s+['"](?:fs|http|net|dgram)['"]|\brequire\(\s*['"](?:fs|http|path|crypto)['"]\)/,
67
+ configConfidence: "high",
68
+ importConfidence: "medium",
69
+ },
70
+ {
71
+ name: "bun",
72
+ category: "runtime",
73
+ importPattern: /\bBun\.serve\b|\bBun\.file\b|\bBun\.write\b/,
74
+ configConfidence: "high",
75
+ importConfidence: "medium",
76
+ },
77
+ {
78
+ name: "deno",
79
+ category: "runtime",
80
+ importPattern: /\bDeno\.serve\b|\bDeno\.readFile\b|\bDeno\.env\b/,
81
+ configConfidence: "high",
82
+ importConfidence: "medium",
83
+ },
84
+ ];
85
+ const CONFIG_NAME_PATTERN = /^(next|vite)\.config\./;
86
+ function shouldProcess(file) {
87
+ if (EXTENDED_EXTENSIONS.has(file.extension))
88
+ return true;
89
+ const basename = file.relativePath.split("/").pop() ?? "";
90
+ return CONFIG_NAME_PATTERN.test(basename);
91
+ }
92
+ function findImportEvidence(lines, pattern, filePath) {
93
+ const evidence = [];
94
+ for (let i = 0; i < lines.length; i++) {
95
+ const line = lines[i];
96
+ if (!line)
97
+ continue;
98
+ if (pattern.test(line)) {
99
+ evidence.push({ file: filePath, line: i + 1, snippet: line.trim().slice(0, 120) });
100
+ if (evidence.length >= 3)
101
+ break;
102
+ }
103
+ }
104
+ return evidence;
105
+ }
106
+ export function detectFrameworks(ctx) {
107
+ const { file } = ctx;
108
+ if (!shouldProcess(file))
109
+ return [];
110
+ const basename = file.relativePath.split("/").pop() ?? "";
111
+ const seen = new Set();
112
+ const signals = [];
113
+ for (const rule of rules) {
114
+ if (rule.configPattern?.test(basename) && !seen.has(rule.name)) {
115
+ seen.add(rule.name);
116
+ signals.push({
117
+ id: `${rule.category}-${rule.name}`,
118
+ name: rule.name,
119
+ category: rule.category,
120
+ confidence: rule.configConfidence,
121
+ evidence: [
122
+ { file: file.relativePath, line: 1, snippet: `Config file detected: ${basename}` },
123
+ ],
124
+ });
125
+ }
126
+ if (!rule.importPattern)
127
+ continue;
128
+ const evidence = findImportEvidence(ctx.lines, rule.importPattern, file.relativePath);
129
+ if (evidence.length > 0 && !seen.has(rule.name)) {
130
+ seen.add(rule.name);
131
+ signals.push({
132
+ id: `${rule.category}-${rule.name}`,
133
+ name: rule.name,
134
+ category: rule.category,
135
+ confidence: rule.importConfidence,
136
+ evidence,
137
+ });
138
+ }
139
+ }
140
+ return signals;
141
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Signal detector registry.
3
+ *
4
+ * Runs all registered detectors against a file and returns combined signals.
5
+ */
6
+ import type { DetectedSignal, DetectorContext } from "../../evidence/types";
7
+ export declare function runAllDetectors(ctx: DetectorContext): DetectedSignal[];
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAkB,MAAM,sBAAsB,CAAC;AAuB5F,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CAUtE"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Signal detector registry.
3
+ *
4
+ * Runs all registered detectors against a file and returns combined signals.
5
+ */
6
+ import { detectAiFrameworkSignals } from "./ai-framework-detector";
7
+ import { detectAiProviderSignals } from "./ai-provider-detector";
8
+ import { detectCompliance } from "./compliance-detector";
9
+ import { detectConfig } from "./config-detector";
10
+ import { detectFrameworks } from "./framework-detector";
11
+ import { detectLocalInferenceSignals } from "./local-inference-detector";
12
+ import { detectMarkdown } from "./markdown-detector";
13
+ import { detectPackageJsonSignals } from "./package-json-detector";
14
+ import { detectRagSignals } from "./rag-detector";
15
+ const ALL_DETECTORS = [
16
+ detectPackageJsonSignals,
17
+ detectAiProviderSignals,
18
+ detectAiFrameworkSignals,
19
+ detectLocalInferenceSignals,
20
+ detectRagSignals,
21
+ detectFrameworks,
22
+ detectCompliance,
23
+ detectConfig,
24
+ detectMarkdown,
25
+ ];
26
+ export function runAllDetectors(ctx) {
27
+ const signals = [];
28
+ for (const detector of ALL_DETECTORS) {
29
+ try {
30
+ signals.push(...detector(ctx));
31
+ }
32
+ catch {
33
+ // Individual detector failure should not break the scan
34
+ }
35
+ }
36
+ return signals;
37
+ }
@@ -0,0 +1,3 @@
1
+ import type { DetectedSignal, DetectorContext } from "../../evidence/types";
2
+ export declare function detectLocalInferenceSignals(ctx: DetectorContext): DetectedSignal[];
3
+ //# sourceMappingURL=local-inference-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-inference-detector.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/local-inference-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAoG9B,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CAkBlF"}
@@ -0,0 +1,93 @@
1
+ import { EXTENDED_EXTENSIONS } from "./shared";
2
+ const RULES = [
3
+ // Ollama API URL
4
+ {
5
+ id: "local-inference-ollama-api",
6
+ name: "Ollama API (localhost:11434)",
7
+ pattern: /localhost:11434/,
8
+ confidence: "high",
9
+ },
10
+ // Ollama imports
11
+ {
12
+ id: "local-inference-ollama-import",
13
+ name: "Ollama SDK import",
14
+ pattern: /(?:from\s+['"](?:ollama|@ollama\/ollama)['"]|require\s*\(\s*['"](?:ollama|@ollama\/ollama)['"])/,
15
+ confidence: "medium",
16
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
17
+ },
18
+ // Transformers.js browser usage (pipeline / env)
19
+ {
20
+ id: "local-inference-transformers-browser",
21
+ name: "Transformers.js (browser inference)",
22
+ pattern: /(?:from\s+['"]@xenova\/transformers['"]|\.pipeline\s*\(|env\.allowLocalModels)/,
23
+ confidence: "medium",
24
+ extensions: [".ts", ".tsx", ".js", ".jsx"],
25
+ },
26
+ // ONNX Runtime
27
+ {
28
+ id: "local-inference-onnx",
29
+ name: "ONNX Runtime",
30
+ pattern: /(?:from\s+['"]onnxruntime[^'"]*['"]|require\s*\(\s*['"]onnxruntime[^'"]*['"]|onnxruntime)/,
31
+ confidence: "medium",
32
+ },
33
+ // llama.cpp references
34
+ {
35
+ id: "local-inference-llamacpp",
36
+ name: "llama.cpp",
37
+ pattern: /llama\.cpp|llama-cpp|llamacpp/,
38
+ confidence: "medium",
39
+ },
40
+ // Docker Compose ollama service
41
+ {
42
+ id: "local-inference-ollama-docker",
43
+ name: "Ollama Docker service",
44
+ pattern: /ollama\/ollama|image:\s*ollama/,
45
+ confidence: "high",
46
+ extensions: [".yaml", ".yml", ".json"],
47
+ },
48
+ ];
49
+ // ---------------------------------------------------------------------------
50
+ // Detector
51
+ // ---------------------------------------------------------------------------
52
+ function matchRuleToLine(rule, line, lineNum, filePath, signalMap) {
53
+ if (!rule.pattern.test(line))
54
+ return;
55
+ const evidence = {
56
+ file: filePath,
57
+ line: lineNum,
58
+ snippet: line.trim().slice(0, 200),
59
+ };
60
+ const existing = signalMap.get(rule.id);
61
+ if (existing) {
62
+ existing.evidence.push(evidence);
63
+ if (rule.confidence === "high")
64
+ existing.confidence = "high";
65
+ }
66
+ else {
67
+ signalMap.set(rule.id, {
68
+ id: rule.id,
69
+ name: rule.name,
70
+ category: "local-inference",
71
+ confidence: rule.confidence,
72
+ evidence: [evidence],
73
+ });
74
+ }
75
+ }
76
+ export function detectLocalInferenceSignals(ctx) {
77
+ const { file } = ctx;
78
+ if (!EXTENDED_EXTENSIONS.has(file.extension))
79
+ return [];
80
+ const lines = ctx.lines;
81
+ const signalMap = new Map();
82
+ for (let i = 0; i < lines.length; i++) {
83
+ const line = lines[i];
84
+ if (!line)
85
+ continue;
86
+ for (const rule of RULES) {
87
+ if (rule.extensions && !rule.extensions.includes(file.extension))
88
+ continue;
89
+ matchRuleToLine(rule, line, i + 1, file.relativePath, signalMap);
90
+ }
91
+ }
92
+ return Array.from(signalMap.values());
93
+ }
@@ -0,0 +1,3 @@
1
+ import type { DetectedSignal, DetectorContext } from "../../evidence/types";
2
+ export declare function detectMarkdown(ctx: DetectorContext): DetectedSignal[];
3
+ //# sourceMappingURL=markdown-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-detector.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/markdown-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAGhB,MAAM,sBAAsB,CAAC;AA6I9B,wBAAgB,cAAc,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CA4BrE"}