@euconform/core 1.3.0 → 1.5.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 +24 -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/output.d.ts.map +1 -1
- package/dist/evidence/output.js +1 -0
- package/dist/evidence/types.d.ts +8 -2
- package/dist/evidence/types.d.ts.map +1 -1
- package/dist/evidence/validate.d.ts.map +1 -1
- package/dist/evidence/validate.js +59 -39
- 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 +9 -3
- package/dist/inference/ollama-client.d.ts.map +1 -1
- package/dist/inference/ollama-client.js +23 -11
- package/dist/sbom/component-mapper.d.ts +26 -0
- package/dist/sbom/component-mapper.d.ts.map +1 -0
- package/dist/sbom/component-mapper.js +83 -0
- package/dist/sbom/cyclonedx-import.d.ts +34 -0
- package/dist/sbom/cyclonedx-import.d.ts.map +1 -0
- package/dist/sbom/cyclonedx-import.js +131 -0
- package/dist/sbom/index.d.ts +6 -0
- package/dist/sbom/index.d.ts.map +1 -0
- package/dist/sbom/index.js +4 -0
- package/dist/sbom/known-packages.d.ts +13 -0
- package/dist/sbom/known-packages.d.ts.map +1 -0
- package/dist/sbom/known-packages.js +129 -0
- package/dist/sbom/purl.d.ts +14 -0
- package/dist/sbom/purl.d.ts.map +1 -0
- package/dist/sbom/purl.js +56 -0
- package/dist/sbom/types.d.ts +39 -0
- package/dist/sbom/types.d.ts.map +1 -0
- package/dist/sbom/types.js +5 -0
- package/dist/validation/index.d.ts +2 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +1 -0
- package/dist/validation/schema-validator.d.ts +18 -0
- package/dist/validation/schema-validator.d.ts.map +1 -0
- package/dist/validation/schema-validator.js +99 -0
- package/package.json +8 -2
- package/src/datasets/crows-pairs.ts +64 -0
- package/src/evidence/output.ts +1 -0
- package/src/evidence/types.ts +9 -2
- package/src/evidence/validate.ts +107 -70
- package/src/index.ts +1 -0
- package/src/inference/index.ts +6 -1
- package/src/inference/ollama-client.ts +30 -14
- package/src/sbom/component-mapper.ts +107 -0
- package/src/sbom/cyclonedx-import.ts +198 -0
- package/src/sbom/index.ts +12 -0
- package/src/sbom/known-packages.ts +142 -0
- package/src/sbom/purl.ts +66 -0
- package/src/sbom/types.ts +34 -0
- package/src/validation/index.ts +7 -0
- package/src/validation/schema-validator.ts +133 -0
- package/tests/evidence/{ecef-schemas.test.ts → spec-schemas.test.ts} +3 -3
- package/tests/fixtures/cyclonedx-minimal.json +13 -0
- package/tests/fixtures/cyclonedx-mixed.json +17 -0
- package/tests/fixtures/cyclonedx-ml-bom.json +25 -0
- package/tests/sbom/component-mapper.test.ts +258 -0
- package/tests/sbom/cyclonedx-import.test.ts +329 -0
- package/tests/sbom/purl.test.ts +102 -0
- package/tests/validation/schema-validator.test.ts +219 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { BomComponentKind } from "../evidence/types";
|
|
2
|
+
|
|
3
|
+
export const KNOWN_AI_PACKAGES: Record<string, BomComponentKind> = {
|
|
4
|
+
// Models / model runtimes
|
|
5
|
+
"llama.cpp": "model",
|
|
6
|
+
"llama-cpp-python": "model",
|
|
7
|
+
"whisper.cpp": "model",
|
|
8
|
+
ggml: "model",
|
|
9
|
+
ctransformers: "model",
|
|
10
|
+
|
|
11
|
+
// AI Frameworks
|
|
12
|
+
transformers: "ai-framework",
|
|
13
|
+
torch: "ai-framework",
|
|
14
|
+
pytorch: "ai-framework",
|
|
15
|
+
tensorflow: "ai-framework",
|
|
16
|
+
"tensorflow-gpu": "ai-framework",
|
|
17
|
+
jax: "ai-framework",
|
|
18
|
+
keras: "ai-framework",
|
|
19
|
+
"pytorch-lightning": "ai-framework",
|
|
20
|
+
"scikit-learn": "ai-framework",
|
|
21
|
+
sklearn: "ai-framework",
|
|
22
|
+
xgboost: "ai-framework",
|
|
23
|
+
lightgbm: "ai-framework",
|
|
24
|
+
spacy: "ai-framework",
|
|
25
|
+
"huggingface-hub": "ai-framework",
|
|
26
|
+
diffusers: "ai-framework",
|
|
27
|
+
accelerate: "ai-framework",
|
|
28
|
+
peft: "ai-framework",
|
|
29
|
+
trl: "ai-framework",
|
|
30
|
+
onnxruntime: "ai-framework",
|
|
31
|
+
"onnxruntime-gpu": "ai-framework",
|
|
32
|
+
mlflow: "ai-framework",
|
|
33
|
+
|
|
34
|
+
// Embeddings
|
|
35
|
+
"sentence-transformers": "embedding",
|
|
36
|
+
fastembed: "embedding",
|
|
37
|
+
"openai-embeddings": "embedding",
|
|
38
|
+
"cohere-embed": "embedding",
|
|
39
|
+
|
|
40
|
+
// Inference Providers
|
|
41
|
+
openai: "inference-provider",
|
|
42
|
+
anthropic: "inference-provider",
|
|
43
|
+
ollama: "inference-provider",
|
|
44
|
+
vllm: "inference-provider",
|
|
45
|
+
"together-ai": "inference-provider",
|
|
46
|
+
replicate: "inference-provider",
|
|
47
|
+
groq: "inference-provider",
|
|
48
|
+
mistralai: "inference-provider",
|
|
49
|
+
cohere: "inference-provider",
|
|
50
|
+
"google-generativeai": "inference-provider",
|
|
51
|
+
ai21: "inference-provider",
|
|
52
|
+
|
|
53
|
+
// Vector Stores
|
|
54
|
+
pinecone: "vector-store",
|
|
55
|
+
"pinecone-client": "vector-store",
|
|
56
|
+
weaviate: "vector-store",
|
|
57
|
+
"weaviate-client": "vector-store",
|
|
58
|
+
qdrant: "vector-store",
|
|
59
|
+
"qdrant-client": "vector-store",
|
|
60
|
+
milvus: "vector-store",
|
|
61
|
+
pymilvus: "vector-store",
|
|
62
|
+
chromadb: "vector-store",
|
|
63
|
+
"chromadb-client": "vector-store",
|
|
64
|
+
pgvector: "vector-store",
|
|
65
|
+
faiss: "vector-store",
|
|
66
|
+
"faiss-cpu": "vector-store",
|
|
67
|
+
"faiss-gpu": "vector-store",
|
|
68
|
+
|
|
69
|
+
// Datasets
|
|
70
|
+
datasets: "dataset",
|
|
71
|
+
|
|
72
|
+
// Tools / Orchestration
|
|
73
|
+
langchain: "tool",
|
|
74
|
+
"langchain-core": "tool",
|
|
75
|
+
"langchain-community": "tool",
|
|
76
|
+
llamaindex: "tool",
|
|
77
|
+
"llama-index": "tool",
|
|
78
|
+
"semantic-kernel": "tool",
|
|
79
|
+
autogen: "tool",
|
|
80
|
+
crewai: "tool",
|
|
81
|
+
dspy: "tool",
|
|
82
|
+
"haystack-ai": "tool",
|
|
83
|
+
guidance: "tool",
|
|
84
|
+
guardrails: "tool",
|
|
85
|
+
"guardrails-ai": "tool",
|
|
86
|
+
lmql: "tool",
|
|
87
|
+
outlines: "tool",
|
|
88
|
+
|
|
89
|
+
// Scoped packages (npm)
|
|
90
|
+
"@langchain/core": "tool",
|
|
91
|
+
"@langchain/openai": "tool",
|
|
92
|
+
"@langchain/community": "tool",
|
|
93
|
+
"@langchain/anthropic": "tool",
|
|
94
|
+
"@huggingface/transformers": "ai-framework",
|
|
95
|
+
"@huggingface/inference": "inference-provider",
|
|
96
|
+
"@google/generative-ai": "inference-provider",
|
|
97
|
+
"@anthropic-ai/sdk": "inference-provider",
|
|
98
|
+
"@pinecone-database/pinecone": "vector-store",
|
|
99
|
+
"@qdrant/js-client-rest": "vector-store",
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const KNOWN_AI_SCOPES: Record<string, BomComponentKind> = {
|
|
103
|
+
"@langchain": "tool",
|
|
104
|
+
"@huggingface": "ai-framework",
|
|
105
|
+
"@tensorflow": "ai-framework",
|
|
106
|
+
"@anthropic-ai": "inference-provider",
|
|
107
|
+
"@pinecone-database": "vector-store",
|
|
108
|
+
"@qdrant": "vector-store",
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Look up a package name in the known AI packages registry.
|
|
113
|
+
* For scoped packages, tries:
|
|
114
|
+
* 1. Exact match (e.g. @langchain/core)
|
|
115
|
+
* 2. Scope match via KNOWN_AI_SCOPES (e.g. @langchain -> tool)
|
|
116
|
+
* 3. Strip scope, check bare name (e.g. @huggingface/transformers -> transformers)
|
|
117
|
+
* Returns the BomComponentKind if found, null otherwise.
|
|
118
|
+
*/
|
|
119
|
+
export function lookupKnownPackage(name: string): BomComponentKind | null {
|
|
120
|
+
const lower = name.toLowerCase();
|
|
121
|
+
|
|
122
|
+
// 1. Exact match
|
|
123
|
+
const exact = KNOWN_AI_PACKAGES[lower];
|
|
124
|
+
if (exact) return exact;
|
|
125
|
+
|
|
126
|
+
// Scoped package handling
|
|
127
|
+
if (lower.startsWith("@") && lower.includes("/")) {
|
|
128
|
+
const scopeEnd = lower.indexOf("/");
|
|
129
|
+
const scope = lower.slice(0, scopeEnd);
|
|
130
|
+
const bareName = lower.slice(scopeEnd + 1);
|
|
131
|
+
|
|
132
|
+
// 2. Known AI scope
|
|
133
|
+
const scopeKind = KNOWN_AI_SCOPES[scope];
|
|
134
|
+
if (scopeKind) return scopeKind;
|
|
135
|
+
|
|
136
|
+
// 3. Strip scope, check bare name
|
|
137
|
+
const bareKind = KNOWN_AI_PACKAGES[bareName];
|
|
138
|
+
if (bareKind) return bareKind;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return null;
|
|
142
|
+
}
|
package/src/sbom/purl.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export interface ParsedPurl {
|
|
2
|
+
scheme: "pkg";
|
|
3
|
+
type: string;
|
|
4
|
+
namespace?: string;
|
|
5
|
+
name: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Parse a Package URL (purl) string into its components.
|
|
11
|
+
* Follows the purl spec: pkg:type/namespace/name@version?qualifiers#subpath
|
|
12
|
+
* Returns null for invalid or non-pkg URLs.
|
|
13
|
+
*/
|
|
14
|
+
export function parsePurl(purl: string): ParsedPurl | null {
|
|
15
|
+
if (!purl || !purl.startsWith("pkg:")) return null;
|
|
16
|
+
|
|
17
|
+
// Strip qualifiers and subpath
|
|
18
|
+
let rest = purl.slice(4); // remove "pkg:"
|
|
19
|
+
const hashIdx = rest.indexOf("#");
|
|
20
|
+
if (hashIdx !== -1) rest = rest.slice(0, hashIdx);
|
|
21
|
+
const queryIdx = rest.indexOf("?");
|
|
22
|
+
if (queryIdx !== -1) rest = rest.slice(0, queryIdx);
|
|
23
|
+
|
|
24
|
+
// Split type from the rest: type/...
|
|
25
|
+
const slashIdx = rest.indexOf("/");
|
|
26
|
+
if (slashIdx <= 0) return null;
|
|
27
|
+
|
|
28
|
+
const type = rest.slice(0, slashIdx);
|
|
29
|
+
let remainder = rest.slice(slashIdx + 1);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
remainder = decodeURIComponent(remainder);
|
|
33
|
+
} catch {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Extract version
|
|
38
|
+
let version: string | undefined;
|
|
39
|
+
const atIdx = remainder.lastIndexOf("@");
|
|
40
|
+
if (atIdx !== -1) {
|
|
41
|
+
version = remainder.slice(atIdx + 1);
|
|
42
|
+
remainder = remainder.slice(0, atIdx);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Split namespace/name (last segment is name, rest is namespace)
|
|
46
|
+
const lastSlash = remainder.lastIndexOf("/");
|
|
47
|
+
let namespace: string | undefined;
|
|
48
|
+
let name: string;
|
|
49
|
+
|
|
50
|
+
if (lastSlash !== -1) {
|
|
51
|
+
namespace = remainder.slice(0, lastSlash);
|
|
52
|
+
name = remainder.slice(lastSlash + 1);
|
|
53
|
+
} else {
|
|
54
|
+
name = remainder;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!name) return null;
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
scheme: "pkg",
|
|
61
|
+
type,
|
|
62
|
+
namespace: namespace || undefined,
|
|
63
|
+
name,
|
|
64
|
+
version: version || undefined,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal CycloneDX types covering fields relevant to AI component detection.
|
|
3
|
+
* Supports CycloneDX JSON format versions 1.4, 1.5, 1.6.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface CycloneDxBom {
|
|
7
|
+
bomFormat: "CycloneDX";
|
|
8
|
+
specVersion: string;
|
|
9
|
+
version?: number;
|
|
10
|
+
metadata?: CycloneDxMetadata;
|
|
11
|
+
components?: CycloneDxComponent[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface CycloneDxMetadata {
|
|
15
|
+
timestamp?: string;
|
|
16
|
+
tools?: Array<{ name?: string; version?: string }>;
|
|
17
|
+
component?: CycloneDxComponent;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface CycloneDxComponent {
|
|
21
|
+
type: string;
|
|
22
|
+
name: string;
|
|
23
|
+
version?: string;
|
|
24
|
+
purl?: string;
|
|
25
|
+
group?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
scope?: "required" | "optional" | "excluded";
|
|
28
|
+
properties?: Array<{ name: string; value: string }>;
|
|
29
|
+
/** CycloneDX ML-BOM extensions (1.5+) */
|
|
30
|
+
modelCard?: unknown;
|
|
31
|
+
data?: Array<{ type?: string }>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const SUPPORTED_SPEC_VERSIONS = ["1.4", "1.5", "1.6"] as const;
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import addFormats from "ajv-formats";
|
|
5
|
+
import Ajv2020 from "ajv/dist/2020";
|
|
6
|
+
|
|
7
|
+
export interface ValidationError {
|
|
8
|
+
path: string;
|
|
9
|
+
message: string;
|
|
10
|
+
keyword: string;
|
|
11
|
+
expected?: unknown;
|
|
12
|
+
received?: unknown;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SchemaType = "report.v1" | "aibom.v1" | "aibom.v1.1" | "ci.v1" | "bundle.v1";
|
|
16
|
+
|
|
17
|
+
export interface ValidationResult {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
schemaType: SchemaType;
|
|
20
|
+
errors: ValidationError[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ValidateOptions {
|
|
24
|
+
strict?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolve schema directory relative to this file at runtime.
|
|
28
|
+
// When bundled into packages/cli/dist, schemas are copied to dist/schemas/.
|
|
29
|
+
// When running from source at packages/core/src/validation/, schemas are at ../../../../docs/spec/schemas.
|
|
30
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
31
|
+
const __dirname = dirname(__filename);
|
|
32
|
+
const _bundledSchemasDir = resolve(__dirname, "schemas");
|
|
33
|
+
const schemasDir = existsSync(_bundledSchemasDir)
|
|
34
|
+
? _bundledSchemasDir
|
|
35
|
+
: resolve(__dirname, "../../../../docs/spec/schemas");
|
|
36
|
+
|
|
37
|
+
function loadSchema(filename: string): object {
|
|
38
|
+
const content = readFileSync(resolve(schemasDir, filename), "utf-8");
|
|
39
|
+
return JSON.parse(content) as object;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const SCHEMA_MAP: Record<string, { schemaFile: string; type: SchemaType }> = {
|
|
43
|
+
"euconform.report.v1": { schemaFile: "report-v1.schema.json", type: "report.v1" },
|
|
44
|
+
"euconform.aibom.v1": { schemaFile: "aibom-v1.schema.json", type: "aibom.v1" },
|
|
45
|
+
"euconform.aibom.v1.1": { schemaFile: "aibom-v1.1.schema.json", type: "aibom.v1.1" },
|
|
46
|
+
"euconform.ci.v1": { schemaFile: "ci-v1.schema.json", type: "ci.v1" },
|
|
47
|
+
"euconform.bundle.v1": { schemaFile: "bundle-v1.schema.json", type: "bundle.v1" },
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
let ajvInstance: Ajv2020 | null = null;
|
|
51
|
+
|
|
52
|
+
function getAjv(): Ajv2020 {
|
|
53
|
+
if (!ajvInstance) {
|
|
54
|
+
ajvInstance = new Ajv2020({ allErrors: true, strict: false });
|
|
55
|
+
addFormats(ajvInstance);
|
|
56
|
+
}
|
|
57
|
+
return ajvInstance;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function validate(data: unknown, _options?: ValidateOptions): ValidationResult {
|
|
61
|
+
if (typeof data !== "object" || data === null) {
|
|
62
|
+
return {
|
|
63
|
+
valid: false,
|
|
64
|
+
schemaType: "report.v1",
|
|
65
|
+
errors: [
|
|
66
|
+
{
|
|
67
|
+
path: "",
|
|
68
|
+
message: "Input must be a JSON object",
|
|
69
|
+
keyword: "type",
|
|
70
|
+
expected: "object",
|
|
71
|
+
received: typeof data,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const record = data as Record<string, unknown>;
|
|
78
|
+
const schemaVersion = record.schemaVersion;
|
|
79
|
+
|
|
80
|
+
if (typeof schemaVersion !== "string") {
|
|
81
|
+
return {
|
|
82
|
+
valid: false,
|
|
83
|
+
schemaType: "report.v1",
|
|
84
|
+
errors: [
|
|
85
|
+
{
|
|
86
|
+
path: "",
|
|
87
|
+
message: `Missing or invalid schemaVersion field. Expected one of: ${Object.keys(SCHEMA_MAP).join(", ")}`,
|
|
88
|
+
keyword: "required",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const entry = SCHEMA_MAP[schemaVersion];
|
|
95
|
+
if (!entry) {
|
|
96
|
+
return {
|
|
97
|
+
valid: false,
|
|
98
|
+
schemaType: "report.v1",
|
|
99
|
+
errors: [
|
|
100
|
+
{
|
|
101
|
+
path: "/schemaVersion",
|
|
102
|
+
message: `Unknown schemaVersion "${schemaVersion}". Expected one of: ${Object.keys(SCHEMA_MAP).join(", ")}`,
|
|
103
|
+
keyword: "const",
|
|
104
|
+
expected: Object.keys(SCHEMA_MAP),
|
|
105
|
+
received: schemaVersion,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const ajv = getAjv();
|
|
112
|
+
let validateFn = ajv.getSchema(schemaVersion);
|
|
113
|
+
if (!validateFn) {
|
|
114
|
+
const schema = loadSchema(entry.schemaFile);
|
|
115
|
+
validateFn = ajv.compile({ ...schema, $id: schemaVersion });
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const valid = validateFn(data) as boolean;
|
|
119
|
+
|
|
120
|
+
if (valid) {
|
|
121
|
+
return { valid: true, schemaType: entry.type, errors: [] };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const errors: ValidationError[] = (validateFn.errors ?? []).map((err) => ({
|
|
125
|
+
path: err.instancePath ?? "",
|
|
126
|
+
message: err.message ?? "Validation error",
|
|
127
|
+
keyword: err.keyword ?? "unknown",
|
|
128
|
+
expected: err.params,
|
|
129
|
+
received: undefined,
|
|
130
|
+
}));
|
|
131
|
+
|
|
132
|
+
return { valid: false, schemaType: entry.type, errors };
|
|
133
|
+
}
|
|
@@ -18,8 +18,8 @@ type JsonSchema = {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const ROOT = resolve(__dirname, "../../../..");
|
|
21
|
-
const SCHEMAS_DIR = resolve(ROOT, "docs/
|
|
22
|
-
const EXAMPLES_DIR = resolve(ROOT, "docs/
|
|
21
|
+
const SCHEMAS_DIR = resolve(ROOT, "docs/spec/schemas");
|
|
22
|
+
const EXAMPLES_DIR = resolve(ROOT, "docs/spec/examples");
|
|
23
23
|
|
|
24
24
|
function readJson<T>(path: string): T {
|
|
25
25
|
return JSON.parse(readFileSync(path, "utf8")) as T;
|
|
@@ -168,7 +168,7 @@ const EXAMPLE_FILES = {
|
|
|
168
168
|
bundle: "euconform.bundle.json",
|
|
169
169
|
} as const;
|
|
170
170
|
|
|
171
|
-
describe("
|
|
171
|
+
describe("EuConform Evidence Format schemas", () => {
|
|
172
172
|
const schemaEntries = Object.entries(SCHEMA_FILES).map(([kind, path]) => [
|
|
173
173
|
kind,
|
|
174
174
|
readJson<JsonSchema>(path),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bomFormat": "CycloneDX",
|
|
3
|
+
"specVersion": "1.5",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"components": [
|
|
6
|
+
{ "type": "library", "name": "express", "version": "4.18.2" },
|
|
7
|
+
{ "type": "library", "name": "lodash", "version": "4.17.21" },
|
|
8
|
+
{ "type": "library", "name": "openai", "version": "1.12.0" },
|
|
9
|
+
{ "type": "framework", "name": "transformers", "version": "4.38.0" },
|
|
10
|
+
{ "type": "library", "name": "chromadb", "version": "0.4.22" },
|
|
11
|
+
{ "type": "library", "name": "langchain", "version": "0.1.0" },
|
|
12
|
+
{ "type": "machine-learning-model", "name": "whisper-large-v3", "version": "1.0.0" },
|
|
13
|
+
{ "type": "library", "name": "typescript", "version": "5.3.0" },
|
|
14
|
+
{ "type": "library", "name": "react", "version": "18.2.0" },
|
|
15
|
+
{ "type": "library", "name": "axios", "version": "1.6.0" }
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"bomFormat": "CycloneDX",
|
|
3
|
+
"specVersion": "1.5",
|
|
4
|
+
"version": 1,
|
|
5
|
+
"components": [
|
|
6
|
+
{
|
|
7
|
+
"type": "library",
|
|
8
|
+
"name": "custom-bert-model",
|
|
9
|
+
"version": "2.0.0",
|
|
10
|
+
"modelCard": {
|
|
11
|
+
"modelParameters": {
|
|
12
|
+
"approach": { "type": "supervised" },
|
|
13
|
+
"task": "text-classification"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "library",
|
|
19
|
+
"name": "sentiment-dataset",
|
|
20
|
+
"version": "1.0.0",
|
|
21
|
+
"data": [{ "type": "dataset", "name": "imdb-reviews" }]
|
|
22
|
+
},
|
|
23
|
+
{ "type": "library", "name": "numpy", "version": "1.24.0" }
|
|
24
|
+
]
|
|
25
|
+
}
|