@evalguardai/cli 1.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/README.md +87 -0
- package/bin/evalguard.js +2 -0
- package/dist/commands/compare.d.ts +6 -0
- package/dist/commands/compare.d.ts.map +1 -0
- package/dist/commands/compare.js +109 -0
- package/dist/commands/compare.js.map +1 -0
- package/dist/commands/compliance-check.d.ts +18 -0
- package/dist/commands/compliance-check.d.ts.map +1 -0
- package/dist/commands/compliance-check.js +474 -0
- package/dist/commands/compliance-check.js.map +1 -0
- package/dist/commands/debug.d.ts +6 -0
- package/dist/commands/debug.d.ts.map +1 -0
- package/dist/commands/debug.js +151 -0
- package/dist/commands/debug.js.map +1 -0
- package/dist/commands/delete.d.ts +6 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +105 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/eval-local.d.ts +7 -0
- package/dist/commands/eval-local.d.ts.map +1 -0
- package/dist/commands/eval-local.js +376 -0
- package/dist/commands/eval-local.js.map +1 -0
- package/dist/commands/export.d.ts +6 -0
- package/dist/commands/export.d.ts.map +1 -0
- package/dist/commands/export.js +135 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/firewall.d.ts +6 -0
- package/dist/commands/firewall.d.ts.map +1 -0
- package/dist/commands/firewall.js +56 -0
- package/dist/commands/firewall.js.map +1 -0
- package/dist/commands/gate.d.ts +14 -0
- package/dist/commands/gate.d.ts.map +1 -0
- package/dist/commands/gate.js +232 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/generate.d.ts +7 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +182 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/history.d.ts +7 -0
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/commands/history.js +59 -0
- package/dist/commands/history.js.map +1 -0
- package/dist/commands/import-promptfoo.d.ts +7 -0
- package/dist/commands/import-promptfoo.d.ts.map +1 -0
- package/dist/commands/import-promptfoo.js +218 -0
- package/dist/commands/import-promptfoo.js.map +1 -0
- package/dist/commands/index.d.ts +21 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +21 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +509 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +10 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +165 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/logs.d.ts +6 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +153 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/model-scan.d.ts +7 -0
- package/dist/commands/model-scan.d.ts.map +1 -0
- package/dist/commands/model-scan.js +276 -0
- package/dist/commands/model-scan.js.map +1 -0
- package/dist/commands/retry.d.ts +6 -0
- package/dist/commands/retry.d.ts.map +1 -0
- package/dist/commands/retry.js +83 -0
- package/dist/commands/retry.js.map +1 -0
- package/dist/commands/scan-local.d.ts +6 -0
- package/dist/commands/scan-local.d.ts.map +1 -0
- package/dist/commands/scan-local.js +138 -0
- package/dist/commands/scan-local.js.map +1 -0
- package/dist/commands/share.d.ts +6 -0
- package/dist/commands/share.d.ts.map +1 -0
- package/dist/commands/share.js +74 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/store.d.ts +23 -0
- package/dist/commands/store.d.ts.map +1 -0
- package/dist/commands/store.js +54 -0
- package/dist/commands/store.js.map +1 -0
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +171 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +92 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +342 -0
- package/dist/index.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
import * as os from "os";
|
|
6
|
+
const SUPPORTED_FRAMEWORKS = [
|
|
7
|
+
"eu-ai-act",
|
|
8
|
+
"hipaa",
|
|
9
|
+
"fedramp",
|
|
10
|
+
"pci-dss",
|
|
11
|
+
"iso-42001",
|
|
12
|
+
"owasp-llm",
|
|
13
|
+
"nist-ai-rmf",
|
|
14
|
+
];
|
|
15
|
+
function loadConfig() {
|
|
16
|
+
const configFile = path.join(os.homedir(), ".evalguard", "config.json");
|
|
17
|
+
try {
|
|
18
|
+
if (fs.existsSync(configFile)) {
|
|
19
|
+
return JSON.parse(fs.readFileSync(configFile, "utf-8"));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Ignore config errors — fall back to local mode
|
|
24
|
+
}
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
function getApiKey() {
|
|
28
|
+
return process.env.EVALGUARD_API_KEY ?? loadConfig().apiKey;
|
|
29
|
+
}
|
|
30
|
+
function getBaseUrl() {
|
|
31
|
+
return loadConfig().baseUrl ?? "https://evalguard.ai/api/v1";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Run compliance check via the EvalGuard API.
|
|
35
|
+
*/
|
|
36
|
+
async function runRemoteCheck(config) {
|
|
37
|
+
const apiKey = getApiKey();
|
|
38
|
+
const baseUrl = getBaseUrl();
|
|
39
|
+
const res = await fetch(`${baseUrl}/api/v1/compliance/check`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
"Content-Type": "application/json",
|
|
43
|
+
Authorization: `Bearer ${apiKey}`,
|
|
44
|
+
},
|
|
45
|
+
body: JSON.stringify({
|
|
46
|
+
framework: config.framework,
|
|
47
|
+
model: config.model,
|
|
48
|
+
systemPrompt: config.systemPrompt,
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
const errBody = await res.json().catch(() => ({ message: res.statusText }));
|
|
53
|
+
throw new Error(`API error ${res.status}: ${errBody.message ?? "Unknown error"}`);
|
|
54
|
+
}
|
|
55
|
+
return (await res.json());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the framework ID from the CLI flag to the core framework constant.
|
|
59
|
+
* The core library uses different export names and sometimes different IDs.
|
|
60
|
+
*/
|
|
61
|
+
function resolveFramework(frameworkId, core) {
|
|
62
|
+
const map = {
|
|
63
|
+
"eu-ai-act": { export: "EU_AI_ACT" },
|
|
64
|
+
hipaa: { export: "HIPAA_AI", fallback: "HIPAA" },
|
|
65
|
+
fedramp: { export: "FEDRAMP_AI" },
|
|
66
|
+
"pci-dss": { export: "PCI_DSS_AI" },
|
|
67
|
+
"iso-42001": { export: "ISO_42001" },
|
|
68
|
+
"owasp-llm": { export: "OWASP_LLM_TOP10" },
|
|
69
|
+
"nist-ai-rmf": { export: "NIST_AI_RMF" },
|
|
70
|
+
};
|
|
71
|
+
const entry = map[frameworkId];
|
|
72
|
+
const fw = core[entry.export] ?? (entry.fallback ? core[entry.fallback] : undefined);
|
|
73
|
+
if (!fw) {
|
|
74
|
+
throw new Error(`Framework "${frameworkId}" is not available in the installed @evalguard/core version.`);
|
|
75
|
+
}
|
|
76
|
+
return fw;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Detect the provider from the model name.
|
|
80
|
+
*/
|
|
81
|
+
function detectProvider(model) {
|
|
82
|
+
if (model.startsWith("gpt-") || model.startsWith("o1") || model.startsWith("o3") || model.startsWith("o4"))
|
|
83
|
+
return "openai";
|
|
84
|
+
if (model.startsWith("claude-"))
|
|
85
|
+
return "anthropic";
|
|
86
|
+
if (model.startsWith("gemini-"))
|
|
87
|
+
return "google";
|
|
88
|
+
if (model.startsWith("llama") || model.startsWith("meta-"))
|
|
89
|
+
return "meta";
|
|
90
|
+
if (model.startsWith("mistral") || model.startsWith("mixtral"))
|
|
91
|
+
return "mistral";
|
|
92
|
+
return "openai";
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Run compliance check locally using @evalguard/core.
|
|
96
|
+
*/
|
|
97
|
+
async function runLocalCheck(config) {
|
|
98
|
+
const core = (await import("@evalguard/core"));
|
|
99
|
+
const { GapAnalysis, runSecurityScan, createProvider } = core;
|
|
100
|
+
const framework = resolveFramework(config.framework, core);
|
|
101
|
+
const model = config.model ?? "gpt-4o-mini";
|
|
102
|
+
const providerName = config.provider ?? detectProvider(model);
|
|
103
|
+
// Resolve API key for the LLM provider
|
|
104
|
+
const apiKeyEnvMap = {
|
|
105
|
+
openai: "OPENAI_API_KEY",
|
|
106
|
+
anthropic: "ANTHROPIC_API_KEY",
|
|
107
|
+
google: "GOOGLE_API_KEY",
|
|
108
|
+
mistral: "MISTRAL_API_KEY",
|
|
109
|
+
};
|
|
110
|
+
const envVar = apiKeyEnvMap[providerName] ?? `${providerName.toUpperCase()}_API_KEY`;
|
|
111
|
+
const llmApiKey = process.env[envVar];
|
|
112
|
+
// Determine if this is an "enhanced" framework (has requirements) or a
|
|
113
|
+
// "classic" framework (has categories.controls). They use different analysis paths.
|
|
114
|
+
const isEnhanced = !!framework.requirements;
|
|
115
|
+
if (isEnhanced) {
|
|
116
|
+
// Enhanced frameworks: EU AI Act, HIPAA, FedRAMP, PCI-DSS, ISO 42001
|
|
117
|
+
// Use GapAnalysis which works against ComplianceFrameworkEnhanced.
|
|
118
|
+
const gapAnalysis = new GapAnalysis();
|
|
119
|
+
// Collect all automatable attack types from the framework requirements
|
|
120
|
+
const requirements = framework.requirements;
|
|
121
|
+
const attackTypes = new Set();
|
|
122
|
+
for (const req of requirements) {
|
|
123
|
+
if (req.automatable && req.attackTypes) {
|
|
124
|
+
for (const at of req.attackTypes) {
|
|
125
|
+
attackTypes.add(at);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Build minimal scan results if no LLM key is available (dry-run mode)
|
|
130
|
+
let scanResults;
|
|
131
|
+
if (llmApiKey && typeof runSecurityScan === "function") {
|
|
132
|
+
try {
|
|
133
|
+
const provider = typeof createProvider === "function"
|
|
134
|
+
? createProvider(providerName, { apiKey: llmApiKey, model })
|
|
135
|
+
: undefined;
|
|
136
|
+
scanResults = await runSecurityScan({
|
|
137
|
+
model,
|
|
138
|
+
provider: provider ?? providerName,
|
|
139
|
+
systemPrompt: config.systemPrompt ?? "You are a helpful assistant.",
|
|
140
|
+
attackTypes: [...attackTypes],
|
|
141
|
+
apiKey: llmApiKey,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// Fall through to dry-run mode
|
|
146
|
+
scanResults = null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (!scanResults) {
|
|
150
|
+
// Dry-run: generate a gap report with all requirements as "untested"
|
|
151
|
+
scanResults = { findings: [], passed: false, score: 0 };
|
|
152
|
+
}
|
|
153
|
+
const report = gapAnalysis.analyze(scanResults, framework);
|
|
154
|
+
const remediationSteps = gapAnalysis.getRemediationPlan(report.gaps);
|
|
155
|
+
// Build result
|
|
156
|
+
const byCategory = {};
|
|
157
|
+
for (const cat of framework.categories) {
|
|
158
|
+
const catData = report.byCategory[cat.id];
|
|
159
|
+
if (catData) {
|
|
160
|
+
byCategory[cat.id] = {
|
|
161
|
+
name: cat.name,
|
|
162
|
+
total: catData.total,
|
|
163
|
+
met: catData.met,
|
|
164
|
+
partial: catData.partial,
|
|
165
|
+
notMet: catData.notMet,
|
|
166
|
+
untested: catData.untested,
|
|
167
|
+
score: catData.score,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
framework: framework.id,
|
|
173
|
+
frameworkName: framework.name,
|
|
174
|
+
version: framework.version,
|
|
175
|
+
model,
|
|
176
|
+
timestamp: new Date().toISOString(),
|
|
177
|
+
overallScore: report.overallScore,
|
|
178
|
+
totalRequirements: report.totalRequirements,
|
|
179
|
+
metCount: report.metCount,
|
|
180
|
+
partialCount: report.partialCount,
|
|
181
|
+
notMetCount: report.notMetCount,
|
|
182
|
+
untestedCount: report.untestedCount,
|
|
183
|
+
requirements: report.gaps.map((g) => ({
|
|
184
|
+
id: g.requirement.id,
|
|
185
|
+
title: g.requirement.title,
|
|
186
|
+
category: g.requirement.category,
|
|
187
|
+
severity: g.requirement.severity,
|
|
188
|
+
status: g.status,
|
|
189
|
+
notes: g.notes,
|
|
190
|
+
})),
|
|
191
|
+
byCategory,
|
|
192
|
+
remediationSteps: remediationSteps.map((s, i) => ({
|
|
193
|
+
priority: i + 1,
|
|
194
|
+
requirementId: s.requirementId,
|
|
195
|
+
requirementTitle: s.requirementTitle,
|
|
196
|
+
severity: s.severity,
|
|
197
|
+
action: s.action,
|
|
198
|
+
effort: s.effort,
|
|
199
|
+
automatable: s.automatable,
|
|
200
|
+
})),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// Classic frameworks: OWASP LLM Top 10, NIST AI RMF, MITRE ATLAS
|
|
205
|
+
// Use mapToCompliance which works against ComplianceFramework.
|
|
206
|
+
const { mapToCompliance } = core;
|
|
207
|
+
let scanResults;
|
|
208
|
+
if (llmApiKey && typeof runSecurityScan === "function") {
|
|
209
|
+
try {
|
|
210
|
+
const provider = typeof createProvider === "function"
|
|
211
|
+
? createProvider(providerName, { apiKey: llmApiKey, model })
|
|
212
|
+
: undefined;
|
|
213
|
+
scanResults = await runSecurityScan({
|
|
214
|
+
model,
|
|
215
|
+
provider: provider ?? providerName,
|
|
216
|
+
systemPrompt: config.systemPrompt ?? "You are a helpful assistant.",
|
|
217
|
+
apiKey: llmApiKey,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
scanResults = null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (!scanResults) {
|
|
225
|
+
scanResults = { findings: [], passed: false, score: 0 };
|
|
226
|
+
}
|
|
227
|
+
const report = mapToCompliance(scanResults, framework.id);
|
|
228
|
+
const totalControls = report.findings.length;
|
|
229
|
+
const passCount = report.findings.filter((f) => f.status === "pass").length;
|
|
230
|
+
const failCount = report.findings.filter((f) => f.status === "fail").length;
|
|
231
|
+
const untestedCount = report.findings.filter((f) => f.status === "untested").length;
|
|
232
|
+
const overallScore = totalControls > 0 ? Math.round((passCount / totalControls) * 100) : 0;
|
|
233
|
+
const byCategory = {};
|
|
234
|
+
for (const cat of framework.categories) {
|
|
235
|
+
const catFindings = report.findings.filter((f) => f.control.categoryId === cat.id || f.categoryId === cat.id);
|
|
236
|
+
const met = catFindings.filter((f) => f.status === "pass").length;
|
|
237
|
+
const notMet = catFindings.filter((f) => f.status === "fail").length;
|
|
238
|
+
const untested = catFindings.filter((f) => f.status === "untested").length;
|
|
239
|
+
const total = catFindings.length;
|
|
240
|
+
byCategory[cat.id] = {
|
|
241
|
+
name: cat.name,
|
|
242
|
+
total,
|
|
243
|
+
met,
|
|
244
|
+
partial: 0,
|
|
245
|
+
notMet,
|
|
246
|
+
untested,
|
|
247
|
+
score: total > 0 ? Math.round((met / total) * 100) : 0,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
return {
|
|
251
|
+
framework: framework.id,
|
|
252
|
+
frameworkName: framework.name,
|
|
253
|
+
version: framework.version,
|
|
254
|
+
model,
|
|
255
|
+
timestamp: new Date().toISOString(),
|
|
256
|
+
overallScore,
|
|
257
|
+
totalRequirements: totalControls,
|
|
258
|
+
metCount: passCount,
|
|
259
|
+
partialCount: 0,
|
|
260
|
+
notMetCount: failCount,
|
|
261
|
+
untestedCount,
|
|
262
|
+
requirements: report.findings.map((f) => ({
|
|
263
|
+
id: f.control?.id ?? f.id,
|
|
264
|
+
title: f.control?.name ?? f.title ?? f.id,
|
|
265
|
+
category: f.control?.categoryId ?? f.categoryId ?? "unknown",
|
|
266
|
+
severity: f.control?.severity ?? f.severity ?? "medium",
|
|
267
|
+
status: f.status === "pass" ? "met" : f.status === "fail" ? "not-met" : "untested",
|
|
268
|
+
notes: f.status === "pass"
|
|
269
|
+
? "All tests passed."
|
|
270
|
+
: f.status === "fail"
|
|
271
|
+
? "Test failures detected. Remediation required."
|
|
272
|
+
: "No test coverage for this control.",
|
|
273
|
+
})),
|
|
274
|
+
byCategory,
|
|
275
|
+
remediationSteps: report.findings
|
|
276
|
+
.filter((f) => f.status === "fail")
|
|
277
|
+
.map((f, i) => ({
|
|
278
|
+
priority: i + 1,
|
|
279
|
+
requirementId: f.control?.id ?? f.id,
|
|
280
|
+
requirementTitle: f.control?.name ?? f.title ?? f.id,
|
|
281
|
+
severity: f.control?.severity ?? "medium",
|
|
282
|
+
action: `Implement controls for: ${f.control?.name ?? f.title}. ${f.control?.description ?? ""}`.trim(),
|
|
283
|
+
effort: "medium",
|
|
284
|
+
automatable: true,
|
|
285
|
+
})),
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// ─── Output Formatting ──────────────────────────────────────────────────────
|
|
290
|
+
function statusIcon(status) {
|
|
291
|
+
switch (status) {
|
|
292
|
+
case "met":
|
|
293
|
+
return chalk.green("PASS");
|
|
294
|
+
case "partial":
|
|
295
|
+
return chalk.yellow("PARTIAL");
|
|
296
|
+
case "not-met":
|
|
297
|
+
return chalk.red("FAIL");
|
|
298
|
+
case "untested":
|
|
299
|
+
return chalk.dim("UNTESTED");
|
|
300
|
+
default:
|
|
301
|
+
return chalk.dim(status);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function severityColor(severity) {
|
|
305
|
+
switch (severity) {
|
|
306
|
+
case "critical":
|
|
307
|
+
return chalk.red.bold(severity.toUpperCase());
|
|
308
|
+
case "high":
|
|
309
|
+
return chalk.red(severity.toUpperCase());
|
|
310
|
+
case "medium":
|
|
311
|
+
return chalk.yellow(severity.toUpperCase());
|
|
312
|
+
case "low":
|
|
313
|
+
return chalk.dim(severity.toUpperCase());
|
|
314
|
+
default:
|
|
315
|
+
return severity;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function printReport(result) {
|
|
319
|
+
const { overallScore, threshold } = result;
|
|
320
|
+
console.log("");
|
|
321
|
+
console.log(chalk.bold.underline(`Compliance Report: ${result.frameworkName} (v${result.version})`));
|
|
322
|
+
console.log(chalk.dim(`Model: ${result.model} | Timestamp: ${result.timestamp}`));
|
|
323
|
+
console.log("");
|
|
324
|
+
// Overall score bar
|
|
325
|
+
const scoreColor = overallScore >= 80 ? chalk.green : overallScore >= 50 ? chalk.yellow : chalk.red;
|
|
326
|
+
const barLen = 30;
|
|
327
|
+
const filled = Math.round((overallScore / 100) * barLen);
|
|
328
|
+
const bar = scoreColor("\u2588".repeat(filled)) + chalk.dim("\u2591".repeat(barLen - filled));
|
|
329
|
+
console.log(` Overall Score: ${bar} ${scoreColor.bold(`${overallScore}%`)}`);
|
|
330
|
+
console.log("");
|
|
331
|
+
// Summary counts
|
|
332
|
+
console.log(` ${chalk.green(String(result.metCount))} met | ` +
|
|
333
|
+
`${chalk.yellow(String(result.partialCount))} partial | ` +
|
|
334
|
+
`${chalk.red(String(result.notMetCount))} not met | ` +
|
|
335
|
+
`${chalk.dim(String(result.untestedCount))} untested | ` +
|
|
336
|
+
`${chalk.bold(String(result.totalRequirements))} total`);
|
|
337
|
+
console.log("");
|
|
338
|
+
// Category breakdown
|
|
339
|
+
console.log(chalk.bold(" Category Breakdown:"));
|
|
340
|
+
for (const [catId, cat] of Object.entries(result.byCategory)) {
|
|
341
|
+
const catScore = cat.score;
|
|
342
|
+
const catColor = catScore >= 80 ? chalk.green : catScore >= 50 ? chalk.yellow : chalk.red;
|
|
343
|
+
console.log(` ${chalk.bold(cat.name)} ${chalk.dim(`(${catId})`)} — ${catColor.bold(`${catScore}%`)} ` +
|
|
344
|
+
chalk.dim(`[${cat.met} met, ${cat.partial} partial, ${cat.notMet} fail, ${cat.untested} untested]`));
|
|
345
|
+
}
|
|
346
|
+
console.log("");
|
|
347
|
+
// Requirements detail (show failures and partials first, then untested, then met)
|
|
348
|
+
const sortedReqs = [...result.requirements].sort((a, b) => {
|
|
349
|
+
const order = { "not-met": 0, partial: 1, untested: 2, met: 3 };
|
|
350
|
+
return (order[a.status] ?? 4) - (order[b.status] ?? 4);
|
|
351
|
+
});
|
|
352
|
+
const failures = sortedReqs.filter((r) => r.status === "not-met" || r.status === "partial");
|
|
353
|
+
if (failures.length > 0) {
|
|
354
|
+
console.log(chalk.bold(" Findings Requiring Attention:"));
|
|
355
|
+
for (const req of failures) {
|
|
356
|
+
console.log(` ${statusIcon(req.status)} ${chalk.bold(req.id)} ${req.title} ` +
|
|
357
|
+
chalk.dim(`[${severityColor(req.severity)}]`));
|
|
358
|
+
if (req.notes) {
|
|
359
|
+
console.log(` ${chalk.dim(req.notes)}`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
console.log("");
|
|
363
|
+
}
|
|
364
|
+
// Remediation steps
|
|
365
|
+
if (result.remediationSteps.length > 0) {
|
|
366
|
+
console.log(chalk.bold(" Remediation Plan:"));
|
|
367
|
+
const maxSteps = Math.min(result.remediationSteps.length, 10);
|
|
368
|
+
for (let i = 0; i < maxSteps; i++) {
|
|
369
|
+
const step = result.remediationSteps[i];
|
|
370
|
+
const effortBadge = step.effort === "high"
|
|
371
|
+
? chalk.red("[HIGH EFFORT]")
|
|
372
|
+
: step.effort === "medium"
|
|
373
|
+
? chalk.yellow("[MED EFFORT]")
|
|
374
|
+
: chalk.green("[LOW EFFORT]");
|
|
375
|
+
console.log(` ${chalk.bold(`${step.priority}.`)} ${severityColor(step.severity)} ${step.requirementTitle} ${effortBadge}`);
|
|
376
|
+
console.log(` ${chalk.dim(step.action)}`);
|
|
377
|
+
}
|
|
378
|
+
if (result.remediationSteps.length > maxSteps) {
|
|
379
|
+
console.log(chalk.dim(` ... and ${result.remediationSteps.length - maxSteps} more. Use --json for full details.`));
|
|
380
|
+
}
|
|
381
|
+
console.log("");
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// ─── Command Registration ───────────────────────────────────────────────────
|
|
385
|
+
export function registerComplianceCheck(program) {
|
|
386
|
+
program
|
|
387
|
+
.command("compliance-check")
|
|
388
|
+
.description("Check AI system compliance against regulatory frameworks")
|
|
389
|
+
.requiredOption("-f, --framework <id>", `Framework to check against (${SUPPORTED_FRAMEWORKS.join(", ")})`)
|
|
390
|
+
.option("-m, --model <model>", "Model to evaluate", "gpt-4o-mini")
|
|
391
|
+
.option("-p, --provider <provider>", "LLM provider override")
|
|
392
|
+
.option("-t, --threshold <number>", "Minimum compliance score (0-100) to pass", "70")
|
|
393
|
+
.option("--json", "Output results as JSON", false)
|
|
394
|
+
.option("--system-prompt <prompt>", "System prompt to test against")
|
|
395
|
+
.option("--config <path>", "Path to compliance config file (JSON)")
|
|
396
|
+
.action(async (opts) => {
|
|
397
|
+
// Validate framework
|
|
398
|
+
const frameworkId = opts.framework.toLowerCase();
|
|
399
|
+
if (!SUPPORTED_FRAMEWORKS.includes(frameworkId)) {
|
|
400
|
+
console.error(chalk.red(`Unknown framework: "${opts.framework}". Supported: ${SUPPORTED_FRAMEWORKS.join(", ")}`));
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
// Parse threshold
|
|
404
|
+
const threshold = parseInt(opts.threshold, 10);
|
|
405
|
+
if (isNaN(threshold) || threshold < 0 || threshold > 100) {
|
|
406
|
+
console.error(chalk.red(`Invalid threshold: "${opts.threshold}". Must be 0-100.`));
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
// Load config file if provided
|
|
410
|
+
let configOverrides = {};
|
|
411
|
+
if (opts.config) {
|
|
412
|
+
const configPath = path.resolve(opts.config);
|
|
413
|
+
if (!fs.existsSync(configPath)) {
|
|
414
|
+
console.error(chalk.red(`Config file not found: ${configPath}`));
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
configOverrides = JSON.parse(fs.readFileSync(configPath, "utf-8"));
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
console.error(chalk.red(`Failed to parse config file: ${err instanceof Error ? err.message : String(err)}`));
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const checkConfig = {
|
|
426
|
+
framework: frameworkId,
|
|
427
|
+
model: opts.model ?? configOverrides.model,
|
|
428
|
+
provider: opts.provider ?? configOverrides.provider,
|
|
429
|
+
systemPrompt: opts.systemPrompt ?? configOverrides.systemPrompt,
|
|
430
|
+
threshold,
|
|
431
|
+
};
|
|
432
|
+
const spinner = opts.json ? null : ora(`Running ${frameworkId} compliance check...`).start();
|
|
433
|
+
try {
|
|
434
|
+
let result;
|
|
435
|
+
const apiKey = getApiKey();
|
|
436
|
+
if (apiKey) {
|
|
437
|
+
if (spinner)
|
|
438
|
+
spinner.text = `Running ${frameworkId} compliance check via API...`;
|
|
439
|
+
result = await runRemoteCheck(checkConfig);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
if (spinner)
|
|
443
|
+
spinner.text = `Running ${frameworkId} compliance check locally...`;
|
|
444
|
+
result = await runLocalCheck(checkConfig);
|
|
445
|
+
}
|
|
446
|
+
spinner?.stop();
|
|
447
|
+
if (opts.json) {
|
|
448
|
+
console.log(JSON.stringify({
|
|
449
|
+
...result,
|
|
450
|
+
threshold,
|
|
451
|
+
passed: result.overallScore >= threshold,
|
|
452
|
+
}, null, 2));
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
printReport(result);
|
|
456
|
+
// Final verdict
|
|
457
|
+
if (result.overallScore >= threshold) {
|
|
458
|
+
console.log(chalk.green.bold(` PASSED Compliance score ${result.overallScore}% meets threshold ${threshold}%`));
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
console.log(chalk.red.bold(` FAILED Compliance score ${result.overallScore}% is below threshold ${threshold}%`));
|
|
462
|
+
}
|
|
463
|
+
console.log("");
|
|
464
|
+
}
|
|
465
|
+
// Exit code based on threshold
|
|
466
|
+
process.exit(result.overallScore >= threshold ? 0 : 1);
|
|
467
|
+
}
|
|
468
|
+
catch (err) {
|
|
469
|
+
spinner?.fail(`Compliance check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
470
|
+
process.exit(1);
|
|
471
|
+
}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
//# sourceMappingURL=compliance-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compliance-check.js","sourceRoot":"","sources":["../../src/commands/compliance-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../../src/commands/debug.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAoIpD"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
const CONFIG_DIR = path.join(os.homedir(), ".evalguard");
|
|
6
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
7
|
+
const PROVIDER_ENV_VARS = {
|
|
8
|
+
openai: ["OPENAI_API_KEY"],
|
|
9
|
+
anthropic: ["ANTHROPIC_API_KEY"],
|
|
10
|
+
google: ["GOOGLE_AI_API_KEY", "GOOGLE_API_KEY"],
|
|
11
|
+
azure: ["AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT"],
|
|
12
|
+
cohere: ["COHERE_API_KEY"],
|
|
13
|
+
mistral: ["MISTRAL_API_KEY"],
|
|
14
|
+
groq: ["GROQ_API_KEY"],
|
|
15
|
+
together: ["TOGETHER_API_KEY"],
|
|
16
|
+
replicate: ["REPLICATE_API_TOKEN"],
|
|
17
|
+
};
|
|
18
|
+
export function registerDebug(program) {
|
|
19
|
+
program
|
|
20
|
+
.command("debug")
|
|
21
|
+
.description("Debug provider/scorer configuration and API connectivity")
|
|
22
|
+
.option("-p, --provider <name>", "Test a specific provider connection")
|
|
23
|
+
.option("-v, --verbose", "Show detailed output including env var values (masked)", false)
|
|
24
|
+
.action(async (opts) => {
|
|
25
|
+
console.log();
|
|
26
|
+
console.log(chalk.bold(" EvalGuard Debug Info"));
|
|
27
|
+
console.log(chalk.dim(" " + "-".repeat(60)));
|
|
28
|
+
// 1. CLI Config
|
|
29
|
+
console.log();
|
|
30
|
+
console.log(chalk.bold(" Configuration"));
|
|
31
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
32
|
+
try {
|
|
33
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
|
|
34
|
+
const apiKey = config.apiKey;
|
|
35
|
+
if (apiKey) {
|
|
36
|
+
const masked = apiKey.substring(0, 7) + "..." + apiKey.substring(apiKey.length - 4);
|
|
37
|
+
console.log(` ${chalk.green("✓")} API Key: ${chalk.dim(masked)}`);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log(` ${chalk.yellow("!")} API Key: ${chalk.dim("not set")}`);
|
|
41
|
+
}
|
|
42
|
+
console.log(` ${chalk.dim(" Base URL:")} ${config.baseUrl ?? "https://evalguard.ai/api/v1"}`);
|
|
43
|
+
if (config.projectId) {
|
|
44
|
+
console.log(` ${chalk.dim(" Project:")} ${config.projectId}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
console.log(` ${chalk.red("✗")} Config file exists but is corrupt: ${CONFIG_FILE}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.log(` ${chalk.yellow("!")} No config file found at ${chalk.dim(CONFIG_FILE)}`);
|
|
53
|
+
console.log(chalk.dim(" Run `evalguard login` to authenticate."));
|
|
54
|
+
}
|
|
55
|
+
// 2. EvalGuard env vars
|
|
56
|
+
console.log();
|
|
57
|
+
console.log(chalk.bold(" Environment Variables"));
|
|
58
|
+
const evalguardEnv = ["EVALGUARD_API_KEY", "EVALGUARD_BASE_URL", "EVALGUARD_PROJECT_ID"];
|
|
59
|
+
for (const key of evalguardEnv) {
|
|
60
|
+
const val = process.env[key];
|
|
61
|
+
if (val) {
|
|
62
|
+
const masked = opts.verbose ? val.substring(0, 7) + "..." + val.substring(val.length - 4) : "(set)";
|
|
63
|
+
console.log(` ${chalk.green("✓")} ${key} = ${chalk.dim(masked)}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(` ${chalk.dim("-")} ${key} ${chalk.dim("not set")}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// 3. Provider env vars
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.bold(" Provider API Keys"));
|
|
72
|
+
const providersToCheck = opts.provider
|
|
73
|
+
? { [opts.provider]: PROVIDER_ENV_VARS[opts.provider] ?? [`${opts.provider.toUpperCase()}_API_KEY`] }
|
|
74
|
+
: PROVIDER_ENV_VARS;
|
|
75
|
+
for (const [provider, envVars] of Object.entries(providersToCheck)) {
|
|
76
|
+
const found = envVars.filter((v) => process.env[v]);
|
|
77
|
+
if (found.length > 0) {
|
|
78
|
+
console.log(` ${chalk.green("✓")} ${provider.padEnd(12)} ${chalk.dim(found.join(", "))}`);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log(` ${chalk.dim("-")} ${provider.padEnd(12)} ${chalk.dim(envVars.join(", ") + " not set")}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// 4. API connectivity test
|
|
85
|
+
console.log();
|
|
86
|
+
console.log(chalk.bold(" API Connectivity"));
|
|
87
|
+
try {
|
|
88
|
+
let config = {};
|
|
89
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
90
|
+
config = JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
|
|
91
|
+
}
|
|
92
|
+
const baseUrl = config.baseUrl ?? "https://evalguard.ai/api/v1";
|
|
93
|
+
const apiKey = config.apiKey ?? process.env.EVALGUARD_API_KEY;
|
|
94
|
+
if (!apiKey) {
|
|
95
|
+
console.log(` ${chalk.yellow("!")} Skipped — no API key configured`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const start = Date.now();
|
|
99
|
+
const res = await fetch(`${baseUrl}/health`, {
|
|
100
|
+
method: "GET",
|
|
101
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
102
|
+
signal: AbortSignal.timeout(10000),
|
|
103
|
+
});
|
|
104
|
+
const latency = Date.now() - start;
|
|
105
|
+
if (res.ok) {
|
|
106
|
+
console.log(` ${chalk.green("✓")} ${baseUrl} ${chalk.dim(`(${latency}ms)`)}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log(` ${chalk.red("✗")} ${baseUrl} — HTTP ${res.status} ${chalk.dim(`(${latency}ms)`)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.log(` ${chalk.red("✗")} Connection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
115
|
+
}
|
|
116
|
+
// 5. Local storage info
|
|
117
|
+
console.log();
|
|
118
|
+
console.log(chalk.bold(" Local Storage"));
|
|
119
|
+
const dbFile = path.join(CONFIG_DIR, "results.json");
|
|
120
|
+
if (fs.existsSync(dbFile)) {
|
|
121
|
+
const stat = fs.statSync(dbFile);
|
|
122
|
+
try {
|
|
123
|
+
const runs = JSON.parse(fs.readFileSync(dbFile, "utf-8"));
|
|
124
|
+
console.log(` ${chalk.green("✓")} ${runs.length} runs stored (${(stat.size / 1024).toFixed(1)} KB)`);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
console.log(` ${chalk.yellow("!")} Storage file exists but is corrupt`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
console.log(` ${chalk.dim("-")} No local runs stored yet`);
|
|
132
|
+
}
|
|
133
|
+
// 6. Node/platform info
|
|
134
|
+
console.log();
|
|
135
|
+
console.log(chalk.bold(" Runtime"));
|
|
136
|
+
console.log(` ${chalk.dim("Node:")} ${process.version}`);
|
|
137
|
+
console.log(` ${chalk.dim("Platform:")} ${process.platform} ${process.arch}`);
|
|
138
|
+
console.log(` ${chalk.dim("CWD:")} ${process.cwd()}`);
|
|
139
|
+
// Check for evalguard config files in CWD
|
|
140
|
+
const configFiles = ["evalguard.yaml", "evalguard.yml", "evalguard.config.json"];
|
|
141
|
+
const foundConfigs = configFiles.filter((f) => fs.existsSync(path.join(process.cwd(), f)));
|
|
142
|
+
if (foundConfigs.length > 0) {
|
|
143
|
+
console.log(` ${chalk.green("✓")} Config: ${foundConfigs.join(", ")}`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
console.log(` ${chalk.dim("-")} No evalguard config in CWD`);
|
|
147
|
+
}
|
|
148
|
+
console.log();
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=debug.js.map
|