@aigrc/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +226 -0
- package/dist/index.d.ts +226 -0
- package/dist/index.js +2337 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2264 -0
- package/dist/index.mjs.map +1 -0
- package/dist/schemas/index.d.mts +2332 -0
- package/dist/schemas/index.d.ts +2332 -0
- package/dist/schemas/index.js +213 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/index.mjs +176 -0
- package/dist/schemas/index.mjs.map +1 -0
- package/package.json +69 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2264 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __esm = (fn, res) => function __init() {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
};
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
|
|
22
|
+
// src/detection/patterns/registry.ts
|
|
23
|
+
var registry_exports = {};
|
|
24
|
+
__export(registry_exports, {
|
|
25
|
+
clearRegistry: () => clearRegistry,
|
|
26
|
+
createImplication: () => createImplication,
|
|
27
|
+
getAllPatterns: () => getAllPatterns,
|
|
28
|
+
getPattern: () => getPattern,
|
|
29
|
+
getPatternsByCategory: () => getPatternsByCategory,
|
|
30
|
+
getPatternsByLanguage: () => getPatternsByLanguage,
|
|
31
|
+
isRegistryInitialized: () => isRegistryInitialized,
|
|
32
|
+
registerPattern: () => registerPattern
|
|
33
|
+
});
|
|
34
|
+
function registerPattern(pattern) {
|
|
35
|
+
if (registry.has(pattern.id)) {
|
|
36
|
+
throw new Error(`Pattern with ID "${pattern.id}" already registered`);
|
|
37
|
+
}
|
|
38
|
+
registry.set(pattern.id, pattern);
|
|
39
|
+
}
|
|
40
|
+
function getPattern(id) {
|
|
41
|
+
return registry.get(id);
|
|
42
|
+
}
|
|
43
|
+
function getAllPatterns() {
|
|
44
|
+
return Array.from(registry.values());
|
|
45
|
+
}
|
|
46
|
+
function getPatternsByCategory(category) {
|
|
47
|
+
return getAllPatterns().filter((p) => p.category === category);
|
|
48
|
+
}
|
|
49
|
+
function getPatternsByLanguage(language) {
|
|
50
|
+
return getAllPatterns().filter((p) => p.language === language || p.language === "any");
|
|
51
|
+
}
|
|
52
|
+
function clearRegistry() {
|
|
53
|
+
registry.clear();
|
|
54
|
+
}
|
|
55
|
+
function isRegistryInitialized() {
|
|
56
|
+
return registry.size > 0;
|
|
57
|
+
}
|
|
58
|
+
function createImplication(factor, value, reason) {
|
|
59
|
+
return { factor, value, reason };
|
|
60
|
+
}
|
|
61
|
+
var registry;
|
|
62
|
+
var init_registry = __esm({
|
|
63
|
+
"src/detection/patterns/registry.ts"() {
|
|
64
|
+
"use strict";
|
|
65
|
+
registry = /* @__PURE__ */ new Map();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// src/detection/patterns/python.ts
|
|
70
|
+
var python_exports = {};
|
|
71
|
+
__export(python_exports, {
|
|
72
|
+
pythonPatterns: () => pythonPatterns,
|
|
73
|
+
registerPythonPatterns: () => registerPythonPatterns
|
|
74
|
+
});
|
|
75
|
+
function registerPythonPatterns() {
|
|
76
|
+
pythonPatterns.forEach(registerPattern);
|
|
77
|
+
}
|
|
78
|
+
var pythonPatterns;
|
|
79
|
+
var init_python = __esm({
|
|
80
|
+
"src/detection/patterns/python.ts"() {
|
|
81
|
+
"use strict";
|
|
82
|
+
init_registry();
|
|
83
|
+
pythonPatterns = [
|
|
84
|
+
// ─────────────────────────────────────────────────────────────────
|
|
85
|
+
// ML FRAMEWORKS
|
|
86
|
+
// ─────────────────────────────────────────────────────────────────
|
|
87
|
+
{
|
|
88
|
+
id: "pytorch",
|
|
89
|
+
name: "PyTorch",
|
|
90
|
+
category: "ml_framework",
|
|
91
|
+
language: "python",
|
|
92
|
+
patterns: [
|
|
93
|
+
{ type: "import", pattern: "import torch", confidence: "high" },
|
|
94
|
+
{ type: "import", pattern: "from torch", confidence: "high" },
|
|
95
|
+
{ type: "regex", pattern: "torch\\.nn\\.", confidence: "medium" },
|
|
96
|
+
{ type: "regex", pattern: "torch\\.tensor", confidence: "medium" },
|
|
97
|
+
{ type: "regex", pattern: "torch\\.cuda", confidence: "medium" }
|
|
98
|
+
],
|
|
99
|
+
implies: []
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: "tensorflow",
|
|
103
|
+
name: "TensorFlow",
|
|
104
|
+
category: "ml_framework",
|
|
105
|
+
language: "python",
|
|
106
|
+
patterns: [
|
|
107
|
+
{ type: "import", pattern: "import tensorflow", confidence: "high" },
|
|
108
|
+
{ type: "import", pattern: "from tensorflow", confidence: "high" },
|
|
109
|
+
{ type: "regex", pattern: "tf\\.keras", confidence: "medium" },
|
|
110
|
+
{ type: "regex", pattern: "tf\\.data", confidence: "medium" }
|
|
111
|
+
],
|
|
112
|
+
implies: []
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: "keras",
|
|
116
|
+
name: "Keras",
|
|
117
|
+
category: "ml_framework",
|
|
118
|
+
language: "python",
|
|
119
|
+
patterns: [
|
|
120
|
+
{ type: "import", pattern: "import keras", confidence: "high" },
|
|
121
|
+
{ type: "import", pattern: "from keras", confidence: "high" },
|
|
122
|
+
{ type: "regex", pattern: "Sequential\\(", confidence: "medium" }
|
|
123
|
+
],
|
|
124
|
+
implies: []
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
id: "scikit-learn",
|
|
128
|
+
name: "Scikit-learn",
|
|
129
|
+
category: "ml_framework",
|
|
130
|
+
language: "python",
|
|
131
|
+
patterns: [
|
|
132
|
+
{ type: "import", pattern: "import sklearn", confidence: "high" },
|
|
133
|
+
{ type: "import", pattern: "from sklearn", confidence: "high" },
|
|
134
|
+
{ type: "regex", pattern: "\\.fit\\(", confidence: "low" },
|
|
135
|
+
{ type: "regex", pattern: "\\.predict\\(", confidence: "low" }
|
|
136
|
+
],
|
|
137
|
+
implies: []
|
|
138
|
+
},
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────
|
|
140
|
+
// LLM PROVIDERS
|
|
141
|
+
// ─────────────────────────────────────────────────────────────────
|
|
142
|
+
{
|
|
143
|
+
id: "openai-python",
|
|
144
|
+
name: "OpenAI Python SDK",
|
|
145
|
+
category: "llm_provider",
|
|
146
|
+
language: "python",
|
|
147
|
+
patterns: [
|
|
148
|
+
{ type: "import", pattern: "from openai", confidence: "high" },
|
|
149
|
+
{ type: "import", pattern: "import openai", confidence: "high" },
|
|
150
|
+
{ type: "regex", pattern: "OpenAI\\s*\\(", confidence: "high" },
|
|
151
|
+
{ type: "regex", pattern: "client\\.chat\\.completions", confidence: "medium" },
|
|
152
|
+
{ type: "regex", pattern: "ChatCompletion\\.create", confidence: "medium" }
|
|
153
|
+
],
|
|
154
|
+
implies: [
|
|
155
|
+
createImplication("externalDataAccess", true, "OpenAI SDK calls external API")
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "anthropic-python",
|
|
160
|
+
name: "Anthropic Python SDK",
|
|
161
|
+
category: "llm_provider",
|
|
162
|
+
language: "python",
|
|
163
|
+
patterns: [
|
|
164
|
+
{ type: "import", pattern: "from anthropic", confidence: "high" },
|
|
165
|
+
{ type: "import", pattern: "import anthropic", confidence: "high" },
|
|
166
|
+
{ type: "regex", pattern: "Anthropic\\s*\\(", confidence: "high" },
|
|
167
|
+
{ type: "regex", pattern: "client\\.messages\\.create", confidence: "medium" }
|
|
168
|
+
],
|
|
169
|
+
implies: [
|
|
170
|
+
createImplication("externalDataAccess", true, "Anthropic SDK calls external API")
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
id: "cohere-python",
|
|
175
|
+
name: "Cohere Python SDK",
|
|
176
|
+
category: "llm_provider",
|
|
177
|
+
language: "python",
|
|
178
|
+
patterns: [
|
|
179
|
+
{ type: "import", pattern: "import cohere", confidence: "high" },
|
|
180
|
+
{ type: "import", pattern: "from cohere", confidence: "high" },
|
|
181
|
+
{ type: "regex", pattern: "cohere\\.Client", confidence: "high" }
|
|
182
|
+
],
|
|
183
|
+
implies: [
|
|
184
|
+
createImplication("externalDataAccess", true, "Cohere SDK calls external API")
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "google-genai",
|
|
189
|
+
name: "Google Generative AI",
|
|
190
|
+
category: "llm_provider",
|
|
191
|
+
language: "python",
|
|
192
|
+
patterns: [
|
|
193
|
+
{ type: "import", pattern: "import google.generativeai", confidence: "high" },
|
|
194
|
+
{ type: "import", pattern: "from google.generativeai", confidence: "high" },
|
|
195
|
+
{ type: "regex", pattern: "genai\\.GenerativeModel", confidence: "high" }
|
|
196
|
+
],
|
|
197
|
+
implies: [
|
|
198
|
+
createImplication("externalDataAccess", true, "Google GenAI SDK calls external API")
|
|
199
|
+
]
|
|
200
|
+
},
|
|
201
|
+
// ─────────────────────────────────────────────────────────────────
|
|
202
|
+
// FRAMEWORKS
|
|
203
|
+
// ─────────────────────────────────────────────────────────────────
|
|
204
|
+
{
|
|
205
|
+
id: "huggingface-transformers",
|
|
206
|
+
name: "Hugging Face Transformers",
|
|
207
|
+
category: "framework",
|
|
208
|
+
language: "python",
|
|
209
|
+
patterns: [
|
|
210
|
+
{ type: "import", pattern: "from transformers", confidence: "high" },
|
|
211
|
+
{ type: "import", pattern: "import transformers", confidence: "high" },
|
|
212
|
+
{ type: "regex", pattern: "AutoModel\\.from_pretrained", confidence: "high" },
|
|
213
|
+
{ type: "regex", pattern: "AutoTokenizer", confidence: "medium" },
|
|
214
|
+
{ type: "regex", pattern: "pipeline\\s*\\(", confidence: "medium" }
|
|
215
|
+
],
|
|
216
|
+
implies: [
|
|
217
|
+
createImplication("externalDataAccess", true, "Hugging Face typically loads models from Hub")
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: "langchain-python",
|
|
222
|
+
name: "LangChain",
|
|
223
|
+
category: "framework",
|
|
224
|
+
language: "python",
|
|
225
|
+
patterns: [
|
|
226
|
+
{ type: "import", pattern: "from langchain", confidence: "high" },
|
|
227
|
+
{ type: "import", pattern: "import langchain", confidence: "high" },
|
|
228
|
+
{ type: "import", pattern: "from langchain_core", confidence: "high" },
|
|
229
|
+
{ type: "import", pattern: "from langchain_openai", confidence: "high" },
|
|
230
|
+
{ type: "import", pattern: "from langchain_anthropic", confidence: "high" },
|
|
231
|
+
{ type: "import", pattern: "from langchain_community", confidence: "high" },
|
|
232
|
+
{ type: "regex", pattern: "LLMChain", confidence: "high" },
|
|
233
|
+
{ type: "regex", pattern: "ChatPromptTemplate", confidence: "medium" },
|
|
234
|
+
{ type: "regex", pattern: "\\.invoke\\s*\\(", confidence: "medium" }
|
|
235
|
+
],
|
|
236
|
+
implies: [
|
|
237
|
+
createImplication("toolExecution", true, "LangChain supports tool/function calling"),
|
|
238
|
+
createImplication("externalDataAccess", true, "LangChain chains often access external data")
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: "llamaindex",
|
|
243
|
+
name: "LlamaIndex",
|
|
244
|
+
category: "framework",
|
|
245
|
+
language: "python",
|
|
246
|
+
patterns: [
|
|
247
|
+
{ type: "import", pattern: "from llama_index", confidence: "high" },
|
|
248
|
+
{ type: "import", pattern: "import llama_index", confidence: "high" },
|
|
249
|
+
{ type: "regex", pattern: "VectorStoreIndex", confidence: "medium" },
|
|
250
|
+
{ type: "regex", pattern: "ServiceContext", confidence: "medium" },
|
|
251
|
+
{ type: "regex", pattern: "SimpleDirectoryReader", confidence: "medium" }
|
|
252
|
+
],
|
|
253
|
+
implies: [
|
|
254
|
+
createImplication("externalDataAccess", true, "LlamaIndex typically ingests external data")
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
// ─────────────────────────────────────────────────────────────────
|
|
258
|
+
// AGENT FRAMEWORKS
|
|
259
|
+
// ─────────────────────────────────────────────────────────────────
|
|
260
|
+
{
|
|
261
|
+
id: "crewai",
|
|
262
|
+
name: "CrewAI",
|
|
263
|
+
category: "agent_framework",
|
|
264
|
+
language: "python",
|
|
265
|
+
patterns: [
|
|
266
|
+
{ type: "import", pattern: "from crewai", confidence: "high" },
|
|
267
|
+
{ type: "import", pattern: "import crewai", confidence: "high" },
|
|
268
|
+
{ type: "decorator", pattern: "@agent", confidence: "high" },
|
|
269
|
+
{ type: "decorator", pattern: "@task", confidence: "high" },
|
|
270
|
+
{ type: "decorator", pattern: "@crew", confidence: "high" },
|
|
271
|
+
{ type: "regex", pattern: "Crew\\s*\\(", confidence: "high" },
|
|
272
|
+
{ type: "regex", pattern: "Agent\\s*\\(", confidence: "medium" }
|
|
273
|
+
],
|
|
274
|
+
implies: [
|
|
275
|
+
createImplication("autonomousDecisions", true, "CrewAI enables autonomous agent orchestration"),
|
|
276
|
+
createImplication("toolExecution", true, "CrewAI agents execute tools autonomously")
|
|
277
|
+
]
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
id: "autogen",
|
|
281
|
+
name: "AutoGen",
|
|
282
|
+
category: "agent_framework",
|
|
283
|
+
language: "python",
|
|
284
|
+
patterns: [
|
|
285
|
+
{ type: "import", pattern: "from autogen", confidence: "high" },
|
|
286
|
+
{ type: "import", pattern: "import autogen", confidence: "high" },
|
|
287
|
+
{ type: "regex", pattern: "AssistantAgent", confidence: "high" },
|
|
288
|
+
{ type: "regex", pattern: "UserProxyAgent", confidence: "high" },
|
|
289
|
+
{ type: "regex", pattern: "GroupChat", confidence: "medium" }
|
|
290
|
+
],
|
|
291
|
+
implies: [
|
|
292
|
+
createImplication("autonomousDecisions", true, "AutoGen enables multi-agent autonomous systems"),
|
|
293
|
+
createImplication("toolExecution", true, "AutoGen agents can execute code and tools")
|
|
294
|
+
]
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
id: "langgraph",
|
|
298
|
+
name: "LangGraph",
|
|
299
|
+
category: "agent_framework",
|
|
300
|
+
language: "python",
|
|
301
|
+
patterns: [
|
|
302
|
+
{ type: "import", pattern: "from langgraph", confidence: "high" },
|
|
303
|
+
{ type: "import", pattern: "import langgraph", confidence: "high" },
|
|
304
|
+
{ type: "regex", pattern: "StateGraph", confidence: "high" },
|
|
305
|
+
{ type: "regex", pattern: "add_node", confidence: "medium" },
|
|
306
|
+
{ type: "regex", pattern: "add_edge", confidence: "medium" }
|
|
307
|
+
],
|
|
308
|
+
implies: [
|
|
309
|
+
createImplication("autonomousDecisions", true, "LangGraph enables stateful agent workflows"),
|
|
310
|
+
createImplication("toolExecution", true, "LangGraph agents execute tools in graph nodes")
|
|
311
|
+
]
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
id: "agency-swarm",
|
|
315
|
+
name: "Agency Swarm",
|
|
316
|
+
category: "agent_framework",
|
|
317
|
+
language: "python",
|
|
318
|
+
patterns: [
|
|
319
|
+
{ type: "import", pattern: "from agency_swarm", confidence: "high" },
|
|
320
|
+
{ type: "regex", pattern: "Agency\\s*\\(", confidence: "high" }
|
|
321
|
+
],
|
|
322
|
+
implies: [
|
|
323
|
+
createImplication("autonomousDecisions", true, "Agency Swarm enables multi-agent systems"),
|
|
324
|
+
createImplication("toolExecution", true, "Agency Swarm agents execute tools")
|
|
325
|
+
]
|
|
326
|
+
},
|
|
327
|
+
// ─────────────────────────────────────────────────────────────────
|
|
328
|
+
// ML OPS
|
|
329
|
+
// ─────────────────────────────────────────────────────────────────
|
|
330
|
+
{
|
|
331
|
+
id: "mlflow",
|
|
332
|
+
name: "MLflow",
|
|
333
|
+
category: "ml_ops",
|
|
334
|
+
language: "python",
|
|
335
|
+
patterns: [
|
|
336
|
+
{ type: "import", pattern: "import mlflow", confidence: "high" },
|
|
337
|
+
{ type: "import", pattern: "from mlflow", confidence: "high" },
|
|
338
|
+
{ type: "regex", pattern: "mlflow\\.log_", confidence: "medium" },
|
|
339
|
+
{ type: "regex", pattern: "mlflow\\.start_run", confidence: "medium" }
|
|
340
|
+
],
|
|
341
|
+
implies: []
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "wandb",
|
|
345
|
+
name: "Weights & Biases",
|
|
346
|
+
category: "ml_ops",
|
|
347
|
+
language: "python",
|
|
348
|
+
patterns: [
|
|
349
|
+
{ type: "import", pattern: "import wandb", confidence: "high" },
|
|
350
|
+
{ type: "import", pattern: "from wandb", confidence: "high" },
|
|
351
|
+
{ type: "regex", pattern: "wandb\\.init", confidence: "medium" }
|
|
352
|
+
],
|
|
353
|
+
implies: [
|
|
354
|
+
createImplication("externalDataAccess", true, "W&B syncs to external service")
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
];
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// src/detection/patterns/javascript.ts
|
|
362
|
+
var javascript_exports = {};
|
|
363
|
+
__export(javascript_exports, {
|
|
364
|
+
javascriptPatterns: () => javascriptPatterns,
|
|
365
|
+
registerJavaScriptPatterns: () => registerJavaScriptPatterns
|
|
366
|
+
});
|
|
367
|
+
function registerJavaScriptPatterns() {
|
|
368
|
+
javascriptPatterns.forEach(registerPattern);
|
|
369
|
+
}
|
|
370
|
+
var javascriptPatterns;
|
|
371
|
+
var init_javascript = __esm({
|
|
372
|
+
"src/detection/patterns/javascript.ts"() {
|
|
373
|
+
"use strict";
|
|
374
|
+
init_registry();
|
|
375
|
+
javascriptPatterns = [
|
|
376
|
+
// ─────────────────────────────────────────────────────────────────
|
|
377
|
+
// LLM PROVIDERS
|
|
378
|
+
// ─────────────────────────────────────────────────────────────────
|
|
379
|
+
{
|
|
380
|
+
id: "openai-js",
|
|
381
|
+
name: "OpenAI JavaScript SDK",
|
|
382
|
+
category: "llm_provider",
|
|
383
|
+
language: "javascript",
|
|
384
|
+
patterns: [
|
|
385
|
+
{ type: "import", pattern: 'from "openai"', confidence: "high" },
|
|
386
|
+
{ type: "import", pattern: "from 'openai'", confidence: "high" },
|
|
387
|
+
{ type: "regex", pattern: "new OpenAI\\s*\\(", confidence: "high" },
|
|
388
|
+
{ type: "regex", pattern: "openai\\.chat\\.completions", confidence: "medium" }
|
|
389
|
+
],
|
|
390
|
+
implies: [
|
|
391
|
+
createImplication("externalDataAccess", true, "OpenAI SDK calls external API")
|
|
392
|
+
]
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
id: "anthropic-js",
|
|
396
|
+
name: "Anthropic JavaScript SDK",
|
|
397
|
+
category: "llm_provider",
|
|
398
|
+
language: "javascript",
|
|
399
|
+
patterns: [
|
|
400
|
+
{ type: "import", pattern: 'from "@anthropic-ai/sdk"', confidence: "high" },
|
|
401
|
+
{ type: "import", pattern: "from '@anthropic-ai/sdk'", confidence: "high" },
|
|
402
|
+
{ type: "regex", pattern: "new Anthropic\\s*\\(", confidence: "high" },
|
|
403
|
+
{ type: "regex", pattern: "\\.messages\\.create", confidence: "medium" }
|
|
404
|
+
],
|
|
405
|
+
implies: [
|
|
406
|
+
createImplication("externalDataAccess", true, "Anthropic SDK calls external API")
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
id: "cohere-js",
|
|
411
|
+
name: "Cohere JavaScript SDK",
|
|
412
|
+
category: "llm_provider",
|
|
413
|
+
language: "javascript",
|
|
414
|
+
patterns: [
|
|
415
|
+
{ type: "import", pattern: 'from "cohere-ai"', confidence: "high" },
|
|
416
|
+
{ type: "import", pattern: "from 'cohere-ai'", confidence: "high" },
|
|
417
|
+
{ type: "regex", pattern: "new CohereClient", confidence: "high" }
|
|
418
|
+
],
|
|
419
|
+
implies: [
|
|
420
|
+
createImplication("externalDataAccess", true, "Cohere SDK calls external API")
|
|
421
|
+
]
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
id: "replicate-js",
|
|
425
|
+
name: "Replicate",
|
|
426
|
+
category: "llm_provider",
|
|
427
|
+
language: "javascript",
|
|
428
|
+
patterns: [
|
|
429
|
+
{ type: "import", pattern: 'from "replicate"', confidence: "high" },
|
|
430
|
+
{ type: "import", pattern: "from 'replicate'", confidence: "high" },
|
|
431
|
+
{ type: "regex", pattern: "new Replicate\\s*\\(", confidence: "high" }
|
|
432
|
+
],
|
|
433
|
+
implies: [
|
|
434
|
+
createImplication("externalDataAccess", true, "Replicate SDK calls external API")
|
|
435
|
+
]
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: "huggingface-js",
|
|
439
|
+
name: "Hugging Face Inference",
|
|
440
|
+
category: "llm_provider",
|
|
441
|
+
language: "javascript",
|
|
442
|
+
patterns: [
|
|
443
|
+
{ type: "import", pattern: 'from "@huggingface/inference"', confidence: "high" },
|
|
444
|
+
{ type: "import", pattern: "from '@huggingface/inference'", confidence: "high" },
|
|
445
|
+
{ type: "regex", pattern: "HfInference\\s*\\(", confidence: "high" }
|
|
446
|
+
],
|
|
447
|
+
implies: [
|
|
448
|
+
createImplication("externalDataAccess", true, "Hugging Face SDK calls external API")
|
|
449
|
+
]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
id: "together-js",
|
|
453
|
+
name: "Together AI",
|
|
454
|
+
category: "llm_provider",
|
|
455
|
+
language: "javascript",
|
|
456
|
+
patterns: [
|
|
457
|
+
{ type: "import", pattern: 'from "together-ai"', confidence: "high" },
|
|
458
|
+
{ type: "import", pattern: "from 'together-ai'", confidence: "high" },
|
|
459
|
+
{ type: "regex", pattern: "new Together\\s*\\(", confidence: "high" }
|
|
460
|
+
],
|
|
461
|
+
implies: [
|
|
462
|
+
createImplication("externalDataAccess", true, "Together AI SDK calls external API")
|
|
463
|
+
]
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
id: "groq-js",
|
|
467
|
+
name: "Groq SDK",
|
|
468
|
+
category: "llm_provider",
|
|
469
|
+
language: "javascript",
|
|
470
|
+
patterns: [
|
|
471
|
+
{ type: "import", pattern: 'from "groq-sdk"', confidence: "high" },
|
|
472
|
+
{ type: "import", pattern: "from 'groq-sdk'", confidence: "high" },
|
|
473
|
+
{ type: "regex", pattern: "new Groq\\s*\\(", confidence: "high" }
|
|
474
|
+
],
|
|
475
|
+
implies: [
|
|
476
|
+
createImplication("externalDataAccess", true, "Groq SDK calls external API")
|
|
477
|
+
]
|
|
478
|
+
},
|
|
479
|
+
// ─────────────────────────────────────────────────────────────────
|
|
480
|
+
// FRAMEWORKS
|
|
481
|
+
// ─────────────────────────────────────────────────────────────────
|
|
482
|
+
{
|
|
483
|
+
id: "langchain-js",
|
|
484
|
+
name: "LangChain.js",
|
|
485
|
+
category: "framework",
|
|
486
|
+
language: "javascript",
|
|
487
|
+
patterns: [
|
|
488
|
+
{ type: "import", pattern: 'from "langchain"', confidence: "high" },
|
|
489
|
+
{ type: "import", pattern: "from 'langchain'", confidence: "high" },
|
|
490
|
+
{ type: "import", pattern: 'from "@langchain/core"', confidence: "high" },
|
|
491
|
+
{ type: "import", pattern: 'from "@langchain/openai"', confidence: "high" },
|
|
492
|
+
{ type: "import", pattern: 'from "@langchain/anthropic"', confidence: "high" },
|
|
493
|
+
{ type: "import", pattern: 'from "@langchain/community"', confidence: "high" },
|
|
494
|
+
{ type: "regex", pattern: "new ChatOpenAI", confidence: "medium" },
|
|
495
|
+
{ type: "regex", pattern: "ChatPromptTemplate", confidence: "medium" },
|
|
496
|
+
{ type: "regex", pattern: "\\.invoke\\s*\\(", confidence: "low" }
|
|
497
|
+
],
|
|
498
|
+
implies: [
|
|
499
|
+
createImplication("toolExecution", true, "LangChain.js supports tool calling"),
|
|
500
|
+
createImplication("externalDataAccess", true, "LangChain.js chains access external data")
|
|
501
|
+
]
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: "vercel-ai-sdk",
|
|
505
|
+
name: "Vercel AI SDK",
|
|
506
|
+
category: "framework",
|
|
507
|
+
language: "javascript",
|
|
508
|
+
patterns: [
|
|
509
|
+
{ type: "import", pattern: 'from "ai"', confidence: "medium" },
|
|
510
|
+
{ type: "import", pattern: "from 'ai'", confidence: "medium" },
|
|
511
|
+
{ type: "import", pattern: 'from "ai/react"', confidence: "high" },
|
|
512
|
+
{ type: "import", pattern: 'from "@ai-sdk/openai"', confidence: "high" },
|
|
513
|
+
{ type: "import", pattern: 'from "@ai-sdk/anthropic"', confidence: "high" },
|
|
514
|
+
{ type: "regex", pattern: "generateText\\s*\\(", confidence: "high" },
|
|
515
|
+
{ type: "regex", pattern: "streamText\\s*\\(", confidence: "high" },
|
|
516
|
+
{ type: "regex", pattern: "useChat\\s*\\(", confidence: "high" },
|
|
517
|
+
{ type: "regex", pattern: "useCompletion\\s*\\(", confidence: "high" }
|
|
518
|
+
],
|
|
519
|
+
implies: [
|
|
520
|
+
createImplication("customerFacing", true, "Vercel AI SDK typically used in user-facing apps"),
|
|
521
|
+
createImplication("externalDataAccess", true, "Vercel AI SDK calls LLM providers")
|
|
522
|
+
]
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
id: "llamaindex-js",
|
|
526
|
+
name: "LlamaIndex.TS",
|
|
527
|
+
category: "framework",
|
|
528
|
+
language: "javascript",
|
|
529
|
+
patterns: [
|
|
530
|
+
{ type: "import", pattern: 'from "llamaindex"', confidence: "high" },
|
|
531
|
+
{ type: "import", pattern: "from 'llamaindex'", confidence: "high" },
|
|
532
|
+
{ type: "regex", pattern: "VectorStoreIndex", confidence: "medium" }
|
|
533
|
+
],
|
|
534
|
+
implies: [
|
|
535
|
+
createImplication("externalDataAccess", true, "LlamaIndex typically ingests external data")
|
|
536
|
+
]
|
|
537
|
+
},
|
|
538
|
+
// ─────────────────────────────────────────────────────────────────
|
|
539
|
+
// ML FRAMEWORKS
|
|
540
|
+
// ─────────────────────────────────────────────────────────────────
|
|
541
|
+
{
|
|
542
|
+
id: "tensorflow-js",
|
|
543
|
+
name: "TensorFlow.js",
|
|
544
|
+
category: "ml_framework",
|
|
545
|
+
language: "javascript",
|
|
546
|
+
patterns: [
|
|
547
|
+
{ type: "import", pattern: 'from "@tensorflow/tfjs"', confidence: "high" },
|
|
548
|
+
{ type: "import", pattern: "from '@tensorflow/tfjs'", confidence: "high" },
|
|
549
|
+
{ type: "import", pattern: 'from "@tensorflow/tfjs-node"', confidence: "high" },
|
|
550
|
+
{ type: "regex", pattern: "tf\\.loadLayersModel", confidence: "medium" },
|
|
551
|
+
{ type: "regex", pattern: "tf\\.sequential", confidence: "medium" }
|
|
552
|
+
],
|
|
553
|
+
implies: []
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: "onnxruntime-js",
|
|
557
|
+
name: "ONNX Runtime Web",
|
|
558
|
+
category: "ml_framework",
|
|
559
|
+
language: "javascript",
|
|
560
|
+
patterns: [
|
|
561
|
+
{ type: "import", pattern: 'from "onnxruntime-web"', confidence: "high" },
|
|
562
|
+
{ type: "import", pattern: 'from "onnxruntime-node"', confidence: "high" },
|
|
563
|
+
{ type: "regex", pattern: "InferenceSession\\.create", confidence: "high" }
|
|
564
|
+
],
|
|
565
|
+
implies: []
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
id: "transformers-js",
|
|
569
|
+
name: "Transformers.js",
|
|
570
|
+
category: "ml_framework",
|
|
571
|
+
language: "javascript",
|
|
572
|
+
patterns: [
|
|
573
|
+
{ type: "import", pattern: 'from "@xenova/transformers"', confidence: "high" },
|
|
574
|
+
{ type: "import", pattern: 'from "@huggingface/transformers"', confidence: "high" },
|
|
575
|
+
{ type: "regex", pattern: "pipeline\\s*\\(", confidence: "medium" }
|
|
576
|
+
],
|
|
577
|
+
implies: []
|
|
578
|
+
},
|
|
579
|
+
// ─────────────────────────────────────────────────────────────────
|
|
580
|
+
// AGENT FRAMEWORKS
|
|
581
|
+
// ─────────────────────────────────────────────────────────────────
|
|
582
|
+
{
|
|
583
|
+
id: "langgraph-js",
|
|
584
|
+
name: "LangGraph.js",
|
|
585
|
+
category: "agent_framework",
|
|
586
|
+
language: "javascript",
|
|
587
|
+
patterns: [
|
|
588
|
+
{ type: "import", pattern: 'from "@langchain/langgraph"', confidence: "high" },
|
|
589
|
+
{ type: "regex", pattern: "StateGraph", confidence: "high" },
|
|
590
|
+
{ type: "regex", pattern: "addNode", confidence: "medium" }
|
|
591
|
+
],
|
|
592
|
+
implies: [
|
|
593
|
+
createImplication("autonomousDecisions", true, "LangGraph enables stateful agent workflows"),
|
|
594
|
+
createImplication("toolExecution", true, "LangGraph agents execute tools")
|
|
595
|
+
]
|
|
596
|
+
},
|
|
597
|
+
{
|
|
598
|
+
id: "autogen-js",
|
|
599
|
+
name: "AutoGen.js",
|
|
600
|
+
category: "agent_framework",
|
|
601
|
+
language: "javascript",
|
|
602
|
+
patterns: [
|
|
603
|
+
{ type: "import", pattern: 'from "autogen"', confidence: "high" },
|
|
604
|
+
{ type: "regex", pattern: "AssistantAgent", confidence: "high" }
|
|
605
|
+
],
|
|
606
|
+
implies: [
|
|
607
|
+
createImplication("autonomousDecisions", true, "AutoGen enables multi-agent systems"),
|
|
608
|
+
createImplication("toolExecution", true, "AutoGen agents execute tools")
|
|
609
|
+
]
|
|
610
|
+
}
|
|
611
|
+
];
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// src/detection/patterns/model-files.ts
|
|
616
|
+
var model_files_exports = {};
|
|
617
|
+
__export(model_files_exports, {
|
|
618
|
+
modelFilePatterns: () => modelFilePatterns,
|
|
619
|
+
registerModelFilePatterns: () => registerModelFilePatterns
|
|
620
|
+
});
|
|
621
|
+
function registerModelFilePatterns() {
|
|
622
|
+
modelFilePatterns.forEach(registerPattern);
|
|
623
|
+
}
|
|
624
|
+
var modelFilePatterns;
|
|
625
|
+
var init_model_files = __esm({
|
|
626
|
+
"src/detection/patterns/model-files.ts"() {
|
|
627
|
+
"use strict";
|
|
628
|
+
init_registry();
|
|
629
|
+
modelFilePatterns = [
|
|
630
|
+
{
|
|
631
|
+
id: "pytorch-model",
|
|
632
|
+
name: "PyTorch Model File",
|
|
633
|
+
category: "model_file",
|
|
634
|
+
language: "any",
|
|
635
|
+
patterns: [
|
|
636
|
+
{ type: "literal", pattern: ".pt", confidence: "high" },
|
|
637
|
+
{ type: "literal", pattern: ".pth", confidence: "high" },
|
|
638
|
+
{ type: "literal", pattern: ".bin", confidence: "medium", description: "May be transformer weights" }
|
|
639
|
+
],
|
|
640
|
+
implies: []
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
id: "safetensors-model",
|
|
644
|
+
name: "SafeTensors Model File",
|
|
645
|
+
category: "model_file",
|
|
646
|
+
language: "any",
|
|
647
|
+
patterns: [
|
|
648
|
+
{ type: "literal", pattern: ".safetensors", confidence: "high" }
|
|
649
|
+
],
|
|
650
|
+
implies: []
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
id: "onnx-model",
|
|
654
|
+
name: "ONNX Model File",
|
|
655
|
+
category: "model_file",
|
|
656
|
+
language: "any",
|
|
657
|
+
patterns: [
|
|
658
|
+
{ type: "literal", pattern: ".onnx", confidence: "high" }
|
|
659
|
+
],
|
|
660
|
+
implies: []
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
id: "keras-model",
|
|
664
|
+
name: "Keras/TensorFlow Model File",
|
|
665
|
+
category: "model_file",
|
|
666
|
+
language: "any",
|
|
667
|
+
patterns: [
|
|
668
|
+
{ type: "literal", pattern: ".h5", confidence: "high" },
|
|
669
|
+
{ type: "literal", pattern: ".keras", confidence: "high" },
|
|
670
|
+
{ type: "literal", pattern: ".pb", confidence: "medium", description: "TensorFlow frozen graph" }
|
|
671
|
+
],
|
|
672
|
+
implies: []
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
id: "sklearn-model",
|
|
676
|
+
name: "Scikit-learn Model File",
|
|
677
|
+
category: "model_file",
|
|
678
|
+
language: "any",
|
|
679
|
+
patterns: [
|
|
680
|
+
{ type: "literal", pattern: ".pkl", confidence: "low", description: "Could be any pickle file" },
|
|
681
|
+
{ type: "literal", pattern: ".joblib", confidence: "high" }
|
|
682
|
+
],
|
|
683
|
+
implies: []
|
|
684
|
+
},
|
|
685
|
+
{
|
|
686
|
+
id: "model-config",
|
|
687
|
+
name: "Model Configuration File",
|
|
688
|
+
category: "model_file",
|
|
689
|
+
language: "any",
|
|
690
|
+
patterns: [
|
|
691
|
+
{ type: "regex", pattern: "config\\.json$", confidence: "low", description: "May be model config" },
|
|
692
|
+
{ type: "regex", pattern: "model\\.json$", confidence: "medium" },
|
|
693
|
+
{ type: "regex", pattern: "adapter_config\\.json$", confidence: "high", description: "LoRA adapter" },
|
|
694
|
+
{ type: "regex", pattern: "tokenizer\\.json$", confidence: "high" },
|
|
695
|
+
{ type: "regex", pattern: "tokenizer_config\\.json$", confidence: "high" },
|
|
696
|
+
{ type: "regex", pattern: "generation_config\\.json$", confidence: "high" }
|
|
697
|
+
],
|
|
698
|
+
implies: []
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
id: "gguf-model",
|
|
702
|
+
name: "GGUF Model File",
|
|
703
|
+
category: "model_file",
|
|
704
|
+
language: "any",
|
|
705
|
+
patterns: [
|
|
706
|
+
{ type: "literal", pattern: ".gguf", confidence: "high", description: "llama.cpp format" },
|
|
707
|
+
{ type: "literal", pattern: ".ggml", confidence: "high", description: "Legacy GGML format" }
|
|
708
|
+
],
|
|
709
|
+
implies: []
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
id: "mlx-model",
|
|
713
|
+
name: "MLX Model File",
|
|
714
|
+
category: "model_file",
|
|
715
|
+
language: "any",
|
|
716
|
+
patterns: [
|
|
717
|
+
{ type: "literal", pattern: ".npz", confidence: "low", description: "May be MLX weights" }
|
|
718
|
+
],
|
|
719
|
+
implies: []
|
|
720
|
+
}
|
|
721
|
+
];
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
|
|
725
|
+
// src/detection/patterns/risk-indicators.ts
|
|
726
|
+
var risk_indicators_exports = {};
|
|
727
|
+
__export(risk_indicators_exports, {
|
|
728
|
+
registerRiskIndicatorPatterns: () => registerRiskIndicatorPatterns,
|
|
729
|
+
riskIndicatorPatterns: () => riskIndicatorPatterns
|
|
730
|
+
});
|
|
731
|
+
function registerRiskIndicatorPatterns() {
|
|
732
|
+
riskIndicatorPatterns.forEach(registerPattern);
|
|
733
|
+
}
|
|
734
|
+
var riskIndicatorPatterns;
|
|
735
|
+
var init_risk_indicators = __esm({
|
|
736
|
+
"src/detection/patterns/risk-indicators.ts"() {
|
|
737
|
+
"use strict";
|
|
738
|
+
init_registry();
|
|
739
|
+
riskIndicatorPatterns = [
|
|
740
|
+
// ─────────────────────────────────────────────────────────────────
|
|
741
|
+
// AUTONOMOUS EXECUTION
|
|
742
|
+
// ─────────────────────────────────────────────────────────────────
|
|
743
|
+
{
|
|
744
|
+
id: "autonomous-execution",
|
|
745
|
+
name: "Autonomous Execution Patterns",
|
|
746
|
+
category: "framework",
|
|
747
|
+
language: "any",
|
|
748
|
+
patterns: [
|
|
749
|
+
{ type: "regex", pattern: "\\.invoke\\s*\\(", confidence: "medium", description: "Agent invocation" },
|
|
750
|
+
{ type: "regex", pattern: "\\.run\\s*\\(", confidence: "low", description: "Run method (generic)" },
|
|
751
|
+
{ type: "regex", pattern: "while\\s+True", confidence: "medium", description: "Potential agent loop (Python)" },
|
|
752
|
+
{ type: "regex", pattern: "while\\s*\\(\\s*true\\s*\\)", confidence: "medium", description: "Potential agent loop (JS)" },
|
|
753
|
+
{ type: "regex", pattern: "agent\\.execute", confidence: "high", description: "Agent execution" },
|
|
754
|
+
{ type: "regex", pattern: "AgentExecutor", confidence: "high", description: "LangChain agent executor" }
|
|
755
|
+
],
|
|
756
|
+
implies: [
|
|
757
|
+
createImplication("autonomousDecisions", true, "Pattern indicates autonomous execution capability")
|
|
758
|
+
]
|
|
759
|
+
},
|
|
760
|
+
// ─────────────────────────────────────────────────────────────────
|
|
761
|
+
// TOOL EXECUTION
|
|
762
|
+
// ─────────────────────────────────────────────────────────────────
|
|
763
|
+
{
|
|
764
|
+
id: "tool-execution",
|
|
765
|
+
name: "Tool Execution Patterns",
|
|
766
|
+
category: "framework",
|
|
767
|
+
language: "any",
|
|
768
|
+
patterns: [
|
|
769
|
+
{ type: "decorator", pattern: "@tool", confidence: "high", description: "Tool decorator" },
|
|
770
|
+
{ type: "regex", pattern: "function_calling", confidence: "high" },
|
|
771
|
+
{ type: "regex", pattern: "tools\\s*[=:]\\s*\\[", confidence: "medium" },
|
|
772
|
+
{ type: "regex", pattern: "bind_tools", confidence: "high" },
|
|
773
|
+
{ type: "regex", pattern: "create_tool", confidence: "high" },
|
|
774
|
+
{ type: "regex", pattern: "StructuredTool", confidence: "high" },
|
|
775
|
+
{ type: "regex", pattern: "BaseTool", confidence: "high" },
|
|
776
|
+
{ type: "regex", pattern: "mcp_server", confidence: "high", description: "MCP tool server" },
|
|
777
|
+
{ type: "regex", pattern: "McpServer", confidence: "high", description: "MCP server" }
|
|
778
|
+
],
|
|
779
|
+
implies: [
|
|
780
|
+
createImplication("toolExecution", true, "Pattern indicates tool execution capability")
|
|
781
|
+
]
|
|
782
|
+
},
|
|
783
|
+
// ─────────────────────────────────────────────────────────────────
|
|
784
|
+
// EXTERNAL DATA ACCESS
|
|
785
|
+
// ─────────────────────────────────────────────────────────────────
|
|
786
|
+
{
|
|
787
|
+
id: "external-data-access",
|
|
788
|
+
name: "External Data Access Patterns",
|
|
789
|
+
category: "framework",
|
|
790
|
+
language: "any",
|
|
791
|
+
patterns: [
|
|
792
|
+
{ type: "regex", pattern: "requests\\.(get|post|put|delete|patch)", confidence: "medium" },
|
|
793
|
+
{ type: "regex", pattern: "fetch\\s*\\(", confidence: "medium" },
|
|
794
|
+
{ type: "regex", pattern: "axios\\.", confidence: "medium" },
|
|
795
|
+
{ type: "regex", pattern: "httpx\\.", confidence: "medium" },
|
|
796
|
+
{ type: "regex", pattern: "aiohttp\\.", confidence: "medium" },
|
|
797
|
+
{ type: "regex", pattern: "WebBrowser", confidence: "high", description: "Web browsing capability" },
|
|
798
|
+
{ type: "regex", pattern: "Retriever", confidence: "medium", description: "RAG retrieval" },
|
|
799
|
+
{ type: "regex", pattern: "VectorStore", confidence: "medium", description: "Vector database access" }
|
|
800
|
+
],
|
|
801
|
+
implies: [
|
|
802
|
+
createImplication("externalDataAccess", true, "Pattern indicates external data access")
|
|
803
|
+
]
|
|
804
|
+
},
|
|
805
|
+
// ─────────────────────────────────────────────────────────────────
|
|
806
|
+
// DATABASE ACCESS
|
|
807
|
+
// ─────────────────────────────────────────────────────────────────
|
|
808
|
+
{
|
|
809
|
+
id: "database-access",
|
|
810
|
+
name: "Database Access Patterns",
|
|
811
|
+
category: "framework",
|
|
812
|
+
language: "any",
|
|
813
|
+
patterns: [
|
|
814
|
+
{ type: "regex", pattern: "SQLDatabase", confidence: "high" },
|
|
815
|
+
{ type: "regex", pattern: "create_sql_agent", confidence: "high" },
|
|
816
|
+
{ type: "regex", pattern: "sql_agent", confidence: "high" },
|
|
817
|
+
{ type: "regex", pattern: "MongoClient", confidence: "medium" },
|
|
818
|
+
{ type: "regex", pattern: "psycopg", confidence: "medium" },
|
|
819
|
+
{ type: "regex", pattern: "pymongo", confidence: "medium" }
|
|
820
|
+
],
|
|
821
|
+
implies: [
|
|
822
|
+
createImplication("externalDataAccess", true, "Pattern indicates database access")
|
|
823
|
+
]
|
|
824
|
+
},
|
|
825
|
+
// ─────────────────────────────────────────────────────────────────
|
|
826
|
+
// PII PROCESSING
|
|
827
|
+
// ─────────────────────────────────────────────────────────────────
|
|
828
|
+
{
|
|
829
|
+
id: "pii-processing",
|
|
830
|
+
name: "PII Processing Patterns",
|
|
831
|
+
category: "framework",
|
|
832
|
+
language: "any",
|
|
833
|
+
patterns: [
|
|
834
|
+
{ type: "regex", pattern: "email|e-mail|e_mail", confidence: "low" },
|
|
835
|
+
{ type: "regex", pattern: "phone_number|phone|telephone|mobile", confidence: "low" },
|
|
836
|
+
{ type: "regex", pattern: "ssn|social_security|social-security", confidence: "high" },
|
|
837
|
+
{ type: "regex", pattern: "password|passwd|pwd", confidence: "medium" },
|
|
838
|
+
{ type: "regex", pattern: "credit_card|creditcard|cc_number", confidence: "high" },
|
|
839
|
+
{ type: "regex", pattern: "date_of_birth|dob|birthdate", confidence: "medium" },
|
|
840
|
+
{ type: "regex", pattern: "address|street|city|zipcode|zip_code", confidence: "low" },
|
|
841
|
+
{ type: "regex", pattern: "passport|driver_license|drivers_license", confidence: "high" }
|
|
842
|
+
],
|
|
843
|
+
implies: [
|
|
844
|
+
createImplication("piiProcessing", "yes", "Pattern suggests PII handling")
|
|
845
|
+
]
|
|
846
|
+
},
|
|
847
|
+
// ─────────────────────────────────────────────────────────────────
|
|
848
|
+
// HIGH-STAKES DECISIONS
|
|
849
|
+
// ─────────────────────────────────────────────────────────────────
|
|
850
|
+
{
|
|
851
|
+
id: "high-stakes-medical",
|
|
852
|
+
name: "Medical/Healthcare Patterns",
|
|
853
|
+
category: "framework",
|
|
854
|
+
language: "any",
|
|
855
|
+
patterns: [
|
|
856
|
+
{ type: "regex", pattern: "medical|diagnosis|patient|treatment", confidence: "high" },
|
|
857
|
+
{ type: "regex", pattern: "healthcare|health_care|clinical", confidence: "high" },
|
|
858
|
+
{ type: "regex", pattern: "prescription|medication|drug", confidence: "medium" },
|
|
859
|
+
{ type: "regex", pattern: "symptom|disease|condition", confidence: "medium" }
|
|
860
|
+
],
|
|
861
|
+
implies: [
|
|
862
|
+
createImplication("highStakesDecisions", true, "Pattern indicates medical/healthcare domain")
|
|
863
|
+
]
|
|
864
|
+
},
|
|
865
|
+
{
|
|
866
|
+
id: "high-stakes-legal",
|
|
867
|
+
name: "Legal Patterns",
|
|
868
|
+
category: "framework",
|
|
869
|
+
language: "any",
|
|
870
|
+
patterns: [
|
|
871
|
+
{ type: "regex", pattern: "legal|lawsuit|attorney|lawyer", confidence: "high" },
|
|
872
|
+
{ type: "regex", pattern: "contract|agreement|terms", confidence: "low" },
|
|
873
|
+
{ type: "regex", pattern: "court|judge|verdict|sentence", confidence: "high" },
|
|
874
|
+
{ type: "regex", pattern: "compliance|regulation|regulatory", confidence: "medium" }
|
|
875
|
+
],
|
|
876
|
+
implies: [
|
|
877
|
+
createImplication("highStakesDecisions", true, "Pattern indicates legal domain")
|
|
878
|
+
]
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
id: "high-stakes-financial",
|
|
882
|
+
name: "Financial Patterns",
|
|
883
|
+
category: "framework",
|
|
884
|
+
language: "any",
|
|
885
|
+
patterns: [
|
|
886
|
+
{ type: "regex", pattern: "financial|trading|investment|loan", confidence: "high" },
|
|
887
|
+
{ type: "regex", pattern: "credit_score|creditworthiness|credit_rating", confidence: "high" },
|
|
888
|
+
{ type: "regex", pattern: "mortgage|banking|transaction", confidence: "medium" },
|
|
889
|
+
{ type: "regex", pattern: "portfolio|stock|bond|asset", confidence: "medium" }
|
|
890
|
+
],
|
|
891
|
+
implies: [
|
|
892
|
+
createImplication("highStakesDecisions", true, "Pattern indicates financial domain")
|
|
893
|
+
]
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
id: "high-stakes-hiring",
|
|
897
|
+
name: "Hiring/Employment Patterns",
|
|
898
|
+
category: "framework",
|
|
899
|
+
language: "any",
|
|
900
|
+
patterns: [
|
|
901
|
+
{ type: "regex", pattern: "hiring|recruitment|candidate|applicant", confidence: "high" },
|
|
902
|
+
{ type: "regex", pattern: "resume|cv|curriculum_vitae", confidence: "high" },
|
|
903
|
+
{ type: "regex", pattern: "interview|screening|background_check", confidence: "high" },
|
|
904
|
+
{ type: "regex", pattern: "employee|termination|performance_review", confidence: "medium" }
|
|
905
|
+
],
|
|
906
|
+
implies: [
|
|
907
|
+
createImplication("highStakesDecisions", true, "Pattern indicates hiring/employment domain")
|
|
908
|
+
]
|
|
909
|
+
},
|
|
910
|
+
// ─────────────────────────────────────────────────────────────────
|
|
911
|
+
// CUSTOMER FACING
|
|
912
|
+
// ─────────────────────────────────────────────────────────────────
|
|
913
|
+
{
|
|
914
|
+
id: "customer-facing",
|
|
915
|
+
name: "Customer-Facing Patterns",
|
|
916
|
+
category: "framework",
|
|
917
|
+
language: "any",
|
|
918
|
+
patterns: [
|
|
919
|
+
{ type: "regex", pattern: "chatbot|chat_bot|conversational", confidence: "high" },
|
|
920
|
+
{ type: "regex", pattern: "customer_service|customer_support", confidence: "high" },
|
|
921
|
+
{ type: "regex", pattern: "useChat|useCompletion", confidence: "high", description: "Vercel AI hooks" },
|
|
922
|
+
{ type: "regex", pattern: "StreamingTextResponse", confidence: "high" },
|
|
923
|
+
{ type: "regex", pattern: "user_input|user_message|user_query", confidence: "medium" }
|
|
924
|
+
],
|
|
925
|
+
implies: [
|
|
926
|
+
createImplication("customerFacing", true, "Pattern indicates customer-facing application")
|
|
927
|
+
]
|
|
928
|
+
}
|
|
929
|
+
];
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
// src/schemas/index.ts
|
|
934
|
+
import { z } from "zod";
|
|
935
|
+
var OwnerSchema = z.object({
|
|
936
|
+
name: z.string().min(1),
|
|
937
|
+
email: z.string().email(),
|
|
938
|
+
team: z.string().optional()
|
|
939
|
+
});
|
|
940
|
+
var TechnicalSchema = z.object({
|
|
941
|
+
type: z.enum(["model", "agent", "api_client", "framework", "pipeline"]),
|
|
942
|
+
framework: z.string().optional(),
|
|
943
|
+
frameworkVersion: z.string().optional(),
|
|
944
|
+
components: z.array(
|
|
945
|
+
z.object({
|
|
946
|
+
type: z.string(),
|
|
947
|
+
provider: z.string().optional(),
|
|
948
|
+
model: z.string().optional()
|
|
949
|
+
})
|
|
950
|
+
).optional(),
|
|
951
|
+
sourceFiles: z.array(z.string()).optional()
|
|
952
|
+
});
|
|
953
|
+
var RiskFactorsSchema = z.object({
|
|
954
|
+
autonomousDecisions: z.boolean().default(false),
|
|
955
|
+
customerFacing: z.boolean().default(false),
|
|
956
|
+
toolExecution: z.boolean().default(false),
|
|
957
|
+
externalDataAccess: z.boolean().default(false),
|
|
958
|
+
piiProcessing: z.enum(["yes", "no", "unknown"]).default("unknown"),
|
|
959
|
+
highStakesDecisions: z.boolean().default(false)
|
|
960
|
+
});
|
|
961
|
+
var ControlStatusSchema = z.object({
|
|
962
|
+
controlId: z.string(),
|
|
963
|
+
status: z.enum(["implemented", "partial", "not_implemented", "not_applicable"]),
|
|
964
|
+
evidence: z.string().optional(),
|
|
965
|
+
notes: z.string().optional(),
|
|
966
|
+
lastUpdated: z.string().datetime().optional()
|
|
967
|
+
});
|
|
968
|
+
var JurisdictionClassificationSchema = z.object({
|
|
969
|
+
/** Profile/jurisdiction ID (e.g., "eu-ai-act", "us-omb-m24") */
|
|
970
|
+
jurisdictionId: z.string(),
|
|
971
|
+
/** Risk level mapped to this jurisdiction's terminology */
|
|
972
|
+
riskLevel: z.string(),
|
|
973
|
+
/** Jurisdiction-specific category (e.g., EU AI Act category) */
|
|
974
|
+
category: z.string().optional(),
|
|
975
|
+
/** Status of controls for this jurisdiction */
|
|
976
|
+
controlStatuses: z.array(ControlStatusSchema).optional(),
|
|
977
|
+
/** Required artifacts for this jurisdiction */
|
|
978
|
+
requiredArtifacts: z.array(
|
|
979
|
+
z.object({
|
|
980
|
+
artifactId: z.string(),
|
|
981
|
+
status: z.enum(["pending", "complete", "not_applicable"]),
|
|
982
|
+
path: z.string().optional()
|
|
983
|
+
})
|
|
984
|
+
).optional(),
|
|
985
|
+
/** Last compliance check date */
|
|
986
|
+
lastChecked: z.string().datetime().optional(),
|
|
987
|
+
/** Compliance percentage for this jurisdiction */
|
|
988
|
+
compliancePercentage: z.number().min(0).max(100).optional()
|
|
989
|
+
});
|
|
990
|
+
var TrustworthinessCharacteristicSchema = z.object({
|
|
991
|
+
score: z.number().min(0).max(100).optional(),
|
|
992
|
+
notes: z.string().optional(),
|
|
993
|
+
lastAssessed: z.string().datetime().optional(),
|
|
994
|
+
assessedBy: z.string().optional()
|
|
995
|
+
});
|
|
996
|
+
var TrustworthinessSchema = z.object({
|
|
997
|
+
/** Valid and reliable: produces accurate, consistent results */
|
|
998
|
+
valid: TrustworthinessCharacteristicSchema.optional(),
|
|
999
|
+
reliable: TrustworthinessCharacteristicSchema.optional(),
|
|
1000
|
+
/** Safe: minimizes harm and risk */
|
|
1001
|
+
safe: TrustworthinessCharacteristicSchema.optional(),
|
|
1002
|
+
/** Secure: protected against threats */
|
|
1003
|
+
secure: TrustworthinessCharacteristicSchema.optional(),
|
|
1004
|
+
/** Accountable: clear responsibility and oversight */
|
|
1005
|
+
accountable: TrustworthinessCharacteristicSchema.optional(),
|
|
1006
|
+
/** Transparent: understandable and open about limitations */
|
|
1007
|
+
transparent: TrustworthinessCharacteristicSchema.optional(),
|
|
1008
|
+
/** Explainable: decisions can be understood */
|
|
1009
|
+
explainable: TrustworthinessCharacteristicSchema.optional(),
|
|
1010
|
+
/** Privacy-enhanced: protects personal information */
|
|
1011
|
+
privacyEnhanced: TrustworthinessCharacteristicSchema.optional(),
|
|
1012
|
+
/** Fair: avoids bias and discrimination */
|
|
1013
|
+
fair: TrustworthinessCharacteristicSchema.optional()
|
|
1014
|
+
});
|
|
1015
|
+
var ClassificationSchema = z.object({
|
|
1016
|
+
/** Primary AIGRC risk level */
|
|
1017
|
+
riskLevel: z.enum(["minimal", "limited", "high", "unacceptable"]),
|
|
1018
|
+
/** Risk factors that influenced the classification */
|
|
1019
|
+
riskFactors: RiskFactorsSchema,
|
|
1020
|
+
/** EU AI Act specific classification (legacy, prefer jurisdictions) */
|
|
1021
|
+
euAiAct: z.object({
|
|
1022
|
+
category: z.string(),
|
|
1023
|
+
transparencyRequired: z.boolean().default(false)
|
|
1024
|
+
}).optional(),
|
|
1025
|
+
/** Required artifacts based on classification */
|
|
1026
|
+
requiredArtifacts: z.array(
|
|
1027
|
+
z.object({
|
|
1028
|
+
type: z.string(),
|
|
1029
|
+
status: z.enum(["pending", "complete", "not_applicable"]),
|
|
1030
|
+
path: z.string().optional()
|
|
1031
|
+
})
|
|
1032
|
+
).optional(),
|
|
1033
|
+
/** Per-jurisdiction classifications for multi-jurisdiction compliance */
|
|
1034
|
+
jurisdictions: z.array(JurisdictionClassificationSchema).optional(),
|
|
1035
|
+
/** NIST AI RMF trustworthiness characteristics */
|
|
1036
|
+
trustworthiness: TrustworthinessSchema.optional()
|
|
1037
|
+
});
|
|
1038
|
+
var IntentSchema = z.object({
|
|
1039
|
+
linked: z.boolean().default(false),
|
|
1040
|
+
ticketSystem: z.enum(["jira", "ado", "github", "gitlab"]).nullable().optional(),
|
|
1041
|
+
ticketId: z.string().nullable().optional(),
|
|
1042
|
+
ticketUrl: z.string().url().nullable().optional(),
|
|
1043
|
+
businessJustification: z.string().nullable().optional(),
|
|
1044
|
+
riskTolerance: z.enum(["low", "medium", "high"]).nullable().optional(),
|
|
1045
|
+
importedAt: z.string().datetime().nullable().optional()
|
|
1046
|
+
});
|
|
1047
|
+
var ApprovalSchema = z.object({
|
|
1048
|
+
role: z.string(),
|
|
1049
|
+
name: z.string(),
|
|
1050
|
+
email: z.string().email().optional(),
|
|
1051
|
+
date: z.string(),
|
|
1052
|
+
source: z.string().optional()
|
|
1053
|
+
});
|
|
1054
|
+
var GovernanceSchema = z.object({
|
|
1055
|
+
status: z.enum(["draft", "linked", "approved", "production", "deprecated", "revoked"]),
|
|
1056
|
+
approvals: z.array(ApprovalSchema).default([]),
|
|
1057
|
+
deployment: z.object({
|
|
1058
|
+
environments: z.array(z.string()).default([]),
|
|
1059
|
+
lastDeployed: z.string().datetime().nullable().optional()
|
|
1060
|
+
}).optional()
|
|
1061
|
+
});
|
|
1062
|
+
var ConstraintsSchema = z.object({
|
|
1063
|
+
runtime: z.object({
|
|
1064
|
+
maxIterations: z.number().positive().optional(),
|
|
1065
|
+
timeoutSeconds: z.number().positive().optional(),
|
|
1066
|
+
maxTokensPerRequest: z.number().positive().optional(),
|
|
1067
|
+
maxCostPerRequestUsd: z.number().positive().optional()
|
|
1068
|
+
}).optional(),
|
|
1069
|
+
humanApprovalRequired: z.array(z.string()).optional(),
|
|
1070
|
+
monitoring: z.object({
|
|
1071
|
+
logAllDecisions: z.boolean().default(true),
|
|
1072
|
+
logToolInvocations: z.boolean().default(true)
|
|
1073
|
+
}).optional()
|
|
1074
|
+
});
|
|
1075
|
+
var AssetCardSchema = z.object({
|
|
1076
|
+
$schema: z.string().optional(),
|
|
1077
|
+
id: z.string().regex(/^aigrc-\d{4}-[a-f0-9]{8}$/),
|
|
1078
|
+
name: z.string().min(1).max(100),
|
|
1079
|
+
description: z.string().max(500).optional(),
|
|
1080
|
+
version: z.string().default("1.0.0"),
|
|
1081
|
+
created: z.string().datetime(),
|
|
1082
|
+
updated: z.string().datetime(),
|
|
1083
|
+
ownership: z.object({
|
|
1084
|
+
owner: OwnerSchema,
|
|
1085
|
+
team: z.string().optional()
|
|
1086
|
+
}),
|
|
1087
|
+
technical: TechnicalSchema,
|
|
1088
|
+
classification: ClassificationSchema,
|
|
1089
|
+
intent: IntentSchema,
|
|
1090
|
+
governance: GovernanceSchema,
|
|
1091
|
+
constraints: ConstraintsSchema.optional()
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
// src/classification.ts
|
|
1095
|
+
function classifyRisk(factors) {
|
|
1096
|
+
const reasons = [];
|
|
1097
|
+
let riskLevel = "minimal";
|
|
1098
|
+
if (factors.highStakesDecisions) {
|
|
1099
|
+
riskLevel = "high";
|
|
1100
|
+
reasons.push("Makes high-stakes decisions affecting individuals");
|
|
1101
|
+
}
|
|
1102
|
+
if (factors.autonomousDecisions && factors.toolExecution) {
|
|
1103
|
+
riskLevel = "high";
|
|
1104
|
+
reasons.push("Autonomous agent with tool execution capability");
|
|
1105
|
+
}
|
|
1106
|
+
if (factors.customerFacing && riskLevel === "minimal") {
|
|
1107
|
+
riskLevel = "limited";
|
|
1108
|
+
reasons.push("Customer-facing AI requires transparency");
|
|
1109
|
+
}
|
|
1110
|
+
if (factors.piiProcessing === "yes" && riskLevel === "minimal") {
|
|
1111
|
+
riskLevel = "limited";
|
|
1112
|
+
reasons.push("Processes personal data");
|
|
1113
|
+
}
|
|
1114
|
+
const euAiActCategory = mapToEuAiAct(riskLevel, factors);
|
|
1115
|
+
const requiredArtifacts = getRequiredArtifacts(riskLevel, factors);
|
|
1116
|
+
return {
|
|
1117
|
+
riskLevel,
|
|
1118
|
+
reasons,
|
|
1119
|
+
euAiActCategory,
|
|
1120
|
+
requiredArtifacts
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
function mapToEuAiAct(level, factors) {
|
|
1124
|
+
if (level === "unacceptable") return "prohibited";
|
|
1125
|
+
if (level === "high") return "high_risk";
|
|
1126
|
+
if (level === "limited" || factors.customerFacing) return "limited_risk";
|
|
1127
|
+
return "minimal_risk";
|
|
1128
|
+
}
|
|
1129
|
+
function getRequiredArtifacts(level, factors) {
|
|
1130
|
+
const artifacts = ["ai_asset_card"];
|
|
1131
|
+
if (level === "limited" || level === "high") {
|
|
1132
|
+
if (factors.customerFacing) {
|
|
1133
|
+
artifacts.push("transparency_notice");
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (level === "high") {
|
|
1137
|
+
artifacts.push("risk_assessment");
|
|
1138
|
+
artifacts.push("human_oversight_plan");
|
|
1139
|
+
if (factors.toolExecution) {
|
|
1140
|
+
artifacts.push("tool_inventory");
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
return artifacts;
|
|
1144
|
+
}
|
|
1145
|
+
function validateRiskFactors(factors) {
|
|
1146
|
+
const requiredProperties = [
|
|
1147
|
+
"highStakesDecisions",
|
|
1148
|
+
"autonomousDecisions",
|
|
1149
|
+
"toolExecution",
|
|
1150
|
+
"customerFacing",
|
|
1151
|
+
"piiProcessing"
|
|
1152
|
+
];
|
|
1153
|
+
for (const prop of requiredProperties) {
|
|
1154
|
+
if (!(prop in factors)) {
|
|
1155
|
+
console.error(`Missing required property: ${prop}`);
|
|
1156
|
+
return false;
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
return true;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// src/asset-card.ts
|
|
1163
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
1164
|
+
import { dirname } from "path";
|
|
1165
|
+
import YAML from "yaml";
|
|
1166
|
+
import { randomBytes } from "crypto";
|
|
1167
|
+
function generateAssetId() {
|
|
1168
|
+
const year = (/* @__PURE__ */ new Date()).getFullYear();
|
|
1169
|
+
const random = randomBytes(4).toString("hex");
|
|
1170
|
+
return `aigrc-${year}-${random}`;
|
|
1171
|
+
}
|
|
1172
|
+
function createAssetCard(options) {
|
|
1173
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1174
|
+
const id = generateAssetId();
|
|
1175
|
+
const jurisdictions = options.jurisdictions && options.jurisdictions.length > 0 ? options.jurisdictions.map((jurisdictionId) => ({
|
|
1176
|
+
jurisdictionId,
|
|
1177
|
+
riskLevel: "minimal",
|
|
1178
|
+
// Will be updated by classify
|
|
1179
|
+
controlStatuses: [],
|
|
1180
|
+
requiredArtifacts: []
|
|
1181
|
+
})) : void 0;
|
|
1182
|
+
const card = {
|
|
1183
|
+
$schema: "https://aigrc.dev/schemas/asset-card/v1",
|
|
1184
|
+
id,
|
|
1185
|
+
name: options.name,
|
|
1186
|
+
description: options.description,
|
|
1187
|
+
version: "1.0.0",
|
|
1188
|
+
created: now,
|
|
1189
|
+
updated: now,
|
|
1190
|
+
ownership: {
|
|
1191
|
+
owner: options.owner,
|
|
1192
|
+
team: options.owner.team
|
|
1193
|
+
},
|
|
1194
|
+
technical: {
|
|
1195
|
+
type: options.technical.type,
|
|
1196
|
+
framework: options.technical.framework,
|
|
1197
|
+
frameworkVersion: options.technical.frameworkVersion
|
|
1198
|
+
},
|
|
1199
|
+
classification: {
|
|
1200
|
+
riskLevel: "minimal",
|
|
1201
|
+
riskFactors: {
|
|
1202
|
+
autonomousDecisions: options.riskFactors?.autonomousDecisions ?? false,
|
|
1203
|
+
customerFacing: options.riskFactors?.customerFacing ?? false,
|
|
1204
|
+
toolExecution: options.riskFactors?.toolExecution ?? false,
|
|
1205
|
+
externalDataAccess: options.riskFactors?.externalDataAccess ?? false,
|
|
1206
|
+
piiProcessing: options.riskFactors?.piiProcessing ?? "unknown",
|
|
1207
|
+
highStakesDecisions: options.riskFactors?.highStakesDecisions ?? false
|
|
1208
|
+
},
|
|
1209
|
+
jurisdictions,
|
|
1210
|
+
trustworthiness: options.trustworthiness
|
|
1211
|
+
},
|
|
1212
|
+
intent: {
|
|
1213
|
+
linked: false
|
|
1214
|
+
},
|
|
1215
|
+
governance: {
|
|
1216
|
+
status: "draft",
|
|
1217
|
+
approvals: []
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
const result = AssetCardSchema.safeParse(card);
|
|
1221
|
+
if (!result.success) {
|
|
1222
|
+
throw new Error(`Invalid asset card: ${result.error.message}`);
|
|
1223
|
+
}
|
|
1224
|
+
return result.data;
|
|
1225
|
+
}
|
|
1226
|
+
function addJurisdiction(card, jurisdictionId, riskLevel) {
|
|
1227
|
+
const jurisdictions = card.classification.jurisdictions || [];
|
|
1228
|
+
const existing = jurisdictions.find((j) => j.jurisdictionId === jurisdictionId);
|
|
1229
|
+
if (existing) {
|
|
1230
|
+
if (riskLevel) {
|
|
1231
|
+
existing.riskLevel = riskLevel;
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
jurisdictions.push({
|
|
1235
|
+
jurisdictionId,
|
|
1236
|
+
riskLevel: riskLevel || "minimal",
|
|
1237
|
+
controlStatuses: [],
|
|
1238
|
+
requiredArtifacts: []
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1241
|
+
return {
|
|
1242
|
+
...card,
|
|
1243
|
+
classification: {
|
|
1244
|
+
...card.classification,
|
|
1245
|
+
jurisdictions
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
function updateJurisdictionCompliance(card, jurisdictionId, update) {
|
|
1250
|
+
const jurisdictions = card.classification.jurisdictions || [];
|
|
1251
|
+
const idx = jurisdictions.findIndex((j) => j.jurisdictionId === jurisdictionId);
|
|
1252
|
+
if (idx === -1) {
|
|
1253
|
+
jurisdictions.push({
|
|
1254
|
+
jurisdictionId,
|
|
1255
|
+
riskLevel: update.riskLevel || "minimal",
|
|
1256
|
+
...update,
|
|
1257
|
+
lastChecked: (/* @__PURE__ */ new Date()).toISOString()
|
|
1258
|
+
});
|
|
1259
|
+
} else {
|
|
1260
|
+
jurisdictions[idx] = {
|
|
1261
|
+
...jurisdictions[idx],
|
|
1262
|
+
...update,
|
|
1263
|
+
lastChecked: (/* @__PURE__ */ new Date()).toISOString()
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
return {
|
|
1267
|
+
...card,
|
|
1268
|
+
classification: {
|
|
1269
|
+
...card.classification,
|
|
1270
|
+
jurisdictions
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
function loadAssetCard(filePath) {
|
|
1275
|
+
if (!existsSync(filePath)) {
|
|
1276
|
+
throw new Error(`Asset card not found: ${filePath}`);
|
|
1277
|
+
}
|
|
1278
|
+
const content = readFileSync(filePath, "utf-8");
|
|
1279
|
+
const data = YAML.parse(content);
|
|
1280
|
+
const result = AssetCardSchema.safeParse(data);
|
|
1281
|
+
if (!result.success) {
|
|
1282
|
+
throw new Error(`Invalid asset card at ${filePath}: ${result.error.message}`);
|
|
1283
|
+
}
|
|
1284
|
+
return result.data;
|
|
1285
|
+
}
|
|
1286
|
+
function saveAssetCard(card, filePath) {
|
|
1287
|
+
const result = AssetCardSchema.safeParse(card);
|
|
1288
|
+
if (!result.success) {
|
|
1289
|
+
throw new Error(`Invalid asset card: ${result.error.message}`);
|
|
1290
|
+
}
|
|
1291
|
+
const dir = dirname(filePath);
|
|
1292
|
+
if (!existsSync(dir)) {
|
|
1293
|
+
mkdirSync(dir, { recursive: true });
|
|
1294
|
+
}
|
|
1295
|
+
card.updated = (/* @__PURE__ */ new Date()).toISOString();
|
|
1296
|
+
const content = YAML.stringify(card, { indent: 2, lineWidth: 100 });
|
|
1297
|
+
writeFileSync(filePath, content, "utf-8");
|
|
1298
|
+
}
|
|
1299
|
+
function validateAssetCard(card) {
|
|
1300
|
+
const result = AssetCardSchema.safeParse(card);
|
|
1301
|
+
if (result.success) {
|
|
1302
|
+
return { valid: true };
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
valid: false,
|
|
1306
|
+
errors: result.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`)
|
|
1307
|
+
};
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/golden-thread.ts
|
|
1311
|
+
function linkAssetToTicket(asset, ticket) {
|
|
1312
|
+
const warnings = [];
|
|
1313
|
+
const intent = {
|
|
1314
|
+
linked: true,
|
|
1315
|
+
ticketSystem: ticket.system,
|
|
1316
|
+
ticketId: ticket.id,
|
|
1317
|
+
ticketUrl: ticket.url,
|
|
1318
|
+
businessJustification: ticket.businessJustification,
|
|
1319
|
+
riskTolerance: ticket.riskTolerance,
|
|
1320
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1321
|
+
};
|
|
1322
|
+
if (ticket.riskTolerance && asset.classification.riskLevel) {
|
|
1323
|
+
const toleranceMap = { low: 0, medium: 1, high: 2 };
|
|
1324
|
+
const levelMap = { minimal: 0, limited: 1, high: 2, unacceptable: 3 };
|
|
1325
|
+
if (levelMap[asset.classification.riskLevel] > toleranceMap[ticket.riskTolerance]) {
|
|
1326
|
+
warnings.push(
|
|
1327
|
+
`Asset risk (${asset.classification.riskLevel}) exceeds ticket tolerance (${ticket.riskTolerance})`
|
|
1328
|
+
);
|
|
1329
|
+
}
|
|
1330
|
+
}
|
|
1331
|
+
return {
|
|
1332
|
+
success: true,
|
|
1333
|
+
intent,
|
|
1334
|
+
warnings: warnings.length > 0 ? warnings : void 0
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
function validateGoldenThread(asset) {
|
|
1338
|
+
const issues = [];
|
|
1339
|
+
let score = 100;
|
|
1340
|
+
if (!asset.intent.linked) {
|
|
1341
|
+
issues.push("Asset is not linked to any ticket");
|
|
1342
|
+
score -= 50;
|
|
1343
|
+
return { valid: false, healthScore: score, issues };
|
|
1344
|
+
}
|
|
1345
|
+
if (!asset.intent.businessJustification) {
|
|
1346
|
+
issues.push("Missing business justification");
|
|
1347
|
+
score -= 20;
|
|
1348
|
+
}
|
|
1349
|
+
if (asset.classification.riskLevel === "high" && asset.governance.approvals.length === 0) {
|
|
1350
|
+
issues.push("High-risk asset missing approvals");
|
|
1351
|
+
score -= 30;
|
|
1352
|
+
}
|
|
1353
|
+
return {
|
|
1354
|
+
valid: issues.length === 0,
|
|
1355
|
+
healthScore: Math.max(0, score),
|
|
1356
|
+
issues
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// src/detection/types.ts
|
|
1361
|
+
import { z as z2 } from "zod";
|
|
1362
|
+
var ConfidenceLevelSchema = z2.enum(["high", "medium", "low"]);
|
|
1363
|
+
var DetectionStrategySchema = z2.enum([
|
|
1364
|
+
"pattern_match",
|
|
1365
|
+
"import_analysis",
|
|
1366
|
+
"file_extension",
|
|
1367
|
+
"annotation"
|
|
1368
|
+
]);
|
|
1369
|
+
var FrameworkCategorySchema = z2.enum([
|
|
1370
|
+
"llm_provider",
|
|
1371
|
+
"framework",
|
|
1372
|
+
"agent_framework",
|
|
1373
|
+
"ml_framework",
|
|
1374
|
+
"ml_ops",
|
|
1375
|
+
"model_file"
|
|
1376
|
+
]);
|
|
1377
|
+
|
|
1378
|
+
// src/detection/scanner.ts
|
|
1379
|
+
import { readFileSync as readFileSync2, readdirSync, statSync, existsSync as existsSync2 } from "fs";
|
|
1380
|
+
import { join, extname as extname2, relative } from "path";
|
|
1381
|
+
|
|
1382
|
+
// src/detection/patterns/index.ts
|
|
1383
|
+
init_registry();
|
|
1384
|
+
init_python();
|
|
1385
|
+
init_javascript();
|
|
1386
|
+
init_model_files();
|
|
1387
|
+
init_risk_indicators();
|
|
1388
|
+
var initialized = false;
|
|
1389
|
+
function initializePatterns() {
|
|
1390
|
+
if (initialized) {
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
const { registerPythonPatterns: registerPythonPatterns2 } = (init_python(), __toCommonJS(python_exports));
|
|
1394
|
+
const { registerJavaScriptPatterns: registerJavaScriptPatterns2 } = (init_javascript(), __toCommonJS(javascript_exports));
|
|
1395
|
+
const { registerModelFilePatterns: registerModelFilePatterns2 } = (init_model_files(), __toCommonJS(model_files_exports));
|
|
1396
|
+
const { registerRiskIndicatorPatterns: registerRiskIndicatorPatterns2 } = (init_risk_indicators(), __toCommonJS(risk_indicators_exports));
|
|
1397
|
+
registerPythonPatterns2();
|
|
1398
|
+
registerJavaScriptPatterns2();
|
|
1399
|
+
registerModelFilePatterns2();
|
|
1400
|
+
registerRiskIndicatorPatterns2();
|
|
1401
|
+
initialized = true;
|
|
1402
|
+
}
|
|
1403
|
+
function resetPatterns() {
|
|
1404
|
+
const { clearRegistry: clearRegistry2 } = (init_registry(), __toCommonJS(registry_exports));
|
|
1405
|
+
clearRegistry2();
|
|
1406
|
+
initialized = false;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
// src/detection/strategies/pattern-matcher.ts
|
|
1410
|
+
function matchPatterns(filePath, lines, patterns) {
|
|
1411
|
+
const detections = [];
|
|
1412
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
1413
|
+
const line = lines[lineIndex];
|
|
1414
|
+
for (const pattern of patterns) {
|
|
1415
|
+
for (const rule of pattern.patterns) {
|
|
1416
|
+
if (rule.type !== "regex" && rule.type !== "literal") continue;
|
|
1417
|
+
const match = matchRule(line, rule);
|
|
1418
|
+
if (match) {
|
|
1419
|
+
detections.push({
|
|
1420
|
+
filePath,
|
|
1421
|
+
line: lineIndex + 1,
|
|
1422
|
+
column: match.index,
|
|
1423
|
+
match: match.text,
|
|
1424
|
+
matchContext: getContext(lines, lineIndex),
|
|
1425
|
+
registryCard: pattern.id,
|
|
1426
|
+
framework: pattern.name,
|
|
1427
|
+
category: pattern.category,
|
|
1428
|
+
confidence: rule.confidence,
|
|
1429
|
+
strategy: "pattern_match",
|
|
1430
|
+
implies: pattern.implies
|
|
1431
|
+
});
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
return detections;
|
|
1437
|
+
}
|
|
1438
|
+
function matchRule(line, rule) {
|
|
1439
|
+
if (rule.type === "literal") {
|
|
1440
|
+
const index = line.indexOf(rule.pattern);
|
|
1441
|
+
if (index !== -1) {
|
|
1442
|
+
return { text: rule.pattern, index };
|
|
1443
|
+
}
|
|
1444
|
+
} else if (rule.type === "regex") {
|
|
1445
|
+
try {
|
|
1446
|
+
const regex = new RegExp(rule.pattern, "i");
|
|
1447
|
+
const match = regex.exec(line);
|
|
1448
|
+
if (match) {
|
|
1449
|
+
return { text: match[0], index: match.index };
|
|
1450
|
+
}
|
|
1451
|
+
} catch {
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
return null;
|
|
1455
|
+
}
|
|
1456
|
+
function getContext(lines, index, contextLines = 2) {
|
|
1457
|
+
const start = Math.max(0, index - contextLines);
|
|
1458
|
+
const end = Math.min(lines.length, index + contextLines + 1);
|
|
1459
|
+
return lines.slice(start, end).join("\n");
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// src/detection/strategies/import-analyzer.ts
|
|
1463
|
+
var PYTHON_IMPORT_REGEX = /^(?:from\s+(\S+)\s+import|import\s+(\S+))/;
|
|
1464
|
+
var JS_IMPORT_REGEX = /(?:import\s+(?:[\w{},*\s]+\s+from\s+)?['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\s*\))/;
|
|
1465
|
+
function analyzeImports(filePath, content, patterns) {
|
|
1466
|
+
const detections = [];
|
|
1467
|
+
const lines = content.split("\n");
|
|
1468
|
+
const isPython = filePath.endsWith(".py");
|
|
1469
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
1470
|
+
const line = lines[lineIndex].trim();
|
|
1471
|
+
if (!line) continue;
|
|
1472
|
+
if (isPython && line.startsWith("#")) continue;
|
|
1473
|
+
if (!isPython && (line.startsWith("//") || line.startsWith("/*"))) continue;
|
|
1474
|
+
const importMatch = isPython ? extractPythonImport(line) : extractJsImport(line);
|
|
1475
|
+
if (!importMatch) continue;
|
|
1476
|
+
for (const pattern of patterns) {
|
|
1477
|
+
if (pattern.language !== "any" && (isPython && pattern.language !== "python" || !isPython && pattern.language !== "javascript" && pattern.language !== "typescript")) {
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
for (const rule of pattern.patterns) {
|
|
1481
|
+
if (rule.type !== "import") continue;
|
|
1482
|
+
if (matchesImport(line, rule.pattern)) {
|
|
1483
|
+
detections.push({
|
|
1484
|
+
filePath,
|
|
1485
|
+
line: lineIndex + 1,
|
|
1486
|
+
match: line,
|
|
1487
|
+
registryCard: pattern.id,
|
|
1488
|
+
framework: pattern.name,
|
|
1489
|
+
category: pattern.category,
|
|
1490
|
+
confidence: rule.confidence,
|
|
1491
|
+
strategy: "import_analysis",
|
|
1492
|
+
implies: pattern.implies,
|
|
1493
|
+
metadata: { importedModule: importMatch }
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
return detections;
|
|
1500
|
+
}
|
|
1501
|
+
function extractPythonImport(line) {
|
|
1502
|
+
const match = PYTHON_IMPORT_REGEX.exec(line);
|
|
1503
|
+
if (match) {
|
|
1504
|
+
return match[1] || match[2];
|
|
1505
|
+
}
|
|
1506
|
+
return null;
|
|
1507
|
+
}
|
|
1508
|
+
function extractJsImport(line) {
|
|
1509
|
+
const match = JS_IMPORT_REGEX.exec(line);
|
|
1510
|
+
if (match) {
|
|
1511
|
+
return match[1] || match[2];
|
|
1512
|
+
}
|
|
1513
|
+
return null;
|
|
1514
|
+
}
|
|
1515
|
+
function matchesImport(line, pattern) {
|
|
1516
|
+
const normalizedLine = line.toLowerCase().replace(/'/g, '"');
|
|
1517
|
+
const normalizedPattern = pattern.toLowerCase().replace(/'/g, '"');
|
|
1518
|
+
return normalizedLine.includes(normalizedPattern);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// src/detection/strategies/file-scanner.ts
|
|
1522
|
+
init_registry();
|
|
1523
|
+
import { extname, basename } from "path";
|
|
1524
|
+
function scanFileExtension(filePath) {
|
|
1525
|
+
const detections = [];
|
|
1526
|
+
const ext = extname(filePath).toLowerCase();
|
|
1527
|
+
const filename = basename(filePath);
|
|
1528
|
+
const modelPatterns = getPatternsByCategory("model_file");
|
|
1529
|
+
for (const pattern of modelPatterns) {
|
|
1530
|
+
for (const rule of pattern.patterns) {
|
|
1531
|
+
let matched = false;
|
|
1532
|
+
if (rule.type === "literal") {
|
|
1533
|
+
if (ext === rule.pattern.toLowerCase()) {
|
|
1534
|
+
matched = true;
|
|
1535
|
+
}
|
|
1536
|
+
} else if (rule.type === "regex") {
|
|
1537
|
+
try {
|
|
1538
|
+
const regex = new RegExp(rule.pattern, "i");
|
|
1539
|
+
matched = regex.test(filename);
|
|
1540
|
+
} catch {
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
if (matched) {
|
|
1544
|
+
detections.push({
|
|
1545
|
+
filePath,
|
|
1546
|
+
line: 0,
|
|
1547
|
+
// N/A for file-level detection
|
|
1548
|
+
match: filename,
|
|
1549
|
+
registryCard: pattern.id,
|
|
1550
|
+
framework: pattern.name,
|
|
1551
|
+
category: pattern.category,
|
|
1552
|
+
confidence: rule.confidence,
|
|
1553
|
+
strategy: "file_extension",
|
|
1554
|
+
implies: pattern.implies,
|
|
1555
|
+
metadata: { extension: ext, filename }
|
|
1556
|
+
});
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
return detections;
|
|
1561
|
+
}
|
|
1562
|
+
var MODEL_EXTENSIONS = [
|
|
1563
|
+
".pt",
|
|
1564
|
+
".pth",
|
|
1565
|
+
".safetensors",
|
|
1566
|
+
".onnx",
|
|
1567
|
+
".h5",
|
|
1568
|
+
".keras",
|
|
1569
|
+
".pb",
|
|
1570
|
+
".pkl",
|
|
1571
|
+
".joblib",
|
|
1572
|
+
".bin",
|
|
1573
|
+
".gguf",
|
|
1574
|
+
".ggml",
|
|
1575
|
+
".npz"
|
|
1576
|
+
];
|
|
1577
|
+
function isModelFile(filePath) {
|
|
1578
|
+
const ext = extname(filePath).toLowerCase();
|
|
1579
|
+
return MODEL_EXTENSIONS.includes(ext);
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// src/detection/strategies/annotation-detector.ts
|
|
1583
|
+
var PYTHON_DECORATOR_REGEX = /^\s*@(\w+)(?:\(.*\))?\s*$/;
|
|
1584
|
+
var TS_DECORATOR_REGEX = /^\s*@(\w+)(?:\(.*\))?\s*$/;
|
|
1585
|
+
function detectAnnotations(filePath, lines, patterns) {
|
|
1586
|
+
const detections = [];
|
|
1587
|
+
const isPython = filePath.endsWith(".py");
|
|
1588
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
1589
|
+
const line = lines[lineIndex];
|
|
1590
|
+
const trimmedLine = line.trim();
|
|
1591
|
+
if (!trimmedLine.startsWith("@")) continue;
|
|
1592
|
+
const decoratorMatch = isPython ? PYTHON_DECORATOR_REGEX.exec(trimmedLine) : TS_DECORATOR_REGEX.exec(trimmedLine);
|
|
1593
|
+
if (!decoratorMatch) continue;
|
|
1594
|
+
const decoratorName = decoratorMatch[1];
|
|
1595
|
+
for (const pattern of patterns) {
|
|
1596
|
+
if (pattern.language !== "any" && (isPython && pattern.language !== "python" || !isPython && pattern.language !== "javascript" && pattern.language !== "typescript")) {
|
|
1597
|
+
continue;
|
|
1598
|
+
}
|
|
1599
|
+
for (const rule of pattern.patterns) {
|
|
1600
|
+
if (rule.type !== "decorator") continue;
|
|
1601
|
+
const ruleDecorator = rule.pattern.replace(/^@/, "");
|
|
1602
|
+
if (decoratorName.toLowerCase() === ruleDecorator.toLowerCase()) {
|
|
1603
|
+
const nextLine = lineIndex + 1 < lines.length ? lines[lineIndex + 1] : "";
|
|
1604
|
+
const decoratedName = extractDecoratedName(nextLine, isPython);
|
|
1605
|
+
detections.push({
|
|
1606
|
+
filePath,
|
|
1607
|
+
line: lineIndex + 1,
|
|
1608
|
+
match: trimmedLine,
|
|
1609
|
+
matchContext: decoratedName ? `${trimmedLine}
|
|
1610
|
+
${nextLine.trim()}` : trimmedLine,
|
|
1611
|
+
registryCard: pattern.id,
|
|
1612
|
+
framework: pattern.name,
|
|
1613
|
+
category: pattern.category,
|
|
1614
|
+
confidence: rule.confidence,
|
|
1615
|
+
strategy: "annotation",
|
|
1616
|
+
implies: pattern.implies,
|
|
1617
|
+
metadata: {
|
|
1618
|
+
decorator: decoratorName,
|
|
1619
|
+
decorated: decoratedName
|
|
1620
|
+
}
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
return detections;
|
|
1627
|
+
}
|
|
1628
|
+
function extractDecoratedName(line, isPython) {
|
|
1629
|
+
if (isPython) {
|
|
1630
|
+
const pythonMatch = /(?:def|class|async\s+def)\s+(\w+)/.exec(line);
|
|
1631
|
+
if (pythonMatch) return pythonMatch[1];
|
|
1632
|
+
} else {
|
|
1633
|
+
const tsMatch = /(?:function|class|async\s+function)\s+(\w+)/.exec(line);
|
|
1634
|
+
if (tsMatch) return tsMatch[1];
|
|
1635
|
+
const methodMatch = /^\s*(?:async\s+)?(\w+)\s*\(/.exec(line);
|
|
1636
|
+
if (methodMatch) return methodMatch[1];
|
|
1637
|
+
}
|
|
1638
|
+
return null;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
// src/detection/risk-inference.ts
|
|
1642
|
+
function inferRiskFactors(detections) {
|
|
1643
|
+
const implications = collectImplications(detections);
|
|
1644
|
+
return {
|
|
1645
|
+
autonomousDecisions: inferBoolean(implications, "autonomousDecisions"),
|
|
1646
|
+
customerFacing: inferBoolean(implications, "customerFacing"),
|
|
1647
|
+
toolExecution: inferBoolean(implications, "toolExecution"),
|
|
1648
|
+
externalDataAccess: inferBoolean(implications, "externalDataAccess"),
|
|
1649
|
+
piiProcessing: inferPiiProcessing(implications),
|
|
1650
|
+
highStakesDecisions: inferBoolean(implications, "highStakesDecisions")
|
|
1651
|
+
};
|
|
1652
|
+
}
|
|
1653
|
+
function collectImplications(detections) {
|
|
1654
|
+
const implications = [];
|
|
1655
|
+
for (const detection of detections) {
|
|
1656
|
+
const weight = confidenceWeight(detection.confidence);
|
|
1657
|
+
for (const implication of detection.implies) {
|
|
1658
|
+
if (weight >= 2) {
|
|
1659
|
+
implications.push({
|
|
1660
|
+
...implication,
|
|
1661
|
+
weight
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
return implications;
|
|
1667
|
+
}
|
|
1668
|
+
function confidenceWeight(confidence) {
|
|
1669
|
+
const weights = {
|
|
1670
|
+
high: 3,
|
|
1671
|
+
medium: 2,
|
|
1672
|
+
low: 1
|
|
1673
|
+
};
|
|
1674
|
+
return weights[confidence];
|
|
1675
|
+
}
|
|
1676
|
+
function inferBoolean(implications, factor) {
|
|
1677
|
+
const relevant = implications.filter((i) => i.factor === factor);
|
|
1678
|
+
if (relevant.length === 0) return false;
|
|
1679
|
+
const highWeight = relevant.filter((i) => i.weight >= 3 && i.value === true);
|
|
1680
|
+
if (highWeight.length > 0) return true;
|
|
1681
|
+
const mediumWeight = relevant.filter((i) => i.weight >= 2 && i.value === true);
|
|
1682
|
+
if (mediumWeight.length >= 2) return true;
|
|
1683
|
+
if (mediumWeight.length >= 1) return true;
|
|
1684
|
+
return false;
|
|
1685
|
+
}
|
|
1686
|
+
function inferPiiProcessing(implications) {
|
|
1687
|
+
const relevant = implications.filter((i) => i.factor === "piiProcessing");
|
|
1688
|
+
if (relevant.length === 0) return "unknown";
|
|
1689
|
+
const highYes = relevant.filter((i) => i.weight >= 3 && i.value === "yes");
|
|
1690
|
+
if (highYes.length > 0) return "yes";
|
|
1691
|
+
const mediumYes = relevant.filter((i) => i.weight >= 2 && i.value === "yes");
|
|
1692
|
+
if (mediumYes.length >= 2) return "yes";
|
|
1693
|
+
if (relevant.some((i) => i.value === "yes")) return "yes";
|
|
1694
|
+
if (relevant.every((i) => i.value === "no")) return "no";
|
|
1695
|
+
return "unknown";
|
|
1696
|
+
}
|
|
1697
|
+
var IMPLICATION_CHAINS = {
|
|
1698
|
+
// LangChain implies tool execution and external data access
|
|
1699
|
+
"langchain-python": [
|
|
1700
|
+
{ factor: "toolExecution", value: true, reason: "LangChain enables tool calling" },
|
|
1701
|
+
{ factor: "externalDataAccess", value: true, reason: "LangChain chains access external data" }
|
|
1702
|
+
],
|
|
1703
|
+
"langchain-js": [
|
|
1704
|
+
{ factor: "toolExecution", value: true, reason: "LangChain.js enables tool calling" },
|
|
1705
|
+
{ factor: "externalDataAccess", value: true, reason: "LangChain.js chains access external data" }
|
|
1706
|
+
],
|
|
1707
|
+
// CrewAI implies autonomous decisions and tool execution
|
|
1708
|
+
crewai: [
|
|
1709
|
+
{ factor: "autonomousDecisions", value: true, reason: "CrewAI enables autonomous agents" },
|
|
1710
|
+
{ factor: "toolExecution", value: true, reason: "CrewAI agents execute tools" }
|
|
1711
|
+
],
|
|
1712
|
+
// AutoGen implies autonomous decisions and tool execution
|
|
1713
|
+
autogen: [
|
|
1714
|
+
{ factor: "autonomousDecisions", value: true, reason: "AutoGen enables autonomous agents" },
|
|
1715
|
+
{ factor: "toolExecution", value: true, reason: "AutoGen agents can execute code" }
|
|
1716
|
+
],
|
|
1717
|
+
// LangGraph implies autonomous decisions
|
|
1718
|
+
langgraph: [
|
|
1719
|
+
{ factor: "autonomousDecisions", value: true, reason: "LangGraph enables stateful agents" }
|
|
1720
|
+
],
|
|
1721
|
+
"langgraph-js": [
|
|
1722
|
+
{ factor: "autonomousDecisions", value: true, reason: "LangGraph.js enables stateful agents" }
|
|
1723
|
+
],
|
|
1724
|
+
// Vercel AI SDK implies customer-facing
|
|
1725
|
+
"vercel-ai-sdk": [
|
|
1726
|
+
{ factor: "customerFacing", value: true, reason: "Vercel AI SDK used in user-facing apps" }
|
|
1727
|
+
]
|
|
1728
|
+
};
|
|
1729
|
+
function applyImplicationChains(detections) {
|
|
1730
|
+
return detections.map((detection) => {
|
|
1731
|
+
const chainedImplications = IMPLICATION_CHAINS[detection.registryCard];
|
|
1732
|
+
if (chainedImplications) {
|
|
1733
|
+
return {
|
|
1734
|
+
...detection,
|
|
1735
|
+
implies: [...detection.implies, ...chainedImplications]
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
return detection;
|
|
1739
|
+
});
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// src/detection/scanner.ts
|
|
1743
|
+
var DEFAULT_IGNORE_PATTERNS = [
|
|
1744
|
+
"node_modules",
|
|
1745
|
+
"__pycache__",
|
|
1746
|
+
".git",
|
|
1747
|
+
"dist",
|
|
1748
|
+
"build",
|
|
1749
|
+
".next",
|
|
1750
|
+
".nuxt",
|
|
1751
|
+
"venv",
|
|
1752
|
+
".venv",
|
|
1753
|
+
"env",
|
|
1754
|
+
".env",
|
|
1755
|
+
".aigrc",
|
|
1756
|
+
"*.min.js",
|
|
1757
|
+
"*.bundle.js",
|
|
1758
|
+
"*.map",
|
|
1759
|
+
"coverage",
|
|
1760
|
+
".pytest_cache",
|
|
1761
|
+
".mypy_cache",
|
|
1762
|
+
".tox",
|
|
1763
|
+
"egg-info"
|
|
1764
|
+
];
|
|
1765
|
+
var DEFAULT_CODE_EXTENSIONS = [
|
|
1766
|
+
".py",
|
|
1767
|
+
".js",
|
|
1768
|
+
".ts",
|
|
1769
|
+
".jsx",
|
|
1770
|
+
".tsx",
|
|
1771
|
+
".mjs",
|
|
1772
|
+
".cjs"
|
|
1773
|
+
];
|
|
1774
|
+
async function scan(options, onProgress) {
|
|
1775
|
+
const startTime = Date.now();
|
|
1776
|
+
const detections = [];
|
|
1777
|
+
const errors = [];
|
|
1778
|
+
let scannedFiles = 0;
|
|
1779
|
+
let skippedFiles = 0;
|
|
1780
|
+
if (!isRegistryInitialized()) {
|
|
1781
|
+
initializePatterns();
|
|
1782
|
+
}
|
|
1783
|
+
const resolvedOptions = resolveOptions(options);
|
|
1784
|
+
const files = collectFiles(resolvedOptions);
|
|
1785
|
+
const totalFiles = files.length;
|
|
1786
|
+
for (const filePath of files) {
|
|
1787
|
+
if (resolvedOptions.maxFiles && scannedFiles >= resolvedOptions.maxFiles) {
|
|
1788
|
+
break;
|
|
1789
|
+
}
|
|
1790
|
+
if (onProgress) {
|
|
1791
|
+
onProgress({
|
|
1792
|
+
totalFiles,
|
|
1793
|
+
scannedFiles,
|
|
1794
|
+
currentFile: relative(resolvedOptions.directory, filePath),
|
|
1795
|
+
detections: detections.length
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
try {
|
|
1799
|
+
const fileDetections = await scanFile(filePath, resolvedOptions);
|
|
1800
|
+
detections.push(...fileDetections);
|
|
1801
|
+
scannedFiles++;
|
|
1802
|
+
if (resolvedOptions.earlyExit && fileDetections.some((d) => d.confidence === "high")) {
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
} catch (error) {
|
|
1806
|
+
errors.push({
|
|
1807
|
+
filePath,
|
|
1808
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1809
|
+
recoverable: true
|
|
1810
|
+
});
|
|
1811
|
+
skippedFiles++;
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
const uniqueDetections = deduplicateDetections(detections);
|
|
1815
|
+
const summary = createSummary(uniqueDetections);
|
|
1816
|
+
const inferredRiskFactors = inferRiskFactors(uniqueDetections);
|
|
1817
|
+
const suggestedTechnical = suggestTechnical(uniqueDetections, summary);
|
|
1818
|
+
return {
|
|
1819
|
+
detections: uniqueDetections,
|
|
1820
|
+
summary,
|
|
1821
|
+
inferredRiskFactors,
|
|
1822
|
+
suggestedTechnical,
|
|
1823
|
+
scannedFiles,
|
|
1824
|
+
skippedFiles,
|
|
1825
|
+
duration: Date.now() - startTime,
|
|
1826
|
+
errors: errors.length > 0 ? errors : void 0
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
function scanSync(options, onProgress) {
|
|
1830
|
+
const startTime = Date.now();
|
|
1831
|
+
const detections = [];
|
|
1832
|
+
const errors = [];
|
|
1833
|
+
let scannedFiles = 0;
|
|
1834
|
+
let skippedFiles = 0;
|
|
1835
|
+
if (!isRegistryInitialized()) {
|
|
1836
|
+
initializePatterns();
|
|
1837
|
+
}
|
|
1838
|
+
const resolvedOptions = resolveOptions(options);
|
|
1839
|
+
const files = collectFiles(resolvedOptions);
|
|
1840
|
+
const totalFiles = files.length;
|
|
1841
|
+
for (const filePath of files) {
|
|
1842
|
+
if (resolvedOptions.maxFiles && scannedFiles >= resolvedOptions.maxFiles) {
|
|
1843
|
+
break;
|
|
1844
|
+
}
|
|
1845
|
+
if (onProgress) {
|
|
1846
|
+
onProgress({
|
|
1847
|
+
totalFiles,
|
|
1848
|
+
scannedFiles,
|
|
1849
|
+
currentFile: relative(resolvedOptions.directory, filePath),
|
|
1850
|
+
detections: detections.length
|
|
1851
|
+
});
|
|
1852
|
+
}
|
|
1853
|
+
try {
|
|
1854
|
+
const fileDetections = scanFileSync(filePath, resolvedOptions);
|
|
1855
|
+
detections.push(...fileDetections);
|
|
1856
|
+
scannedFiles++;
|
|
1857
|
+
if (resolvedOptions.earlyExit && fileDetections.some((d) => d.confidence === "high")) {
|
|
1858
|
+
break;
|
|
1859
|
+
}
|
|
1860
|
+
} catch (error) {
|
|
1861
|
+
errors.push({
|
|
1862
|
+
filePath,
|
|
1863
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1864
|
+
recoverable: true
|
|
1865
|
+
});
|
|
1866
|
+
skippedFiles++;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
const uniqueDetections = deduplicateDetections(detections);
|
|
1870
|
+
const summary = createSummary(uniqueDetections);
|
|
1871
|
+
const inferredRiskFactors = inferRiskFactors(uniqueDetections);
|
|
1872
|
+
const suggestedTechnical = suggestTechnical(uniqueDetections, summary);
|
|
1873
|
+
return {
|
|
1874
|
+
detections: uniqueDetections,
|
|
1875
|
+
summary,
|
|
1876
|
+
inferredRiskFactors,
|
|
1877
|
+
suggestedTechnical,
|
|
1878
|
+
scannedFiles,
|
|
1879
|
+
skippedFiles,
|
|
1880
|
+
duration: Date.now() - startTime,
|
|
1881
|
+
errors: errors.length > 0 ? errors : void 0
|
|
1882
|
+
};
|
|
1883
|
+
}
|
|
1884
|
+
function resolveOptions(options) {
|
|
1885
|
+
return {
|
|
1886
|
+
directory: options.directory,
|
|
1887
|
+
recursive: options.recursive ?? true,
|
|
1888
|
+
extensions: options.extensions ?? [...DEFAULT_CODE_EXTENSIONS, ...MODEL_EXTENSIONS],
|
|
1889
|
+
ignorePatterns: options.ignorePatterns ?? DEFAULT_IGNORE_PATTERNS,
|
|
1890
|
+
strategies: options.strategies ?? [
|
|
1891
|
+
"pattern_match",
|
|
1892
|
+
"import_analysis",
|
|
1893
|
+
"file_extension",
|
|
1894
|
+
"annotation"
|
|
1895
|
+
],
|
|
1896
|
+
maxFileSize: options.maxFileSize ?? 1024 * 1024,
|
|
1897
|
+
// 1MB default
|
|
1898
|
+
maxFiles: options.maxFiles ?? 1e4,
|
|
1899
|
+
earlyExit: options.earlyExit ?? false,
|
|
1900
|
+
respectGitignore: options.respectGitignore ?? true,
|
|
1901
|
+
customPatterns: options.customPatterns ?? []
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
function collectFiles(options) {
|
|
1905
|
+
const files = [];
|
|
1906
|
+
const gitignorePatterns = options.respectGitignore ? loadGitignore(options.directory) : [];
|
|
1907
|
+
function walk(dir) {
|
|
1908
|
+
let entries;
|
|
1909
|
+
try {
|
|
1910
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
1911
|
+
} catch {
|
|
1912
|
+
return;
|
|
1913
|
+
}
|
|
1914
|
+
for (const entry of entries) {
|
|
1915
|
+
const fullPath = join(dir, entry.name);
|
|
1916
|
+
const relativePath = relative(options.directory, fullPath);
|
|
1917
|
+
if (shouldIgnore(relativePath, entry.name, options.ignorePatterns, gitignorePatterns)) {
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
if (entry.isDirectory() && options.recursive) {
|
|
1921
|
+
walk(fullPath);
|
|
1922
|
+
} else if (entry.isFile()) {
|
|
1923
|
+
const ext = extname2(entry.name).toLowerCase();
|
|
1924
|
+
if (options.extensions.some((e) => e.toLowerCase() === ext)) {
|
|
1925
|
+
try {
|
|
1926
|
+
const stats = statSync(fullPath);
|
|
1927
|
+
if (stats.size <= options.maxFileSize) {
|
|
1928
|
+
files.push(fullPath);
|
|
1929
|
+
}
|
|
1930
|
+
} catch {
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
if (existsSync2(options.directory)) {
|
|
1937
|
+
const stat = statSync(options.directory);
|
|
1938
|
+
if (stat.isDirectory()) {
|
|
1939
|
+
walk(options.directory);
|
|
1940
|
+
} else if (stat.isFile()) {
|
|
1941
|
+
files.push(options.directory);
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
return files;
|
|
1945
|
+
}
|
|
1946
|
+
function shouldIgnore(relativePath, name, ignorePatterns, gitignorePatterns) {
|
|
1947
|
+
const allPatterns = [...ignorePatterns, ...gitignorePatterns];
|
|
1948
|
+
for (const pattern of allPatterns) {
|
|
1949
|
+
if (name === pattern || relativePath === pattern) {
|
|
1950
|
+
return true;
|
|
1951
|
+
}
|
|
1952
|
+
if (relativePath.includes(pattern)) {
|
|
1953
|
+
return true;
|
|
1954
|
+
}
|
|
1955
|
+
if (pattern.includes("*")) {
|
|
1956
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
1957
|
+
try {
|
|
1958
|
+
const regex = new RegExp(regexPattern);
|
|
1959
|
+
if (regex.test(name) || regex.test(relativePath)) {
|
|
1960
|
+
return true;
|
|
1961
|
+
}
|
|
1962
|
+
} catch {
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return false;
|
|
1967
|
+
}
|
|
1968
|
+
function loadGitignore(directory) {
|
|
1969
|
+
const gitignorePath = join(directory, ".gitignore");
|
|
1970
|
+
if (!existsSync2(gitignorePath)) {
|
|
1971
|
+
return [];
|
|
1972
|
+
}
|
|
1973
|
+
try {
|
|
1974
|
+
const content = readFileSync2(gitignorePath, "utf-8");
|
|
1975
|
+
return content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
1976
|
+
} catch {
|
|
1977
|
+
return [];
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
async function scanFile(filePath, options) {
|
|
1981
|
+
return scanFileSync(filePath, options);
|
|
1982
|
+
}
|
|
1983
|
+
function scanFileSync(filePath, options) {
|
|
1984
|
+
const detections = [];
|
|
1985
|
+
const ext = extname2(filePath).toLowerCase();
|
|
1986
|
+
const patterns = [...getAllPatterns(), ...options.customPatterns ?? []];
|
|
1987
|
+
if (options.strategies.includes("file_extension") && MODEL_EXTENSIONS.some((e) => e.toLowerCase() === ext)) {
|
|
1988
|
+
const extensionDetections = scanFileExtension(filePath);
|
|
1989
|
+
detections.push(...extensionDetections);
|
|
1990
|
+
}
|
|
1991
|
+
if (DEFAULT_CODE_EXTENSIONS.some((e) => e.toLowerCase() === ext)) {
|
|
1992
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
1993
|
+
const lines = content.split("\n");
|
|
1994
|
+
if (options.strategies.includes("import_analysis")) {
|
|
1995
|
+
const importDetections = analyzeImports(filePath, content, patterns);
|
|
1996
|
+
detections.push(...importDetections);
|
|
1997
|
+
}
|
|
1998
|
+
if (options.strategies.includes("pattern_match")) {
|
|
1999
|
+
const patternDetections = matchPatterns(filePath, lines, patterns);
|
|
2000
|
+
detections.push(...patternDetections);
|
|
2001
|
+
}
|
|
2002
|
+
if (options.strategies.includes("annotation")) {
|
|
2003
|
+
const annotationDetections = detectAnnotations(filePath, lines, patterns);
|
|
2004
|
+
detections.push(...annotationDetections);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return detections;
|
|
2008
|
+
}
|
|
2009
|
+
function deduplicateDetections(detections) {
|
|
2010
|
+
const seen = /* @__PURE__ */ new Map();
|
|
2011
|
+
for (const detection of detections) {
|
|
2012
|
+
const key = `${detection.filePath}:${detection.line}:${detection.registryCard}`;
|
|
2013
|
+
const existing = seen.get(key);
|
|
2014
|
+
if (!existing || confidenceRank(detection.confidence) > confidenceRank(existing.confidence)) {
|
|
2015
|
+
seen.set(key, detection);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
return Array.from(seen.values());
|
|
2019
|
+
}
|
|
2020
|
+
function confidenceRank(level) {
|
|
2021
|
+
const ranks = { high: 3, medium: 2, low: 1 };
|
|
2022
|
+
return ranks[level];
|
|
2023
|
+
}
|
|
2024
|
+
function createSummary(detections) {
|
|
2025
|
+
const byFramework = {};
|
|
2026
|
+
const byCategory = {
|
|
2027
|
+
llm_provider: 0,
|
|
2028
|
+
framework: 0,
|
|
2029
|
+
agent_framework: 0,
|
|
2030
|
+
ml_framework: 0,
|
|
2031
|
+
ml_ops: 0,
|
|
2032
|
+
model_file: 0
|
|
2033
|
+
};
|
|
2034
|
+
const byConfidence = {
|
|
2035
|
+
high: 0,
|
|
2036
|
+
medium: 0,
|
|
2037
|
+
low: 0
|
|
2038
|
+
};
|
|
2039
|
+
for (const detection of detections) {
|
|
2040
|
+
byFramework[detection.framework] = (byFramework[detection.framework] || 0) + 1;
|
|
2041
|
+
byCategory[detection.category]++;
|
|
2042
|
+
byConfidence[detection.confidence]++;
|
|
2043
|
+
}
|
|
2044
|
+
let primaryFramework;
|
|
2045
|
+
let maxScore = 0;
|
|
2046
|
+
for (const [framework] of Object.entries(byFramework)) {
|
|
2047
|
+
const frameworkDetections = detections.filter((d) => d.framework === framework);
|
|
2048
|
+
const score = frameworkDetections.reduce(
|
|
2049
|
+
(sum, d) => sum + confidenceRank(d.confidence),
|
|
2050
|
+
0
|
|
2051
|
+
);
|
|
2052
|
+
if (score > maxScore) {
|
|
2053
|
+
maxScore = score;
|
|
2054
|
+
primaryFramework = framework;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
let primaryCategory;
|
|
2058
|
+
let maxCategoryCount = 0;
|
|
2059
|
+
for (const [cat, count] of Object.entries(byCategory)) {
|
|
2060
|
+
if (count > maxCategoryCount) {
|
|
2061
|
+
maxCategoryCount = count;
|
|
2062
|
+
primaryCategory = cat;
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
return {
|
|
2066
|
+
totalDetections: detections.length,
|
|
2067
|
+
byFramework,
|
|
2068
|
+
byCategory,
|
|
2069
|
+
byConfidence,
|
|
2070
|
+
primaryFramework,
|
|
2071
|
+
primaryCategory
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
function suggestTechnical(detections, summary) {
|
|
2075
|
+
const typeMap = {
|
|
2076
|
+
llm_provider: "api_client",
|
|
2077
|
+
framework: "framework",
|
|
2078
|
+
agent_framework: "agent",
|
|
2079
|
+
ml_framework: "model",
|
|
2080
|
+
ml_ops: "pipeline",
|
|
2081
|
+
model_file: "model"
|
|
2082
|
+
};
|
|
2083
|
+
const sourceFiles = [...new Set(detections.map((d) => d.filePath))];
|
|
2084
|
+
return {
|
|
2085
|
+
type: typeMap[summary.primaryCategory ?? "framework"],
|
|
2086
|
+
framework: summary.primaryFramework,
|
|
2087
|
+
sourceFiles
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
// src/detection/asset-suggestion.ts
|
|
2092
|
+
function suggestAssetCard(scanResult) {
|
|
2093
|
+
const { detections, summary, inferredRiskFactors, suggestedTechnical } = scanResult;
|
|
2094
|
+
const name = generateName(summary.primaryFramework, suggestedTechnical?.type);
|
|
2095
|
+
const description = generateDescription(detections, summary);
|
|
2096
|
+
const components = collectComponents(detections);
|
|
2097
|
+
const sourceFiles = [...new Set(detections.map((d) => d.filePath))];
|
|
2098
|
+
const confidence = calculateOverallConfidence(detections);
|
|
2099
|
+
const basedOn = [...new Set(detections.map((d) => d.registryCard))];
|
|
2100
|
+
return {
|
|
2101
|
+
name,
|
|
2102
|
+
description,
|
|
2103
|
+
technical: {
|
|
2104
|
+
type: suggestedTechnical?.type ?? "framework",
|
|
2105
|
+
framework: suggestedTechnical?.framework ?? summary.primaryFramework ?? "unknown",
|
|
2106
|
+
components,
|
|
2107
|
+
sourceFiles
|
|
2108
|
+
},
|
|
2109
|
+
riskFactors: inferredRiskFactors,
|
|
2110
|
+
confidence,
|
|
2111
|
+
basedOn
|
|
2112
|
+
};
|
|
2113
|
+
}
|
|
2114
|
+
function generateName(primaryFramework, type) {
|
|
2115
|
+
if (!primaryFramework) {
|
|
2116
|
+
return "AI Asset";
|
|
2117
|
+
}
|
|
2118
|
+
const typeLabel = {
|
|
2119
|
+
model: "Model",
|
|
2120
|
+
agent: "Agent",
|
|
2121
|
+
api_client: "Integration",
|
|
2122
|
+
framework: "Application",
|
|
2123
|
+
pipeline: "Pipeline"
|
|
2124
|
+
};
|
|
2125
|
+
return `${primaryFramework} ${typeLabel[type ?? "framework"]}`;
|
|
2126
|
+
}
|
|
2127
|
+
function generateDescription(detections, summary) {
|
|
2128
|
+
const frameworks = Object.keys(summary.byFramework);
|
|
2129
|
+
const parts = [];
|
|
2130
|
+
if (frameworks.length === 1) {
|
|
2131
|
+
parts.push(`AI asset using ${frameworks[0]}.`);
|
|
2132
|
+
} else if (frameworks.length > 1) {
|
|
2133
|
+
parts.push(`AI asset using ${frameworks.slice(0, 3).join(", ")}${frameworks.length > 3 ? ` and ${frameworks.length - 3} more` : ""}.`);
|
|
2134
|
+
} else {
|
|
2135
|
+
parts.push("AI asset detected in codebase.");
|
|
2136
|
+
}
|
|
2137
|
+
const categories = summary.byCategory;
|
|
2138
|
+
if (categories.agent_framework > 0) {
|
|
2139
|
+
parts.push("Includes autonomous agent capabilities.");
|
|
2140
|
+
}
|
|
2141
|
+
if (categories.llm_provider > 0) {
|
|
2142
|
+
parts.push("Integrates with LLM providers.");
|
|
2143
|
+
}
|
|
2144
|
+
if (categories.ml_framework > 0) {
|
|
2145
|
+
parts.push("Uses machine learning frameworks.");
|
|
2146
|
+
}
|
|
2147
|
+
if (categories.model_file > 0) {
|
|
2148
|
+
parts.push("Contains model files.");
|
|
2149
|
+
}
|
|
2150
|
+
return parts.join(" ");
|
|
2151
|
+
}
|
|
2152
|
+
function collectComponents(detections) {
|
|
2153
|
+
const components = [];
|
|
2154
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2155
|
+
for (const detection of detections) {
|
|
2156
|
+
const key = `${detection.category}-${detection.framework}`;
|
|
2157
|
+
if (seen.has(key)) continue;
|
|
2158
|
+
seen.add(key);
|
|
2159
|
+
const component = {
|
|
2160
|
+
type: mapCategoryToComponentType(detection.category)
|
|
2161
|
+
};
|
|
2162
|
+
if (detection.category === "llm_provider") {
|
|
2163
|
+
component.provider = detection.framework;
|
|
2164
|
+
}
|
|
2165
|
+
components.push(component);
|
|
2166
|
+
}
|
|
2167
|
+
return components;
|
|
2168
|
+
}
|
|
2169
|
+
function mapCategoryToComponentType(category) {
|
|
2170
|
+
const mapping = {
|
|
2171
|
+
llm_provider: "llm",
|
|
2172
|
+
framework: "framework",
|
|
2173
|
+
agent_framework: "agent",
|
|
2174
|
+
ml_framework: "model",
|
|
2175
|
+
ml_ops: "mlops",
|
|
2176
|
+
model_file: "model"
|
|
2177
|
+
};
|
|
2178
|
+
return mapping[category] ?? category;
|
|
2179
|
+
}
|
|
2180
|
+
function calculateOverallConfidence(detections) {
|
|
2181
|
+
if (detections.length === 0) return "low";
|
|
2182
|
+
const highCount = detections.filter((d) => d.confidence === "high").length;
|
|
2183
|
+
const mediumCount = detections.filter((d) => d.confidence === "medium").length;
|
|
2184
|
+
if (highCount >= 3) return "high";
|
|
2185
|
+
if (highCount >= 1 && mediumCount >= 2) return "high";
|
|
2186
|
+
if (highCount >= 1 || mediumCount >= 3) return "medium";
|
|
2187
|
+
if (mediumCount >= 1) return "medium";
|
|
2188
|
+
return "low";
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
// src/detection/index.ts
|
|
2192
|
+
init_python();
|
|
2193
|
+
init_javascript();
|
|
2194
|
+
init_model_files();
|
|
2195
|
+
init_risk_indicators();
|
|
2196
|
+
|
|
2197
|
+
// src/utils.ts
|
|
2198
|
+
function formatDate(date) {
|
|
2199
|
+
return date.toISOString();
|
|
2200
|
+
}
|
|
2201
|
+
function parseDate(dateString) {
|
|
2202
|
+
return new Date(dateString);
|
|
2203
|
+
}
|
|
2204
|
+
function slugify(text) {
|
|
2205
|
+
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
|
|
2206
|
+
}
|
|
2207
|
+
export {
|
|
2208
|
+
ApprovalSchema,
|
|
2209
|
+
AssetCardSchema,
|
|
2210
|
+
ClassificationSchema,
|
|
2211
|
+
ConfidenceLevelSchema,
|
|
2212
|
+
ConstraintsSchema,
|
|
2213
|
+
ControlStatusSchema,
|
|
2214
|
+
DetectionStrategySchema,
|
|
2215
|
+
FrameworkCategorySchema,
|
|
2216
|
+
GovernanceSchema,
|
|
2217
|
+
IntentSchema,
|
|
2218
|
+
JurisdictionClassificationSchema,
|
|
2219
|
+
MODEL_EXTENSIONS,
|
|
2220
|
+
OwnerSchema,
|
|
2221
|
+
RiskFactorsSchema,
|
|
2222
|
+
TechnicalSchema,
|
|
2223
|
+
TrustworthinessCharacteristicSchema,
|
|
2224
|
+
TrustworthinessSchema,
|
|
2225
|
+
addJurisdiction,
|
|
2226
|
+
analyzeImports,
|
|
2227
|
+
applyImplicationChains,
|
|
2228
|
+
classifyRisk,
|
|
2229
|
+
clearRegistry,
|
|
2230
|
+
createAssetCard,
|
|
2231
|
+
createImplication,
|
|
2232
|
+
detectAnnotations,
|
|
2233
|
+
formatDate,
|
|
2234
|
+
generateAssetId,
|
|
2235
|
+
getAllPatterns,
|
|
2236
|
+
getPattern,
|
|
2237
|
+
getPatternsByCategory,
|
|
2238
|
+
getPatternsByLanguage,
|
|
2239
|
+
inferRiskFactors,
|
|
2240
|
+
initializePatterns,
|
|
2241
|
+
isModelFile,
|
|
2242
|
+
isRegistryInitialized,
|
|
2243
|
+
javascriptPatterns,
|
|
2244
|
+
linkAssetToTicket,
|
|
2245
|
+
loadAssetCard,
|
|
2246
|
+
matchPatterns,
|
|
2247
|
+
modelFilePatterns,
|
|
2248
|
+
parseDate,
|
|
2249
|
+
pythonPatterns,
|
|
2250
|
+
registerPattern,
|
|
2251
|
+
resetPatterns,
|
|
2252
|
+
riskIndicatorPatterns,
|
|
2253
|
+
saveAssetCard,
|
|
2254
|
+
scan,
|
|
2255
|
+
scanFileExtension,
|
|
2256
|
+
scanSync,
|
|
2257
|
+
slugify,
|
|
2258
|
+
suggestAssetCard,
|
|
2259
|
+
updateJurisdictionCompliance,
|
|
2260
|
+
validateAssetCard,
|
|
2261
|
+
validateGoldenThread,
|
|
2262
|
+
validateRiskFactors
|
|
2263
|
+
};
|
|
2264
|
+
//# sourceMappingURL=index.mjs.map
|