@euconform/core 1.2.0 → 1.4.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 +18 -0
- package/assets/datasets/crows-pairs-de.json +613 -0
- package/assets/datasets/crows-pairs-en.json +9055 -0
- package/dist/datasets/crows-pairs.d.ts +7 -0
- package/dist/datasets/crows-pairs.d.ts.map +1 -0
- package/dist/datasets/crows-pairs.js +41 -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 +192 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/inference/index.d.ts +1 -1
- package/dist/inference/index.d.ts.map +1 -1
- package/dist/inference/index.js +1 -1
- package/dist/inference/ollama-client.d.ts +11 -3
- package/dist/inference/ollama-client.d.ts.map +1 -1
- package/dist/inference/ollama-client.js +84 -84
- 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 +8 -3
- package/src/datasets/crows-pairs.ts +64 -0
- 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 +300 -0
- package/src/index.ts +1 -0
- package/src/inference/index.ts +6 -1
- package/src/inference/ollama-client.ts +111 -104
- 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/hash.test.ts +25 -0
- package/tests/evidence/markdown.test.ts +92 -0
- package/tests/evidence/output.test.ts +203 -0
- package/tests/evidence/spec-schemas.test.ts +316 -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 +4 -4
- package/tests/gpai-timeline.test.ts +2 -2
- 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
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EuConform Evidence Engine — Markdown Summary Generation
|
|
3
|
+
*
|
|
4
|
+
* Generates a human-readable markdown summary from ScanReport and AiBillOfMaterials.
|
|
5
|
+
* Pure function — no side effects, no filesystem operations.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
AiBillOfMaterials,
|
|
10
|
+
BomComponent,
|
|
11
|
+
ComplianceSignalGroup,
|
|
12
|
+
ScanReport,
|
|
13
|
+
ScanScope,
|
|
14
|
+
} from "./types";
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Helpers
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
type ComplianceArea = keyof ScanReport["complianceSignals"];
|
|
21
|
+
|
|
22
|
+
const COMPLIANCE_LABELS: Record<ComplianceArea, string> = {
|
|
23
|
+
disclosure: "AI Disclosure",
|
|
24
|
+
biasTesting: "Bias Testing",
|
|
25
|
+
reportingExports: "Reporting & Exports",
|
|
26
|
+
loggingMonitoring: "Logging & Monitoring",
|
|
27
|
+
humanOversight: "Human Oversight",
|
|
28
|
+
dataGovernance: "Data Governance",
|
|
29
|
+
incidentReporting: "Incident Reporting",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const STATUS_LABELS: Record<ComplianceSignalGroup["status"], string> = {
|
|
33
|
+
present: "Present",
|
|
34
|
+
partial: "Partial",
|
|
35
|
+
absent: "Absent",
|
|
36
|
+
unknown: "Unknown",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function bomKindLabel(kind: BomComponent["kind"]): string {
|
|
40
|
+
const labels: Record<BomComponent["kind"], string> = {
|
|
41
|
+
framework: "Framework",
|
|
42
|
+
runtime: "Runtime",
|
|
43
|
+
"inference-provider": "Inference Provider",
|
|
44
|
+
"ai-framework": "AI Framework",
|
|
45
|
+
model: "Model",
|
|
46
|
+
"vector-store": "Vector Store",
|
|
47
|
+
embedding: "Embedding",
|
|
48
|
+
dataset: "Dataset",
|
|
49
|
+
tool: "Tool",
|
|
50
|
+
};
|
|
51
|
+
return labels[kind];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function formatDate(iso: string): string {
|
|
55
|
+
try {
|
|
56
|
+
const d = new Date(iso);
|
|
57
|
+
return d.toISOString().split("T")[0] ?? iso;
|
|
58
|
+
} catch {
|
|
59
|
+
return iso;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Section builders
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
function buildHeader(report: ScanReport, scanScope: ScanScope): string {
|
|
68
|
+
const date = formatDate(report.generatedAt);
|
|
69
|
+
return [
|
|
70
|
+
"# EuConform Scan Report",
|
|
71
|
+
"",
|
|
72
|
+
"> **Disclaimer:** This is technical guidance only. It does not constitute legal advice.",
|
|
73
|
+
`> Generated by EuConform v${report.tool.version} on ${date}.`,
|
|
74
|
+
`> Scan scope: \`${scanScope}\`.`,
|
|
75
|
+
].join("\n");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildProjectOverview(report: ScanReport): string {
|
|
79
|
+
const lines = [
|
|
80
|
+
"## Project Overview",
|
|
81
|
+
"",
|
|
82
|
+
`- **Name:** ${report.target.name}`,
|
|
83
|
+
`- **Type:** ${report.target.repoType}`,
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
if (report.target.detectedStack.length > 0) {
|
|
87
|
+
lines.push(`- **Stack:** ${report.target.detectedStack.join(", ")}`);
|
|
88
|
+
} else {
|
|
89
|
+
lines.push("- **Stack:** Not detected");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return lines.join("\n");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildAiComponents(aibom: AiBillOfMaterials): string {
|
|
96
|
+
const lines = ["## AI Components Detected", ""];
|
|
97
|
+
|
|
98
|
+
if (aibom.components.length === 0) {
|
|
99
|
+
lines.push("No AI components detected.");
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
lines.push("| Component | Kind | Source |");
|
|
104
|
+
lines.push("|-----------|------|--------|");
|
|
105
|
+
|
|
106
|
+
for (const comp of aibom.components) {
|
|
107
|
+
lines.push(`| ${comp.name} | ${bomKindLabel(comp.kind)} | ${comp.source} |`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return lines.join("\n");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function buildComplianceSignals(report: ScanReport): string {
|
|
114
|
+
const lines = ["## Compliance Signals", ""];
|
|
115
|
+
lines.push("| Area | Status | Confidence |");
|
|
116
|
+
lines.push("|------|--------|------------|");
|
|
117
|
+
|
|
118
|
+
const areas = Object.keys(COMPLIANCE_LABELS) as ComplianceArea[];
|
|
119
|
+
|
|
120
|
+
for (const area of areas) {
|
|
121
|
+
const group = report.complianceSignals[area];
|
|
122
|
+
lines.push(
|
|
123
|
+
`| ${COMPLIANCE_LABELS[area]} | ${STATUS_LABELS[group.status]} | ${group.confidence} |`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function buildAssessmentHints(report: ScanReport): string {
|
|
131
|
+
const { riskIndicators, gpaiIndicators, possibleModes } = report.assessmentHints;
|
|
132
|
+
|
|
133
|
+
const lines = ["## Assessment Hints", ""];
|
|
134
|
+
|
|
135
|
+
if (gpaiIndicators.length === 0 && riskIndicators.length === 0 && possibleModes.length === 0) {
|
|
136
|
+
lines.push("No assessment hints generated (no AI detected).");
|
|
137
|
+
return lines.join("\n");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (possibleModes.length > 0) {
|
|
141
|
+
lines.push(`**Possible classification modes:** ${possibleModes.join(", ")}`);
|
|
142
|
+
lines.push("");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (gpaiIndicators.length > 0) {
|
|
146
|
+
lines.push("### GPAI Indicators");
|
|
147
|
+
lines.push("");
|
|
148
|
+
for (const hint of gpaiIndicators) {
|
|
149
|
+
const ref = hint.articleRef ? ` (${hint.articleRef})` : "";
|
|
150
|
+
lines.push(`- ${hint.hint}${ref}`);
|
|
151
|
+
}
|
|
152
|
+
lines.push("");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (riskIndicators.length > 0) {
|
|
156
|
+
lines.push("### Risk Indicators");
|
|
157
|
+
lines.push("");
|
|
158
|
+
for (const hint of riskIndicators) {
|
|
159
|
+
const ref = hint.articleRef ? ` (${hint.articleRef})` : "";
|
|
160
|
+
lines.push(`- ${hint.hint}${ref}`);
|
|
161
|
+
}
|
|
162
|
+
lines.push("");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return lines.join("\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function buildOpenQuestions(report: ScanReport): string {
|
|
169
|
+
const questions = report.assessmentHints.openQuestions;
|
|
170
|
+
const lines = ["## Open Questions", ""];
|
|
171
|
+
|
|
172
|
+
if (questions.length === 0) {
|
|
173
|
+
lines.push("No open questions.");
|
|
174
|
+
return lines.join("\n");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
questions.forEach((q, i) => {
|
|
178
|
+
lines.push(`${i + 1}. ${q}`);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
return lines.join("\n");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function buildRecommendedActions(report: ScanReport): string {
|
|
185
|
+
const lines = ["## Recommended Actions", ""];
|
|
186
|
+
|
|
187
|
+
if (report.recommendationSummary.length === 0) {
|
|
188
|
+
lines.push("No recommended actions.");
|
|
189
|
+
return lines.join("\n");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (const rec of report.recommendationSummary) {
|
|
193
|
+
lines.push(`- ${rec}`);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return lines.join("\n");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function buildFooter(): string {
|
|
200
|
+
return ["---", "*Full details: `euconform.report.json` -- AI BOM: `euconform.aibom.json`*"].join(
|
|
201
|
+
"\n"
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ---------------------------------------------------------------------------
|
|
206
|
+
// Main export
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
export function generateSummaryMarkdown(
|
|
210
|
+
report: ScanReport,
|
|
211
|
+
aibom: AiBillOfMaterials,
|
|
212
|
+
scanScope: ScanScope
|
|
213
|
+
): string {
|
|
214
|
+
const sections = [
|
|
215
|
+
buildHeader(report, scanScope),
|
|
216
|
+
buildProjectOverview(report),
|
|
217
|
+
buildAiComponents(aibom),
|
|
218
|
+
buildComplianceSignals(report),
|
|
219
|
+
buildAssessmentHints(report),
|
|
220
|
+
buildOpenQuestions(report),
|
|
221
|
+
buildRecommendedActions(report),
|
|
222
|
+
buildFooter(),
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
return `${sections.join("\n\n")}\n`;
|
|
226
|
+
}
|