@euconform/core 1.0.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +12 -0
- package/dist/evidence/bundle.d.ts +23 -0
- package/dist/evidence/bundle.d.ts.map +1 -0
- package/dist/evidence/bundle.js +44 -0
- package/dist/evidence/compliance-evaluation.d.ts +12 -0
- package/dist/evidence/compliance-evaluation.d.ts.map +1 -0
- package/dist/evidence/compliance-evaluation.js +78 -0
- package/dist/evidence/hash.d.ts +2 -0
- package/dist/evidence/hash.d.ts.map +1 -0
- package/dist/evidence/hash.js +4 -0
- package/dist/evidence/index.d.ts +13 -0
- package/dist/evidence/index.d.ts.map +1 -0
- package/dist/evidence/index.js +11 -0
- package/dist/evidence/markdown.d.ts +9 -0
- package/dist/evidence/markdown.d.ts.map +1 -0
- package/dist/evidence/markdown.js +169 -0
- package/dist/evidence/output.d.ts +13 -0
- package/dist/evidence/output.d.ts.map +1 -0
- package/dist/evidence/output.js +547 -0
- package/dist/evidence/types.d.ts +230 -0
- package/dist/evidence/types.d.ts.map +1 -0
- package/dist/evidence/types.js +7 -0
- package/dist/evidence/validate.d.ts +8 -0
- package/dist/evidence/validate.d.ts.map +1 -0
- package/dist/evidence/validate.js +175 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/inference/ollama-client.d.ts +3 -0
- package/dist/inference/ollama-client.d.ts.map +1 -1
- package/dist/inference/ollama-client.js +69 -71
- package/dist/legal-checks/annex-iv-report.d.ts +3 -0
- package/dist/legal-checks/annex-iv-report.d.ts.map +1 -1
- package/dist/legal-checks/annex-iv-report.js +1 -0
- package/dist/legal-checks/deadline-timeline.d.ts +57 -0
- package/dist/legal-checks/deadline-timeline.d.ts.map +1 -0
- package/dist/legal-checks/deadline-timeline.js +265 -0
- package/dist/legal-checks/gap-analysis.d.ts +48 -0
- package/dist/legal-checks/gap-analysis.d.ts.map +1 -0
- package/dist/legal-checks/gap-analysis.js +397 -0
- package/dist/legal-checks/gpai-classifier.d.ts +49 -0
- package/dist/legal-checks/gpai-classifier.d.ts.map +1 -0
- package/dist/legal-checks/gpai-classifier.js +197 -0
- package/dist/legal-checks/index.d.ts +6 -0
- package/dist/legal-checks/index.d.ts.map +1 -1
- package/dist/legal-checks/index.js +3 -0
- package/dist/scanner/aggregator.d.ts +7 -0
- package/dist/scanner/aggregator.d.ts.map +1 -0
- package/dist/scanner/aggregator.js +200 -0
- package/dist/scanner/detectors/ai-framework-detector.d.ts +3 -0
- package/dist/scanner/detectors/ai-framework-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/ai-framework-detector.js +74 -0
- package/dist/scanner/detectors/ai-provider-detector.d.ts +3 -0
- package/dist/scanner/detectors/ai-provider-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/ai-provider-detector.js +100 -0
- package/dist/scanner/detectors/compliance-detector.d.ts +3 -0
- package/dist/scanner/detectors/compliance-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/compliance-detector.js +201 -0
- package/dist/scanner/detectors/config-detector.d.ts +3 -0
- package/dist/scanner/detectors/config-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/config-detector.js +248 -0
- package/dist/scanner/detectors/framework-detector.d.ts +3 -0
- package/dist/scanner/detectors/framework-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/framework-detector.js +141 -0
- package/dist/scanner/detectors/index.d.ts +8 -0
- package/dist/scanner/detectors/index.d.ts.map +1 -0
- package/dist/scanner/detectors/index.js +37 -0
- package/dist/scanner/detectors/local-inference-detector.d.ts +3 -0
- package/dist/scanner/detectors/local-inference-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/local-inference-detector.js +93 -0
- package/dist/scanner/detectors/markdown-detector.d.ts +3 -0
- package/dist/scanner/detectors/markdown-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/markdown-detector.js +139 -0
- package/dist/scanner/detectors/package-json-detector.d.ts +3 -0
- package/dist/scanner/detectors/package-json-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/package-json-detector.js +166 -0
- package/dist/scanner/detectors/rag-detector.d.ts +3 -0
- package/dist/scanner/detectors/rag-detector.d.ts.map +1 -0
- package/dist/scanner/detectors/rag-detector.js +132 -0
- package/dist/scanner/detectors/shared.d.ts +18 -0
- package/dist/scanner/detectors/shared.d.ts.map +1 -0
- package/dist/scanner/detectors/shared.js +36 -0
- package/dist/scanner/discovery.d.ts +14 -0
- package/dist/scanner/discovery.d.ts.map +1 -0
- package/dist/scanner/discovery.js +235 -0
- package/dist/scanner/index.d.ts +9 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +8 -0
- package/package.json +6 -3
- package/src/evidence/bundle.ts +65 -0
- package/src/evidence/compliance-evaluation.ts +114 -0
- package/src/evidence/hash.ts +5 -0
- package/src/evidence/index.ts +51 -0
- package/src/evidence/markdown.ts +226 -0
- package/src/evidence/output.ts +717 -0
- package/src/evidence/types.ts +329 -0
- package/src/evidence/validate.ts +270 -0
- package/src/index.ts +25 -0
- package/src/inference/ollama-client.ts +93 -86
- package/src/legal-checks/annex-iv-report.ts +4 -0
- package/src/legal-checks/deadline-timeline.ts +313 -0
- package/src/legal-checks/gap-analysis.ts +454 -0
- package/src/legal-checks/gpai-classifier.ts +281 -0
- package/src/legal-checks/index.ts +33 -0
- package/src/scanner/aggregator.ts +258 -0
- package/src/scanner/detectors/ai-framework-detector.ts +94 -0
- package/src/scanner/detectors/ai-provider-detector.ts +135 -0
- package/src/scanner/detectors/compliance-detector.ts +232 -0
- package/src/scanner/detectors/config-detector.ts +316 -0
- package/src/scanner/detectors/framework-detector.ts +163 -0
- package/src/scanner/detectors/index.ts +40 -0
- package/src/scanner/detectors/local-inference-detector.ts +124 -0
- package/src/scanner/detectors/markdown-detector.ts +176 -0
- package/src/scanner/detectors/package-json-detector.ts +202 -0
- package/src/scanner/detectors/rag-detector.ts +162 -0
- package/src/scanner/detectors/shared.ts +45 -0
- package/src/scanner/discovery.ts +290 -0
- package/src/scanner/index.ts +9 -0
- package/tests/evidence/bundle.test.ts +128 -0
- package/tests/evidence/ecef-schemas.test.ts +316 -0
- package/tests/evidence/hash.test.ts +25 -0
- package/tests/evidence/markdown.test.ts +92 -0
- package/tests/evidence/output.test.ts +203 -0
- package/tests/fixtures/compliance-good/README.md +14 -0
- package/tests/fixtures/compliance-good/lib/ai-service.ts +17 -0
- package/tests/fixtures/compliance-good/lib/review-flow.ts +11 -0
- package/tests/fixtures/compliance-good/package.json +10 -0
- package/tests/fixtures/compliance-good/tests/bias-check.test.ts +13 -0
- package/tests/fixtures/nextjs-openai/README.md +5 -0
- package/tests/fixtures/nextjs-openai/app/page.tsx +11 -0
- package/tests/fixtures/nextjs-openai/package.json +9 -0
- package/tests/fixtures/ollama-rag/.env.example +2 -0
- package/tests/fixtures/ollama-rag/docker-compose.yml +9 -0
- package/tests/fixtures/ollama-rag/package.json +9 -0
- package/tests/fixtures/ollama-rag/server.ts +21 -0
- package/tests/fixtures/plain-webapp/README.md +3 -0
- package/tests/fixtures/plain-webapp/index.js +5 -0
- package/tests/fixtures/plain-webapp/package.json +8 -0
- package/tests/gpai-classifier.test.ts +125 -0
- package/tests/gpai-timeline.test.ts +55 -0
- package/tests/scanner/aggregator.test.ts +122 -0
- package/tests/scanner/detectors.test.ts +274 -0
- package/tests/scanner/discovery.test.ts +87 -0
- package/vitest.config.ts +1 -0
- package/.turbo/turbo-check-types.log +0 -4
- package/.turbo/turbo-test.log +0 -364
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -3282
- package/coverage/coverage-final.json +0 -20
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -161
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/fairness-metrics.ts.html +0 -1579
- package/coverage/src/index.html +0 -161
- package/coverage/src/index.ts.html +0 -535
- package/coverage/src/inference/browser-inference.ts.html +0 -859
- package/coverage/src/inference/capability-detection.ts.html +0 -2227
- package/coverage/src/inference/index.html +0 -176
- package/coverage/src/inference/index.ts.html +0 -553
- package/coverage/src/inference/inference-factory.ts.html +0 -751
- package/coverage/src/inference/ollama-client.ts.html +0 -1627
- package/coverage/src/legal-checks/annex-iv-report.ts.html +0 -556
- package/coverage/src/legal-checks/bias-metrics.ts.html +0 -1855
- package/coverage/src/legal-checks/data-governance.ts.html +0 -529
- package/coverage/src/legal-checks/human-oversight-logging.ts.html +0 -490
- package/coverage/src/legal-checks/index.html +0 -206
- package/coverage/src/legal-checks/index.ts.html +0 -250
- package/coverage/src/legal-checks/risk-classifier.ts.html +0 -940
- package/coverage/src/legal-checks/robustness-transparency.ts.html +0 -571
- package/coverage/src/metrics/crows-pairs-bias.ts.html +0 -820
- package/coverage/src/metrics/index.html +0 -146
- package/coverage/src/metrics/index.ts.html +0 -151
- package/coverage/src/metrics/stereotype-bias.ts.html +0 -886
- package/coverage/src/risk-engine.ts.html +0 -1660
- package/coverage/src/types.ts.html +0 -547
- package/dist/legal-checks/disclaimer.d.ts +0 -2
- package/dist/legal-checks/disclaimer.d.ts.map +0 -1
- package/dist/legal-checks/disclaimer.js +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
const rules = [
|
|
2
|
+
// --- compliance-disclosure ---
|
|
3
|
+
{
|
|
4
|
+
id: "compliance-disclosure-readme",
|
|
5
|
+
name: "AI disclosure in README",
|
|
6
|
+
category: "compliance-disclosure",
|
|
7
|
+
pattern: /\b(?:artificial\s+intelligence|machine\s+learning|AI[- ]powered|AI[- ]generated|uses?\s+AI|deep\s+learning|neural\s+network|large\s+language\s+model|LLM)\b/i,
|
|
8
|
+
confidence: "low",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "compliance-disclosure-transparency",
|
|
12
|
+
name: "Transparency notice",
|
|
13
|
+
category: "compliance-disclosure",
|
|
14
|
+
pattern: /\b(?:transparency\s+notice|AI\s+disclosure|generated\s+by\s+AI)\b/i,
|
|
15
|
+
confidence: "medium",
|
|
16
|
+
},
|
|
17
|
+
// --- Model card ---
|
|
18
|
+
{
|
|
19
|
+
id: "compliance-disclosure-model-card",
|
|
20
|
+
name: "Model card documentation",
|
|
21
|
+
category: "compliance-disclosure",
|
|
22
|
+
pattern: /^#{1,3}\s+Model\s+Card\b/i,
|
|
23
|
+
confidence: "medium",
|
|
24
|
+
sectionHeading: true,
|
|
25
|
+
},
|
|
26
|
+
// --- compliance-data ---
|
|
27
|
+
{
|
|
28
|
+
id: "compliance-data-docs",
|
|
29
|
+
name: "Data governance documentation",
|
|
30
|
+
category: "compliance-data",
|
|
31
|
+
pattern: /^#{1,3}\s+(?:Data\s+(?:Sources?|Governance|Quality|Lineage)|Training\s+Data)\b/i,
|
|
32
|
+
confidence: "medium",
|
|
33
|
+
sectionHeading: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "compliance-data-reference",
|
|
37
|
+
name: "Data source references",
|
|
38
|
+
category: "compliance-data",
|
|
39
|
+
pattern: /\b(?:training\s+data|data\s+sources?|dataset\s+documentation)\b/i,
|
|
40
|
+
confidence: "low",
|
|
41
|
+
},
|
|
42
|
+
// --- Privacy / GDPR ---
|
|
43
|
+
{
|
|
44
|
+
id: "compliance-data-privacy",
|
|
45
|
+
name: "Privacy policy reference",
|
|
46
|
+
category: "compliance-data",
|
|
47
|
+
pattern: /\b(?:privacy\s+policy|GDPR|data\s+protection|DSGVO)\b/i,
|
|
48
|
+
confidence: "medium",
|
|
49
|
+
},
|
|
50
|
+
// --- License / AI-specific ---
|
|
51
|
+
{
|
|
52
|
+
id: "compliance-disclosure-license",
|
|
53
|
+
name: "AI-relevant license terms",
|
|
54
|
+
category: "compliance-disclosure",
|
|
55
|
+
pattern: /\b(?:model\s+license|AI\s+license|responsible\s+AI|acceptable\s+use\s+policy|RAIL\s+license)\b/i,
|
|
56
|
+
confidence: "medium",
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// File filtering
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
/** Files that should always be skipped unless they contain AI-specific content */
|
|
63
|
+
const SKIP_BASENAMES = new Set([
|
|
64
|
+
"changelog.md",
|
|
65
|
+
"changes.md",
|
|
66
|
+
"history.md",
|
|
67
|
+
"contributing.md",
|
|
68
|
+
"code_of_conduct.md",
|
|
69
|
+
]);
|
|
70
|
+
/** Only process these docs-level paths */
|
|
71
|
+
function isRelevantMarkdown(relativePath) {
|
|
72
|
+
const lower = relativePath.toLowerCase();
|
|
73
|
+
const basename = lower.split("/").pop() ?? "";
|
|
74
|
+
// Always process README files at any level
|
|
75
|
+
if (basename.startsWith("readme"))
|
|
76
|
+
return true;
|
|
77
|
+
// Process files inside docs/ directories
|
|
78
|
+
if (lower.includes("/docs/") || lower.startsWith("docs/")) {
|
|
79
|
+
return !SKIP_BASENAMES.has(basename);
|
|
80
|
+
}
|
|
81
|
+
// For other markdown files, skip known non-relevant ones
|
|
82
|
+
if (SKIP_BASENAMES.has(basename))
|
|
83
|
+
return false;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Detector
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
function gatherMarkdownEvidence(rule, lines, filePath) {
|
|
90
|
+
const evidence = [];
|
|
91
|
+
for (let i = 0; i < lines.length; i++) {
|
|
92
|
+
const line = lines[i];
|
|
93
|
+
if (!line)
|
|
94
|
+
continue;
|
|
95
|
+
if (rule.sectionHeading && !line.startsWith("#"))
|
|
96
|
+
continue;
|
|
97
|
+
if (rule.pattern.test(line)) {
|
|
98
|
+
evidence.push({ file: filePath, line: i + 1, snippet: line.trim().slice(0, 120) });
|
|
99
|
+
if (evidence.length >= 5)
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return evidence;
|
|
104
|
+
}
|
|
105
|
+
function isSkippableGenericContent(basename, evidence) {
|
|
106
|
+
if (!SKIP_BASENAMES.has(basename))
|
|
107
|
+
return false;
|
|
108
|
+
return !evidence.some((e) => /\bAI\b|\bML\b|\bmodel\b|\binference\b/i.test(e.snippet));
|
|
109
|
+
}
|
|
110
|
+
export function detectMarkdown(ctx) {
|
|
111
|
+
const { file } = ctx;
|
|
112
|
+
if (file.extension !== ".md")
|
|
113
|
+
return [];
|
|
114
|
+
if (!isRelevantMarkdown(file.relativePath))
|
|
115
|
+
return [];
|
|
116
|
+
const signalMap = new Map();
|
|
117
|
+
const basename = file.relativePath.toLowerCase().split("/").pop() ?? "";
|
|
118
|
+
for (const rule of rules) {
|
|
119
|
+
const evidence = gatherMarkdownEvidence(rule, ctx.lines, file.relativePath);
|
|
120
|
+
if (evidence.length === 0)
|
|
121
|
+
continue;
|
|
122
|
+
if (isSkippableGenericContent(basename, evidence))
|
|
123
|
+
continue;
|
|
124
|
+
const existing = signalMap.get(rule.id);
|
|
125
|
+
if (existing) {
|
|
126
|
+
existing.evidence.push(...evidence);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
signalMap.set(rule.id, {
|
|
130
|
+
id: rule.id,
|
|
131
|
+
name: rule.name,
|
|
132
|
+
category: rule.category,
|
|
133
|
+
confidence: rule.confidence,
|
|
134
|
+
evidence,
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return Array.from(signalMap.values());
|
|
139
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-json-detector.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/package-json-detector.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAkB,MAAM,sBAAsB,CAAC;AA6E5F,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CAY/E"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { escapeRegex } from "./shared";
|
|
3
|
+
const AI_PACKAGES = {
|
|
4
|
+
// Providers
|
|
5
|
+
openai: { category: "ai-provider", label: "OpenAI SDK" },
|
|
6
|
+
"@anthropic-ai/sdk": { category: "ai-provider", label: "Anthropic SDK" },
|
|
7
|
+
"cohere-ai": { category: "ai-provider", label: "Cohere SDK" },
|
|
8
|
+
"@google/generative-ai": { category: "ai-provider", label: "Google Generative AI" },
|
|
9
|
+
"@mistralai/mistralai": { category: "ai-provider", label: "Mistral AI SDK" },
|
|
10
|
+
// Frameworks
|
|
11
|
+
langchain: { category: "ai-framework", label: "LangChain" },
|
|
12
|
+
"@langchain/core": { category: "ai-framework", label: "LangChain Core" },
|
|
13
|
+
llamaindex: { category: "ai-framework", label: "LlamaIndex" },
|
|
14
|
+
"@xenova/transformers": { category: "ai-framework", label: "Transformers.js" },
|
|
15
|
+
ai: { category: "ai-framework", label: "Vercel AI SDK" },
|
|
16
|
+
"@huggingface/inference": { category: "ai-framework", label: "HuggingFace Inference" },
|
|
17
|
+
// Local inference
|
|
18
|
+
ollama: { category: "local-inference", label: "Ollama" },
|
|
19
|
+
"@ollama/ollama": { category: "local-inference", label: "Ollama SDK" },
|
|
20
|
+
// RAG / Vector
|
|
21
|
+
chromadb: { category: "rag", label: "ChromaDB" },
|
|
22
|
+
"@pinecone-database/pinecone": { category: "rag", label: "Pinecone" },
|
|
23
|
+
"weaviate-client": { category: "rag", label: "Weaviate" },
|
|
24
|
+
"@qdrant/js-client-rest": { category: "rag", label: "Qdrant" },
|
|
25
|
+
pgvector: { category: "rag", label: "pgvector" },
|
|
26
|
+
// Bias / Eval
|
|
27
|
+
"@euconform/core": { category: "compliance-bias", label: "EuConform Core" },
|
|
28
|
+
};
|
|
29
|
+
const FRAMEWORK_PACKAGES = {
|
|
30
|
+
next: { category: "framework", label: "Next.js" },
|
|
31
|
+
react: { category: "framework", label: "React" },
|
|
32
|
+
express: { category: "framework", label: "Express" },
|
|
33
|
+
fastify: { category: "framework", label: "Fastify" },
|
|
34
|
+
"@nestjs/core": { category: "framework", label: "NestJS" },
|
|
35
|
+
hono: { category: "framework", label: "Hono" },
|
|
36
|
+
elysia: { category: "framework", label: "Elysia" },
|
|
37
|
+
};
|
|
38
|
+
const ALL_PACKAGES = {
|
|
39
|
+
...AI_PACKAGES,
|
|
40
|
+
...FRAMEWORK_PACKAGES,
|
|
41
|
+
};
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Helpers
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
const PACKAGE_JSON_NAMES = new Set([
|
|
46
|
+
"package.json",
|
|
47
|
+
"pnpm-lock.yaml",
|
|
48
|
+
"package-lock.json",
|
|
49
|
+
"yarn.lock",
|
|
50
|
+
]);
|
|
51
|
+
function isPackageJsonFile(relativePath) {
|
|
52
|
+
return PACKAGE_JSON_NAMES.has(basename(relativePath));
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Detector
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
export function detectPackageJsonSignals(ctx) {
|
|
58
|
+
const { file } = ctx;
|
|
59
|
+
if (!isPackageJsonFile(file.relativePath))
|
|
60
|
+
return [];
|
|
61
|
+
const fileName = basename(file.relativePath);
|
|
62
|
+
if (fileName === "package.json") {
|
|
63
|
+
return detectFromPackageJson(file.relativePath, file.content);
|
|
64
|
+
}
|
|
65
|
+
// Lock files — scan for known package name strings
|
|
66
|
+
return detectFromLockFile(file.relativePath, file.content);
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// package.json detection
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
function detectFromPackageJson(filePath, content) {
|
|
72
|
+
let parsed;
|
|
73
|
+
try {
|
|
74
|
+
parsed = JSON.parse(content);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
const signals = [];
|
|
80
|
+
const deps = {
|
|
81
|
+
...parsed.dependencies,
|
|
82
|
+
...parsed.devDependencies,
|
|
83
|
+
};
|
|
84
|
+
for (const [pkg, info] of Object.entries(ALL_PACKAGES)) {
|
|
85
|
+
if (pkg in deps) {
|
|
86
|
+
const version = deps[pkg] ?? "unknown";
|
|
87
|
+
signals.push({
|
|
88
|
+
id: `${info.category}-${pkg.replace(/[@/]/g, "").replace(/\s/g, "-")}`,
|
|
89
|
+
name: info.label,
|
|
90
|
+
category: info.category,
|
|
91
|
+
confidence: "high",
|
|
92
|
+
evidence: [
|
|
93
|
+
{
|
|
94
|
+
file: filePath,
|
|
95
|
+
snippet: `"${pkg}": "${version}"`,
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
// Monorepo signals
|
|
102
|
+
if (parsed.workspaces) {
|
|
103
|
+
signals.push({
|
|
104
|
+
id: "runtime-monorepo-workspaces",
|
|
105
|
+
name: "Monorepo (workspaces)",
|
|
106
|
+
category: "runtime",
|
|
107
|
+
confidence: "high",
|
|
108
|
+
evidence: [
|
|
109
|
+
{
|
|
110
|
+
file: filePath,
|
|
111
|
+
snippet: `"workspaces": ${JSON.stringify(parsed.workspaces).slice(0, 120)}`,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const devDeps = parsed.devDependencies;
|
|
117
|
+
if (devDeps && "turbo" in devDeps) {
|
|
118
|
+
signals.push({
|
|
119
|
+
id: "runtime-monorepo-turbo",
|
|
120
|
+
name: "Monorepo (Turborepo)",
|
|
121
|
+
category: "runtime",
|
|
122
|
+
confidence: "high",
|
|
123
|
+
evidence: [
|
|
124
|
+
{
|
|
125
|
+
file: filePath,
|
|
126
|
+
snippet: `"turbo": "${devDeps.turbo}"`,
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return signals;
|
|
132
|
+
}
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
// Lock-file detection (string search, no full parse)
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// Pre-compiled lock-file patterns — avoids RegExp construction on every call
|
|
137
|
+
const LOCK_FILE_PATTERNS = new Map(Object.keys(AI_PACKAGES).map((pkg) => [pkg, new RegExp(`["'/]${escapeRegex(pkg)}["'/@:]`)]));
|
|
138
|
+
function detectFromLockFile(filePath, content) {
|
|
139
|
+
const signals = [];
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
for (const [pkg, info] of Object.entries(AI_PACKAGES)) {
|
|
142
|
+
if (seen.has(pkg))
|
|
143
|
+
continue;
|
|
144
|
+
// Use boundary-aware pattern to avoid false positives on short names
|
|
145
|
+
// Lock files quote package names or use them as path segments
|
|
146
|
+
const pattern = LOCK_FILE_PATTERNS.get(pkg);
|
|
147
|
+
if (!pattern)
|
|
148
|
+
continue;
|
|
149
|
+
if (pattern.test(content)) {
|
|
150
|
+
seen.add(pkg);
|
|
151
|
+
signals.push({
|
|
152
|
+
id: `${info.category}-${pkg.replace(/[@/]/g, "").replace(/\s/g, "-")}`,
|
|
153
|
+
name: info.label,
|
|
154
|
+
category: info.category,
|
|
155
|
+
confidence: "medium",
|
|
156
|
+
evidence: [
|
|
157
|
+
{
|
|
158
|
+
file: filePath,
|
|
159
|
+
snippet: `Found "${pkg}" in lock file`,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return signals;
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rag-detector.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/rag-detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EACd,eAAe,EAEhB,MAAM,sBAAsB,CAAC;AAsH9B,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,GAAG,cAAc,EAAE,CAsCvE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { SOURCE_EXTENSIONS, higherConfidence } from "./shared";
|
|
2
|
+
// Explicit vector store imports (high confidence)
|
|
3
|
+
const IMPORT_RULES = [
|
|
4
|
+
{
|
|
5
|
+
id: "rag-chromadb",
|
|
6
|
+
name: "ChromaDB",
|
|
7
|
+
pattern: /(?:from\s+['"]chromadb['"]|require\s*\(\s*['"]chromadb['"])/,
|
|
8
|
+
confidence: "high",
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
id: "rag-pinecone",
|
|
12
|
+
name: "Pinecone",
|
|
13
|
+
pattern: /(?:from\s+['"]@pinecone-database\/pinecone['"]|require\s*\(\s*['"]@pinecone-database\/pinecone['"])/,
|
|
14
|
+
confidence: "high",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "rag-weaviate",
|
|
18
|
+
name: "Weaviate",
|
|
19
|
+
pattern: /(?:from\s+['"]weaviate-client['"]|require\s*\(\s*['"]weaviate-client['"])/,
|
|
20
|
+
confidence: "high",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: "rag-qdrant",
|
|
24
|
+
name: "Qdrant",
|
|
25
|
+
pattern: /(?:from\s+['"]@qdrant\/js-client-rest['"]|require\s*\(\s*['"]@qdrant\/js-client-rest['"])/,
|
|
26
|
+
confidence: "high",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: "rag-pgvector",
|
|
30
|
+
name: "pgvector",
|
|
31
|
+
pattern: /(?:from\s+['"]pgvector['"]|require\s*\(\s*['"]pgvector['"])/,
|
|
32
|
+
confidence: "high",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "rag-faiss",
|
|
36
|
+
name: "FAISS",
|
|
37
|
+
pattern: /(?:from\s+['"]faiss-node['"]|require\s*\(\s*['"]faiss-node['"])/,
|
|
38
|
+
confidence: "high",
|
|
39
|
+
},
|
|
40
|
+
];
|
|
41
|
+
// Function call / usage patterns (medium confidence)
|
|
42
|
+
const USAGE_RULES = [
|
|
43
|
+
{
|
|
44
|
+
id: "rag-embedding-call",
|
|
45
|
+
name: "Embedding function call",
|
|
46
|
+
pattern: /\.(?:createEmbedding|embedDocuments|embedQuery|embed)\s*\(/,
|
|
47
|
+
confidence: "medium",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "rag-retriever-pattern",
|
|
51
|
+
name: "Retriever pattern",
|
|
52
|
+
pattern: /\.(?:asRetriever|getRelevantDocuments|similaritySearch|similaritySearchWithScore)\s*\(/,
|
|
53
|
+
confidence: "medium",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "rag-vectorstore-usage",
|
|
57
|
+
name: "Vector store usage",
|
|
58
|
+
pattern: /(?:VectorStore|vectorStore|fromDocuments|fromTexts|addDocuments)\s*\(/,
|
|
59
|
+
confidence: "medium",
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
// Keyword patterns (low confidence)
|
|
63
|
+
const KEYWORD_RULES = [
|
|
64
|
+
{
|
|
65
|
+
id: "rag-keyword-embedding",
|
|
66
|
+
name: "Embedding keyword reference",
|
|
67
|
+
pattern: /\b(?:text[_-]?embedding|embedding[_-]?(?:model|vector|dimension|size)|openai.*embedding|embedding[_-]?api)\b/i,
|
|
68
|
+
confidence: "low",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "rag-keyword-vector",
|
|
72
|
+
name: "Vector keyword reference",
|
|
73
|
+
pattern: /\b(?:vector(?:Store|DB|Database|Index))\b/,
|
|
74
|
+
confidence: "low",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "rag-keyword-retriever",
|
|
78
|
+
name: "Retriever keyword reference",
|
|
79
|
+
pattern: /\bretriever\b/i,
|
|
80
|
+
confidence: "low",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "rag-keyword-similarity",
|
|
84
|
+
name: "Similarity search keyword",
|
|
85
|
+
pattern: /\bsimilarity_search\b/,
|
|
86
|
+
confidence: "low",
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Combined rules (hoisted to module scope to avoid per-call reconstruction)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
const ALL_RULES = [...IMPORT_RULES, ...USAGE_RULES, ...KEYWORD_RULES];
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Detector
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
export function detectRagSignals(ctx) {
|
|
97
|
+
const { file } = ctx;
|
|
98
|
+
if (!SOURCE_EXTENSIONS.has(file.extension))
|
|
99
|
+
return [];
|
|
100
|
+
const lines = ctx.lines;
|
|
101
|
+
const signalMap = new Map();
|
|
102
|
+
for (let i = 0; i < lines.length; i++) {
|
|
103
|
+
const line = lines[i];
|
|
104
|
+
if (!line)
|
|
105
|
+
continue;
|
|
106
|
+
const lineNum = i + 1;
|
|
107
|
+
for (const rule of ALL_RULES) {
|
|
108
|
+
if (rule.pattern.test(line)) {
|
|
109
|
+
const evidence = {
|
|
110
|
+
file: file.relativePath,
|
|
111
|
+
line: lineNum,
|
|
112
|
+
snippet: line.trim().slice(0, 200),
|
|
113
|
+
};
|
|
114
|
+
const existing = signalMap.get(rule.id);
|
|
115
|
+
if (existing) {
|
|
116
|
+
existing.evidence.push(evidence);
|
|
117
|
+
existing.confidence = higherConfidence(existing.confidence, rule.confidence);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
signalMap.set(rule.id, {
|
|
121
|
+
id: rule.id,
|
|
122
|
+
name: rule.name,
|
|
123
|
+
category: "rag",
|
|
124
|
+
confidence: rule.confidence,
|
|
125
|
+
evidence: [evidence],
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return Array.from(signalMap.values());
|
|
132
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ConfidenceLevel } from "../../evidence/types";
|
|
2
|
+
/** Source-code extensions used by ai-provider, ai-framework, rag, compliance detectors */
|
|
3
|
+
export declare const SOURCE_EXTENSIONS: Set<string>;
|
|
4
|
+
/** Extended set including config formats, used by framework and local-inference detectors */
|
|
5
|
+
export declare const EXTENDED_EXTENSIONS: Set<string>;
|
|
6
|
+
/** Standardized snippet truncation length */
|
|
7
|
+
export declare const MAX_SNIPPET_LENGTH = 200;
|
|
8
|
+
/** Numeric ranking for confidence levels (higher = more confident) */
|
|
9
|
+
export declare const CONFIDENCE_RANK: Record<ConfidenceLevel, number>;
|
|
10
|
+
/** Return the higher of two confidence levels */
|
|
11
|
+
export declare function higherConfidence(a: ConfidenceLevel, b: ConfidenceLevel): ConfidenceLevel;
|
|
12
|
+
/** Escape special regex characters in a string */
|
|
13
|
+
export declare function escapeRegex(str: string): string;
|
|
14
|
+
/** Check whether an extension is a standard source file */
|
|
15
|
+
export declare function isSourceFile(ext: string): boolean;
|
|
16
|
+
/** Check whether an extension is in the extended (source + config) set */
|
|
17
|
+
export declare function isExtendedSourceFile(ext: string): boolean;
|
|
18
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/scanner/detectors/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,0FAA0F;AAC1F,eAAO,MAAM,iBAAiB,aAA0C,CAAC;AAEzE,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,aAQ9B,CAAC;AAEH,6CAA6C;AAC7C,eAAO,MAAM,kBAAkB,MAAM,CAAC;AAEtC,sEAAsE;AACtE,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAI3D,CAAC;AAEF,iDAAiD;AACjD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CAExF;AAED,kDAAkD;AAClD,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,0EAA0E;AAC1E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEzD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/** Source-code extensions used by ai-provider, ai-framework, rag, compliance detectors */
|
|
2
|
+
export const SOURCE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
3
|
+
/** Extended set including config formats, used by framework and local-inference detectors */
|
|
4
|
+
export const EXTENDED_EXTENSIONS = new Set([
|
|
5
|
+
".ts",
|
|
6
|
+
".tsx",
|
|
7
|
+
".js",
|
|
8
|
+
".jsx",
|
|
9
|
+
".json",
|
|
10
|
+
".yaml",
|
|
11
|
+
".yml",
|
|
12
|
+
]);
|
|
13
|
+
/** Standardized snippet truncation length */
|
|
14
|
+
export const MAX_SNIPPET_LENGTH = 200;
|
|
15
|
+
/** Numeric ranking for confidence levels (higher = more confident) */
|
|
16
|
+
export const CONFIDENCE_RANK = {
|
|
17
|
+
high: 2,
|
|
18
|
+
medium: 1,
|
|
19
|
+
low: 0,
|
|
20
|
+
};
|
|
21
|
+
/** Return the higher of two confidence levels */
|
|
22
|
+
export function higherConfidence(a, b) {
|
|
23
|
+
return CONFIDENCE_RANK[a] >= CONFIDENCE_RANK[b] ? a : b;
|
|
24
|
+
}
|
|
25
|
+
/** Escape special regex characters in a string */
|
|
26
|
+
export function escapeRegex(str) {
|
|
27
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28
|
+
}
|
|
29
|
+
/** Check whether an extension is a standard source file */
|
|
30
|
+
export function isSourceFile(ext) {
|
|
31
|
+
return SOURCE_EXTENSIONS.has(ext);
|
|
32
|
+
}
|
|
33
|
+
/** Check whether an extension is in the extended (source + config) set */
|
|
34
|
+
export function isExtendedSourceFile(ext) {
|
|
35
|
+
return EXTENDED_EXTENSIONS.has(ext);
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File discovery for the EuConform scanner.
|
|
3
|
+
*
|
|
4
|
+
* Walks a target directory, respects .gitignore, filters by extension
|
|
5
|
+
* and named files, and returns file contents for pattern matching.
|
|
6
|
+
*/
|
|
7
|
+
import type { FileProvenance, ScanFile, ScanOptions } from "../evidence/types";
|
|
8
|
+
export declare function classifyFileProvenance(relativePath: string): FileProvenance;
|
|
9
|
+
export interface DiscoveryResult {
|
|
10
|
+
files: ScanFile[];
|
|
11
|
+
skippedCount: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function discoverFiles(options: ScanOptions): Promise<DiscoveryResult>;
|
|
14
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/scanner/discovery.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW,EAAa,MAAM,mBAAmB,CAAC;AAsG1F,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,cAAc,CAoC3E;AAeD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAiFD,wBAAsB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CA0ClF"}
|