vaspera 2.8.0 → 2.9.2
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/CHANGELOG.md +109 -7
- package/README.md +111 -7
- package/dist/__tests__/agents/adversary/tactics/api.test.d.ts +5 -0
- package/dist/__tests__/agents/adversary/tactics/api.test.d.ts.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/api.test.js +369 -0
- package/dist/__tests__/agents/adversary/tactics/api.test.js.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts +5 -0
- package/dist/__tests__/agents/adversary/tactics/llm.test.d.ts.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/llm.test.js +409 -0
- package/dist/__tests__/agents/adversary/tactics/llm.test.js.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts +7 -0
- package/dist/__tests__/agents/adversary/tactics/registry.test.d.ts.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/registry.test.js +74 -0
- package/dist/__tests__/agents/adversary/tactics/registry.test.js.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts +7 -0
- package/dist/__tests__/agents/adversary/tactics/web-app.test.d.ts.map +1 -0
- package/dist/__tests__/agents/adversary/tactics/web-app.test.js +374 -0
- package/dist/__tests__/agents/adversary/tactics/web-app.test.js.map +1 -0
- package/dist/__tests__/compliance-bundle.test.d.ts +9 -0
- package/dist/__tests__/compliance-bundle.test.d.ts.map +1 -0
- package/dist/__tests__/compliance-bundle.test.js +344 -0
- package/dist/__tests__/compliance-bundle.test.js.map +1 -0
- package/dist/__tests__/healthcare-compliance.test.d.ts +9 -0
- package/dist/__tests__/healthcare-compliance.test.d.ts.map +1 -0
- package/dist/__tests__/healthcare-compliance.test.js +233 -0
- package/dist/__tests__/healthcare-compliance.test.js.map +1 -0
- package/dist/action/diff-mode.d.ts +124 -8
- package/dist/action/diff-mode.d.ts.map +1 -1
- package/dist/action/diff-mode.js +384 -65
- package/dist/action/diff-mode.js.map +1 -1
- package/dist/action/diff-mode.test.js +3 -3
- package/dist/action/diff-mode.test.js.map +1 -1
- package/dist/action/pr-comment.test.js +1 -0
- package/dist/action/pr-comment.test.js.map +1 -1
- package/dist/action/sarif-upload.test.js +1 -0
- package/dist/action/sarif-upload.test.js.map +1 -1
- package/dist/agents/adversary/config.d.ts +25 -4
- package/dist/agents/adversary/config.d.ts.map +1 -1
- package/dist/agents/adversary/config.js +38 -8
- package/dist/agents/adversary/config.js.map +1 -1
- package/dist/agents/adversary/index.d.ts +7 -0
- package/dist/agents/adversary/index.d.ts.map +1 -1
- package/dist/agents/adversary/index.js +83 -1
- package/dist/agents/adversary/index.js.map +1 -1
- package/dist/agents/adversary/reporting/compliance-mapper.d.ts +108 -0
- package/dist/agents/adversary/reporting/compliance-mapper.d.ts.map +1 -0
- package/dist/agents/adversary/reporting/compliance-mapper.js +391 -0
- package/dist/agents/adversary/reporting/compliance-mapper.js.map +1 -0
- package/dist/agents/adversary/reporting/index.d.ts +10 -0
- package/dist/agents/adversary/reporting/index.d.ts.map +1 -0
- package/dist/agents/adversary/reporting/index.js +10 -0
- package/dist/agents/adversary/reporting/index.js.map +1 -0
- package/dist/agents/adversary/reporting/poc-generator.d.ts +44 -0
- package/dist/agents/adversary/reporting/poc-generator.d.ts.map +1 -0
- package/dist/agents/adversary/reporting/poc-generator.js +308 -0
- package/dist/agents/adversary/reporting/poc-generator.js.map +1 -0
- package/dist/agents/adversary/tactics/api.d.ts +13 -0
- package/dist/agents/adversary/tactics/api.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/api.js +815 -0
- package/dist/agents/adversary/tactics/api.js.map +1 -0
- package/dist/agents/adversary/tactics/auth.d.ts +13 -0
- package/dist/agents/adversary/tactics/auth.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/auth.js +676 -0
- package/dist/agents/adversary/tactics/auth.js.map +1 -0
- package/dist/agents/adversary/tactics/index.d.ts +129 -0
- package/dist/agents/adversary/tactics/index.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/index.js +199 -0
- package/dist/agents/adversary/tactics/index.js.map +1 -0
- package/dist/agents/adversary/tactics/infra.d.ts +13 -0
- package/dist/agents/adversary/tactics/infra.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/infra.js +827 -0
- package/dist/agents/adversary/tactics/infra.js.map +1 -0
- package/dist/agents/adversary/tactics/injection.d.ts +12 -0
- package/dist/agents/adversary/tactics/injection.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/injection.js +549 -0
- package/dist/agents/adversary/tactics/injection.js.map +1 -0
- package/dist/agents/adversary/tactics/llm.d.ts +13 -0
- package/dist/agents/adversary/tactics/llm.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/llm.js +767 -0
- package/dist/agents/adversary/tactics/llm.js.map +1 -0
- package/dist/agents/adversary/tactics/web-app.d.ts +13 -0
- package/dist/agents/adversary/tactics/web-app.d.ts.map +1 -0
- package/dist/agents/adversary/tactics/web-app.js +717 -0
- package/dist/agents/adversary/tactics/web-app.js.map +1 -0
- package/dist/agents/adversary/types.d.ts +66 -10
- package/dist/agents/adversary/types.d.ts.map +1 -1
- package/dist/agents/zero-day-hunter.d.ts +1 -1
- package/dist/agents/zero-day-hunter.d.ts.map +1 -1
- package/dist/analysis/data-flow.d.ts +154 -0
- package/dist/analysis/data-flow.d.ts.map +1 -0
- package/dist/analysis/data-flow.js +393 -0
- package/dist/analysis/data-flow.js.map +1 -0
- package/dist/analysis/index.d.ts +9 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +9 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/badge-service/index.d.ts +144 -0
- package/dist/badge-service/index.d.ts.map +1 -0
- package/dist/badge-service/index.js +206 -0
- package/dist/badge-service/index.js.map +1 -0
- package/dist/certification/types.d.ts +1 -1
- package/dist/certification/types.d.ts.map +1 -1
- package/dist/certification/types.js.map +1 -1
- package/dist/commands/certification/certify.d.ts.map +1 -1
- package/dist/commands/certification/certify.js +18 -4
- package/dist/commands/certification/certify.js.map +1 -1
- package/dist/compliance/attestation.d.ts +39 -0
- package/dist/compliance/attestation.d.ts.map +1 -0
- package/dist/compliance/attestation.js +364 -0
- package/dist/compliance/attestation.js.map +1 -0
- package/dist/compliance/cfr42-part2.d.ts +42 -0
- package/dist/compliance/cfr42-part2.d.ts.map +1 -0
- package/dist/compliance/cfr42-part2.js +408 -0
- package/dist/compliance/cfr42-part2.js.map +1 -0
- package/dist/compliance/compliance-bundle.d.ts +100 -0
- package/dist/compliance/compliance-bundle.d.ts.map +1 -0
- package/dist/compliance/compliance-bundle.js +210 -0
- package/dist/compliance/compliance-bundle.js.map +1 -0
- package/dist/compliance/healthcare-bundle.d.ts +68 -0
- package/dist/compliance/healthcare-bundle.d.ts.map +1 -0
- package/dist/compliance/healthcare-bundle.js +104 -0
- package/dist/compliance/healthcare-bundle.js.map +1 -0
- package/dist/compliance/hipaa.d.ts.map +1 -1
- package/dist/compliance/hipaa.js +14 -11
- package/dist/compliance/hipaa.js.map +1 -1
- package/dist/compliance/index.d.ts +10 -2
- package/dist/compliance/index.d.ts.map +1 -1
- package/dist/compliance/index.js +9 -3
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/mapper.d.ts.map +1 -1
- package/dist/compliance/mapper.js +3 -17
- package/dist/compliance/mapper.js.map +1 -1
- package/dist/compliance/nist-800-53.d.ts +22 -6
- package/dist/compliance/nist-800-53.d.ts.map +1 -1
- package/dist/compliance/nist-800-53.js +264 -272
- package/dist/compliance/nist-800-53.js.map +1 -1
- package/dist/compliance/report.d.ts +31 -2
- package/dist/compliance/report.d.ts.map +1 -1
- package/dist/compliance/report.js +255 -4
- package/dist/compliance/report.js.map +1 -1
- package/dist/compliance/types.d.ts +1 -1
- package/dist/compliance/types.d.ts.map +1 -1
- package/dist/config/flags.d.ts +12 -12
- package/dist/cost/index.d.ts +1 -1
- package/dist/cost/index.d.ts.map +1 -1
- package/dist/cost/index.js +1 -1
- package/dist/cost/index.js.map +1 -1
- package/dist/cost/tracker.d.ts +64 -0
- package/dist/cost/tracker.d.ts.map +1 -1
- package/dist/cost/tracker.js +165 -0
- package/dist/cost/tracker.js.map +1 -1
- package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +28 -0
- package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +1 -0
- package/dist/eval/fixtures/healthcare/audit-gaps.js +90 -0
- package/dist/eval/fixtures/healthcare/audit-gaps.js.map +1 -0
- package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +31 -0
- package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +1 -0
- package/dist/eval/fixtures/healthcare/consent-bypass.js +61 -0
- package/dist/eval/fixtures/healthcare/consent-bypass.js.map +1 -0
- package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +24 -0
- package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +1 -0
- package/dist/eval/fixtures/healthcare/phi-in-logs.js +41 -0
- package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +1 -0
- package/dist/evidence/collector.d.ts +21 -0
- package/dist/evidence/collector.d.ts.map +1 -0
- package/dist/evidence/collector.js +340 -0
- package/dist/evidence/collector.js.map +1 -0
- package/dist/evidence/index.d.ts +11 -0
- package/dist/evidence/index.d.ts.map +1 -0
- package/dist/evidence/index.js +12 -0
- package/dist/evidence/index.js.map +1 -0
- package/dist/evidence/store.d.ts +39 -0
- package/dist/evidence/store.d.ts.map +1 -0
- package/dist/evidence/store.js +173 -0
- package/dist/evidence/store.js.map +1 -0
- package/dist/evidence/types.d.ts +175 -0
- package/dist/evidence/types.d.ts.map +1 -0
- package/dist/evidence/types.js +9 -0
- package/dist/evidence/types.js.map +1 -0
- package/dist/exporters/checkmarx.d.ts +18 -0
- package/dist/exporters/checkmarx.d.ts.map +1 -0
- package/dist/exporters/checkmarx.js +203 -0
- package/dist/exporters/checkmarx.js.map +1 -0
- package/dist/exporters/index.d.ts +22 -0
- package/dist/exporters/index.d.ts.map +1 -0
- package/dist/exporters/index.js +41 -0
- package/dist/exporters/index.js.map +1 -0
- package/dist/exporters/snyk.d.ts +18 -0
- package/dist/exporters/snyk.d.ts.map +1 -0
- package/dist/exporters/snyk.js +119 -0
- package/dist/exporters/snyk.js.map +1 -0
- package/dist/exporters/sonarqube.d.ts +18 -0
- package/dist/exporters/sonarqube.d.ts.map +1 -0
- package/dist/exporters/sonarqube.js +125 -0
- package/dist/exporters/sonarqube.js.map +1 -0
- package/dist/exporters/types.d.ts +190 -0
- package/dist/exporters/types.d.ts.map +1 -0
- package/dist/exporters/types.js +9 -0
- package/dist/exporters/types.js.map +1 -0
- package/dist/frontier/index.d.ts +12 -0
- package/dist/frontier/index.d.ts.map +1 -0
- package/dist/frontier/index.js +12 -0
- package/dist/frontier/index.js.map +1 -0
- package/dist/frontier/orchestrator.d.ts +73 -0
- package/dist/frontier/orchestrator.d.ts.map +1 -0
- package/dist/frontier/orchestrator.js +312 -0
- package/dist/frontier/orchestrator.js.map +1 -0
- package/dist/frontier/providers/stub.d.ts +32 -0
- package/dist/frontier/providers/stub.d.ts.map +1 -0
- package/dist/frontier/providers/stub.js +66 -0
- package/dist/frontier/providers/stub.js.map +1 -0
- package/dist/frontier/types.d.ts +318 -0
- package/dist/frontier/types.d.ts.map +1 -0
- package/dist/frontier/types.js +27 -0
- package/dist/frontier/types.js.map +1 -0
- package/dist/history/index.d.ts +13 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +15 -0
- package/dist/history/index.js.map +1 -0
- package/dist/history/store.d.ts +74 -0
- package/dist/history/store.d.ts.map +1 -0
- package/dist/history/store.js +399 -0
- package/dist/history/store.js.map +1 -0
- package/dist/history/types.d.ts +282 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/history/types.js +41 -0
- package/dist/history/types.js.map +1 -0
- package/dist/history/verify.d.ts +44 -0
- package/dist/history/verify.d.ts.map +1 -0
- package/dist/history/verify.js +230 -0
- package/dist/history/verify.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +515 -19
- package/dist/index.js.map +1 -1
- package/dist/multimodel/index.d.ts +1 -0
- package/dist/multimodel/index.d.ts.map +1 -1
- package/dist/multimodel/index.js +2 -0
- package/dist/multimodel/index.js.map +1 -1
- package/dist/multimodel/leaderboard.d.ts +116 -0
- package/dist/multimodel/leaderboard.d.ts.map +1 -0
- package/dist/multimodel/leaderboard.js +262 -0
- package/dist/multimodel/leaderboard.js.map +1 -0
- package/dist/observability/otel.d.ts.map +1 -1
- package/dist/observability/otel.js +1 -3
- package/dist/observability/otel.js.map +1 -1
- package/dist/plugins/loader.js +1 -1
- package/dist/plugins/loader.js.map +1 -1
- package/dist/scanners/agent/agent-chain-analysis.d.ts +152 -0
- package/dist/scanners/agent/agent-chain-analysis.d.ts.map +1 -0
- package/dist/scanners/agent/agent-chain-analysis.js +438 -0
- package/dist/scanners/agent/agent-chain-analysis.js.map +1 -0
- package/dist/scanners/agent/payloads/index.d.ts +2 -1
- package/dist/scanners/agent/payloads/index.d.ts.map +1 -1
- package/dist/scanners/agent/payloads/index.js +25 -6
- package/dist/scanners/agent/payloads/index.js.map +1 -1
- package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
- package/dist/scanners/agent/prompt-injection-fuzzer.js +14 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
- package/dist/scanners/agent/types.d.ts +5 -5
- package/dist/scanners/agent/types.d.ts.map +1 -1
- package/dist/scanners/agent/types.js.map +1 -1
- package/dist/scanners/cache.d.ts +156 -0
- package/dist/scanners/cache.d.ts.map +1 -0
- package/dist/scanners/cache.js +462 -0
- package/dist/scanners/cache.js.map +1 -0
- package/dist/scanners/dependencies.js +4 -4
- package/dist/scanners/dependencies.js.map +1 -1
- package/dist/scanners/gosec.d.ts.map +1 -1
- package/dist/scanners/gosec.js +47 -9
- package/dist/scanners/gosec.js.map +1 -1
- package/dist/scanners/healthcare.d.ts +29 -0
- package/dist/scanners/healthcare.d.ts.map +1 -0
- package/dist/scanners/healthcare.js +526 -0
- package/dist/scanners/healthcare.js.map +1 -0
- package/dist/scanners/index.d.ts +1 -0
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +33 -0
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/index.test.js +6 -6
- package/dist/scanners/index.test.js.map +1 -1
- package/dist/scanners/secrets.js +4 -4
- package/dist/scanners/secrets.js.map +1 -1
- package/dist/scanners/semgrep.js +5 -5
- package/dist/scanners/semgrep.js.map +1 -1
- package/dist/scanners/types.d.ts +1 -1
- package/dist/scanners/types.d.ts.map +1 -1
- package/dist/scanners/types.js +1 -0
- package/dist/scanners/types.js.map +1 -1
- package/dist/scanners/typescript.test.js +1 -1
- package/dist/scanners/typescript.test.js.map +1 -1
- package/dist/telemetry/index.d.ts +10 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +10 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/registry.d.ts +178 -0
- package/dist/telemetry/registry.d.ts.map +1 -0
- package/dist/telemetry/registry.js +297 -0
- package/dist/telemetry/registry.js.map +1 -0
- package/dist/telemetry/usage.d.ts +197 -0
- package/dist/telemetry/usage.d.ts.map +1 -0
- package/dist/telemetry/usage.js +252 -0
- package/dist/telemetry/usage.js.map +1 -0
- package/package.json +2 -6
package/dist/index.js
CHANGED
|
@@ -30,13 +30,25 @@ import { getAIFrameworkControls, AI_FRAMEWORKS_METADATA, } from "./compliance/fr
|
|
|
30
30
|
// Evaluation harness
|
|
31
31
|
import { runEvaluation, runStabilityTest, calculateMetrics, calculateStabilityMetrics, meetsTargets, generateEvaluationReport, formatReportAsMarkdown, generateCompactSummary, generateReadmeBadges, getFixtureStats, ALL_FIXTURES, TARGET_METRICS, } from "./eval/index.js";
|
|
32
32
|
// Compliance frameworks
|
|
33
|
-
import { generateComplianceReport, generateMultiFrameworkReport, formatComplianceReportAsMarkdown, formatMultiFrameworkReportAsMarkdown, generateCompactComplianceSummary, getControlsForFramework,
|
|
33
|
+
import { generateComplianceReport, generateMultiFrameworkReport, formatComplianceReportAsMarkdown, formatMultiFrameworkReportAsMarkdown, generateCompactComplianceSummary, getControlsForFramework,
|
|
34
|
+
// Healthcare compliance
|
|
35
|
+
runHealthcareComplianceAssessment, generateHealthcareComplianceSummary,
|
|
36
|
+
// Universal audit-defensible compliance
|
|
37
|
+
runSingleFrameworkAssessment, runComplianceAssessment, generateComplianceSummary, } from "./compliance/index.js";
|
|
38
|
+
// Evidence collection and audit trail verification
|
|
39
|
+
import { collectEvidence, storeEvidenceBundle, formatEvidenceBundleAsMarkdown, } from "./evidence/index.js";
|
|
40
|
+
import { verifyHistoryIntegrity, formatVerificationResultAsMarkdown, } from "./history/verify.js";
|
|
34
41
|
// SBOM, Provenance, and Sigstore Signing (uses @sigstore/sign for real signing)
|
|
35
42
|
import { generateSBOM, generateSBOMSummary, generateProvenance, generateProvenanceSummary, verifyProvenance, signContent, isSigningAvailable, generateSigningSummary, detectCIEnvironment, } from "./sbom/index.js";
|
|
36
43
|
// Cost tracking
|
|
37
44
|
import { getTracker, formatCost, formatTokens, estimateCost, getSupportedModels, MODEL_PRICING, } from "./cost/index.js";
|
|
38
45
|
// Multi-model consensus
|
|
39
46
|
import { getRunner, DEFAULT_MODELS, formatProvider, } from "./multimodel/index.js";
|
|
47
|
+
// Path validation utilities
|
|
48
|
+
import { validateProjectPath, PathValidationError } from "./util/paths.js";
|
|
49
|
+
// Telemetry and scan registry
|
|
50
|
+
import { trackCertificationStarted, trackCertificationCompleted, trackScannerRun, } from "./telemetry/usage.js";
|
|
51
|
+
import { getRegistry } from "./telemetry/registry.js";
|
|
40
52
|
// ---------------------------------------------------------------------------
|
|
41
53
|
// Config
|
|
42
54
|
// ---------------------------------------------------------------------------
|
|
@@ -221,7 +233,17 @@ server.registerTool("hardening_install", {
|
|
|
221
233
|
openWorldHint: false,
|
|
222
234
|
},
|
|
223
235
|
}, async ({ project_path }) => {
|
|
224
|
-
|
|
236
|
+
// Validate path to prevent traversal attacks
|
|
237
|
+
let validatedPath;
|
|
238
|
+
try {
|
|
239
|
+
validatedPath = await validateProjectPath(project_path);
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
if (error instanceof PathValidationError) {
|
|
243
|
+
return {
|
|
244
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
225
247
|
return {
|
|
226
248
|
content: [
|
|
227
249
|
{
|
|
@@ -232,7 +254,7 @@ server.registerTool("hardening_install", {
|
|
|
232
254
|
};
|
|
233
255
|
}
|
|
234
256
|
try {
|
|
235
|
-
const commandsDir = join(
|
|
257
|
+
const commandsDir = join(validatedPath, ".claude", "commands");
|
|
236
258
|
await mkdir(commandsDir, { recursive: true });
|
|
237
259
|
const installed = [];
|
|
238
260
|
const errors = [];
|
|
@@ -248,7 +270,7 @@ server.registerTool("hardening_install", {
|
|
|
248
270
|
}
|
|
249
271
|
}
|
|
250
272
|
const output = {
|
|
251
|
-
project:
|
|
273
|
+
project: validatedPath,
|
|
252
274
|
commands_dir: commandsDir,
|
|
253
275
|
installed_commands: installed,
|
|
254
276
|
errors: errors.length > 0 ? errors : undefined,
|
|
@@ -295,7 +317,17 @@ server.registerTool("hardening_install_all", {
|
|
|
295
317
|
},
|
|
296
318
|
}, async ({ base_dir, dry_run = true }) => {
|
|
297
319
|
const dir = base_dir || DEFAULT_PROJECTS_DIR;
|
|
298
|
-
|
|
320
|
+
// Validate path to prevent traversal attacks
|
|
321
|
+
let validatedDir;
|
|
322
|
+
try {
|
|
323
|
+
validatedDir = await validateProjectPath(dir);
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
if (error instanceof PathValidationError) {
|
|
327
|
+
return {
|
|
328
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
299
331
|
return {
|
|
300
332
|
content: [
|
|
301
333
|
{
|
|
@@ -306,7 +338,7 @@ server.registerTool("hardening_install_all", {
|
|
|
306
338
|
};
|
|
307
339
|
}
|
|
308
340
|
try {
|
|
309
|
-
const projects = await discoverProjects(
|
|
341
|
+
const projects = await discoverProjects(validatedDir);
|
|
310
342
|
const commandCount = Object.keys(COMMANDS).length;
|
|
311
343
|
const results = [];
|
|
312
344
|
for (const projectPath of projects) {
|
|
@@ -347,7 +379,7 @@ server.registerTool("hardening_install_all", {
|
|
|
347
379
|
}
|
|
348
380
|
const output = {
|
|
349
381
|
mode: dry_run ? "dry-run" : "applied",
|
|
350
|
-
base_dir:
|
|
382
|
+
base_dir: validatedDir,
|
|
351
383
|
projects_scanned: projects.length,
|
|
352
384
|
commands_per_project: commandCount,
|
|
353
385
|
projects_updated: dry_run ? 0 : results.filter((r) => !r.error && r.commands_installed).length,
|
|
@@ -726,6 +758,12 @@ server.registerTool("certification_scan", {
|
|
|
726
758
|
project: basename(project_path),
|
|
727
759
|
});
|
|
728
760
|
scanLogger.info("scanners.starting", { scanners, auto_detect });
|
|
761
|
+
const startTime = Date.now();
|
|
762
|
+
// Track scan start via telemetry
|
|
763
|
+
const scannersToRun = auto_detect
|
|
764
|
+
? ["auto-detect"]
|
|
765
|
+
: Object.entries(scanners || {}).filter(([, v]) => v).map(([k]) => k);
|
|
766
|
+
await trackCertificationStarted(project_path, scannersToRun, [], auto_detect ? "auto" : "manual");
|
|
729
767
|
// Use auto-detection or manual scanner selection
|
|
730
768
|
let result;
|
|
731
769
|
let detectedLanguages;
|
|
@@ -739,6 +777,24 @@ server.registerTool("certification_scan", {
|
|
|
739
777
|
else {
|
|
740
778
|
result = await runAllScanners(project_path, scanners);
|
|
741
779
|
}
|
|
780
|
+
// Track scanner runs in telemetry
|
|
781
|
+
for (const scanner of Object.keys(result.byScanner)) {
|
|
782
|
+
await trackScannerRun(project_path, scanner, result.totalDuration / Object.keys(result.byScanner).length, // Approximate per-scanner duration
|
|
783
|
+
result.byScanner[scanner] || 0, !result.failedScanners.includes(scanner));
|
|
784
|
+
}
|
|
785
|
+
// Record scan in registry for analytics
|
|
786
|
+
const registry = getRegistry();
|
|
787
|
+
await registry.recordScan({
|
|
788
|
+
certificationId: certification_id,
|
|
789
|
+
projectPath: project_path,
|
|
790
|
+
scanDate: new Date().toISOString(),
|
|
791
|
+
duration: Date.now() - startTime,
|
|
792
|
+
findingsSummary: result.bySeverity,
|
|
793
|
+
totalFindings: result.totalFindings,
|
|
794
|
+
scannersRun: Object.keys(result.byScanner),
|
|
795
|
+
frameworksAssessed: [],
|
|
796
|
+
success: result.allSucceeded,
|
|
797
|
+
});
|
|
742
798
|
// If certification_id provided and submit_findings is true, submit to certification
|
|
743
799
|
if (certification_id && submit_findings && result.totalFindings > 0) {
|
|
744
800
|
const certFindings = scannerFindingsToCertificationFindings(result);
|
|
@@ -1247,6 +1303,87 @@ server.registerTool("agent_complete", {
|
|
|
1247
1303
|
};
|
|
1248
1304
|
});
|
|
1249
1305
|
// ---------------------------------------------------------------------------
|
|
1306
|
+
// Tool: Batch Submit Findings (for subagent JSON output)
|
|
1307
|
+
// ---------------------------------------------------------------------------
|
|
1308
|
+
server.registerTool("agent_batch_submit", {
|
|
1309
|
+
title: "Batch Submit Agent Findings",
|
|
1310
|
+
description: `Submit multiple findings from a subagent's JSON output. Use this when certification agents run as subagents (via Task tool) and output JSON instead of calling agent_submit_finding directly. Parses the agent's JSON output and submits all findings at once.`,
|
|
1311
|
+
inputSchema: {
|
|
1312
|
+
project_path: z.string().describe("Absolute path to the project root"),
|
|
1313
|
+
certification_id: z.string().describe("Certification ID"),
|
|
1314
|
+
agent: z.enum(["security", "reliability", "typesafety", "performance", "quality", "redteam"]),
|
|
1315
|
+
findings: z.array(z.object({
|
|
1316
|
+
id: z.string().describe("Finding ID (e.g., sec-001)"),
|
|
1317
|
+
severity: z.enum(["critical", "high", "medium", "low", "info"]),
|
|
1318
|
+
category: z.string().describe("Category of the finding"),
|
|
1319
|
+
file: z.string().optional().describe("File path where issue found"),
|
|
1320
|
+
line: z.number().optional().describe("Line number"),
|
|
1321
|
+
description: z.string().describe("Description of the issue"),
|
|
1322
|
+
evidence: z.string().describe("Evidence supporting the finding"),
|
|
1323
|
+
confidence: z.number().min(0).max(100).describe("Confidence score 0-100"),
|
|
1324
|
+
})).describe("Array of findings from subagent JSON output"),
|
|
1325
|
+
summary: z.object({
|
|
1326
|
+
total_findings: z.number(),
|
|
1327
|
+
by_severity: z.object({
|
|
1328
|
+
critical: z.number(),
|
|
1329
|
+
high: z.number(),
|
|
1330
|
+
medium: z.number(),
|
|
1331
|
+
low: z.number(),
|
|
1332
|
+
info: z.number(),
|
|
1333
|
+
}),
|
|
1334
|
+
confidence_score: z.number().min(0).max(100),
|
|
1335
|
+
coverage_areas: z.array(z.string()),
|
|
1336
|
+
notes: z.string().optional(),
|
|
1337
|
+
}).optional().describe("Optional summary to complete the agent run"),
|
|
1338
|
+
},
|
|
1339
|
+
annotations: {
|
|
1340
|
+
readOnlyHint: false,
|
|
1341
|
+
destructiveHint: false,
|
|
1342
|
+
idempotentHint: false,
|
|
1343
|
+
openWorldHint: false,
|
|
1344
|
+
},
|
|
1345
|
+
}, async ({ project_path, certification_id, agent, findings, summary }) => {
|
|
1346
|
+
const certLogger = createChildLogger({ certId: certification_id, agent });
|
|
1347
|
+
// Ensure agent is started
|
|
1348
|
+
let agentFindings = await getAgentFindings(project_path, certification_id, agent);
|
|
1349
|
+
if (!agentFindings) {
|
|
1350
|
+
certLogger.info("agent.started");
|
|
1351
|
+
agentFindings = await startAgent(project_path, certification_id, agent);
|
|
1352
|
+
}
|
|
1353
|
+
// Submit all findings
|
|
1354
|
+
const submitted = [];
|
|
1355
|
+
for (const finding of findings) {
|
|
1356
|
+
await submitFinding(project_path, certification_id, agent, finding);
|
|
1357
|
+
submitted.push({ id: finding.id, severity: finding.severity });
|
|
1358
|
+
certLogger.info("finding.submitted", {
|
|
1359
|
+
findingId: finding.id,
|
|
1360
|
+
severity: finding.severity,
|
|
1361
|
+
confidence: finding.confidence,
|
|
1362
|
+
});
|
|
1363
|
+
}
|
|
1364
|
+
// Complete agent if summary provided
|
|
1365
|
+
let completionResult = null;
|
|
1366
|
+
if (summary) {
|
|
1367
|
+
completionResult = await completeAgent(project_path, certification_id, agent, summary);
|
|
1368
|
+
certLogger.info("agent.completed", {
|
|
1369
|
+
totalFindings: summary.total_findings,
|
|
1370
|
+
confidenceScore: summary.confidence_score,
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
return {
|
|
1374
|
+
content: [{
|
|
1375
|
+
type: "text",
|
|
1376
|
+
text: JSON.stringify({
|
|
1377
|
+
agent,
|
|
1378
|
+
findingsSubmitted: submitted.length,
|
|
1379
|
+
findings: submitted,
|
|
1380
|
+
completed: !!summary,
|
|
1381
|
+
summary: completionResult?.summary,
|
|
1382
|
+
}, null, 2),
|
|
1383
|
+
}],
|
|
1384
|
+
};
|
|
1385
|
+
});
|
|
1386
|
+
// ---------------------------------------------------------------------------
|
|
1250
1387
|
// Tool: Cross-Verify Finding
|
|
1251
1388
|
// ---------------------------------------------------------------------------
|
|
1252
1389
|
server.registerTool("agent_cross_verify", {
|
|
@@ -1469,6 +1606,7 @@ server.registerTool("certification_finalize", {
|
|
|
1469
1606
|
},
|
|
1470
1607
|
}, async ({ project_path, certification_id }) => {
|
|
1471
1608
|
const certLogger = createChildLogger({ certId: certification_id, project: basename(project_path) });
|
|
1609
|
+
const startTime = Date.now();
|
|
1472
1610
|
const certification = await getCertification(project_path, certification_id);
|
|
1473
1611
|
if (!certification) {
|
|
1474
1612
|
certLogger.warn("certification.not_found");
|
|
@@ -1494,6 +1632,36 @@ server.registerTool("certification_finalize", {
|
|
|
1494
1632
|
}
|
|
1495
1633
|
// Generate artifacts
|
|
1496
1634
|
const artifacts = await writeCertificationArtifacts(project_path, finalCert);
|
|
1635
|
+
// Track certification completion via telemetry
|
|
1636
|
+
const severityCounts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
1637
|
+
let totalFindings = 0;
|
|
1638
|
+
for (const agentType of Object.keys(certification.agents || {})) {
|
|
1639
|
+
const agent = certification.agents[agentType];
|
|
1640
|
+
if (agent?.findings) {
|
|
1641
|
+
for (const finding of agent.findings) {
|
|
1642
|
+
severityCounts[finding.severity]++;
|
|
1643
|
+
totalFindings++;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
await trackCertificationCompleted(project_path, certification_id, finalCert.consensus?.certification_level || "BLOCKED", finalCert.consensus?.overall_score || 0, Date.now() - new Date(certification.metadata.started_at).getTime(), severityCounts, totalFindings, [] // frameworks
|
|
1648
|
+
);
|
|
1649
|
+
// Record in registry
|
|
1650
|
+
const registry = getRegistry();
|
|
1651
|
+
await registry.recordScan({
|
|
1652
|
+
certificationId: certification_id,
|
|
1653
|
+
projectPath: project_path,
|
|
1654
|
+
scanDate: new Date().toISOString(),
|
|
1655
|
+
level: finalCert.consensus?.certification_level || "BLOCKED",
|
|
1656
|
+
score: finalCert.consensus?.overall_score || 0,
|
|
1657
|
+
duration: Date.now() - startTime,
|
|
1658
|
+
findingsSummary: severityCounts,
|
|
1659
|
+
totalFindings,
|
|
1660
|
+
scannersRun: Object.keys(certification.agents || {}),
|
|
1661
|
+
frameworksAssessed: [],
|
|
1662
|
+
success: true,
|
|
1663
|
+
tags: ["certification-finalized"],
|
|
1664
|
+
});
|
|
1497
1665
|
certLogger.info("certification.finalized", {
|
|
1498
1666
|
level: finalCert.consensus?.certification_level,
|
|
1499
1667
|
score: finalCert.consensus?.overall_score,
|
|
@@ -2142,13 +2310,17 @@ server.registerTool("certification_eval_fixtures", {
|
|
|
2142
2310
|
// ---------------------------------------------------------------------------
|
|
2143
2311
|
server.registerTool("compliance_report", {
|
|
2144
2312
|
title: "Generate Compliance Report",
|
|
2145
|
-
description: `Generate a compliance report mapping certification findings to framework controls (SOC 2, ISO 27001
|
|
2313
|
+
description: `Generate a compliance report mapping certification findings to framework controls. Supports all major frameworks (SOC 2, ISO 27001, PCI-DSS, HIPAA, 42 CFR Part 2, GDPR, NIST 800-53, CIS). Enable audit-defensibility options for evidence collection and audit trail verification.`,
|
|
2146
2314
|
inputSchema: {
|
|
2147
2315
|
project_path: z.string().describe("Absolute path to the project root"),
|
|
2148
2316
|
certification_id: z.string().describe("Certification ID to assess"),
|
|
2149
2317
|
framework: z
|
|
2150
|
-
.enum(["SOC2", "ISO27001"])
|
|
2318
|
+
.enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"])
|
|
2151
2319
|
.describe("Compliance framework to assess"),
|
|
2320
|
+
collect_evidence: z.boolean().optional().describe("Collect evidence bundle for audit defensibility. Default: false"),
|
|
2321
|
+
verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: false"),
|
|
2322
|
+
store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true if collecting"),
|
|
2323
|
+
include_attestation: z.boolean().optional().describe("Include attestation section with methodology and scope. Default: true when audit features enabled"),
|
|
2152
2324
|
output_format: z
|
|
2153
2325
|
.enum(["markdown", "json", "summary"])
|
|
2154
2326
|
.optional()
|
|
@@ -2160,7 +2332,7 @@ server.registerTool("compliance_report", {
|
|
|
2160
2332
|
idempotentHint: true,
|
|
2161
2333
|
openWorldHint: false,
|
|
2162
2334
|
},
|
|
2163
|
-
}, async ({ project_path, certification_id, framework, output_format }) => {
|
|
2335
|
+
}, async ({ project_path, certification_id, framework, collect_evidence, verify_audit_trail, store_evidence, include_attestation, output_format }) => {
|
|
2164
2336
|
const certification = await getCertification(project_path, certification_id);
|
|
2165
2337
|
if (!certification) {
|
|
2166
2338
|
return errorResponse(`Certification ${certification_id} not found`);
|
|
@@ -2172,6 +2344,46 @@ server.registerTool("compliance_report", {
|
|
|
2172
2344
|
if (allFindings.length === 0) {
|
|
2173
2345
|
return errorResponse("No findings to assess. Run certification agents first.");
|
|
2174
2346
|
}
|
|
2347
|
+
// Check if audit-defensibility features are requested
|
|
2348
|
+
const useAuditFeatures = collect_evidence || verify_audit_trail;
|
|
2349
|
+
if (useAuditFeatures) {
|
|
2350
|
+
// Use the full compliance bundle for audit-defensible reports
|
|
2351
|
+
const result = await runSingleFrameworkAssessment({
|
|
2352
|
+
projectPath: project_path,
|
|
2353
|
+
findings: allFindings,
|
|
2354
|
+
framework: framework,
|
|
2355
|
+
certificationId: certification_id,
|
|
2356
|
+
collectEvidence: collect_evidence ?? false,
|
|
2357
|
+
verifyAuditTrail: verify_audit_trail ?? false,
|
|
2358
|
+
storeEvidence: store_evidence !== false,
|
|
2359
|
+
includeAttestation: include_attestation !== false,
|
|
2360
|
+
});
|
|
2361
|
+
if (output_format === "json") {
|
|
2362
|
+
return jsonResponse({
|
|
2363
|
+
status: result.status,
|
|
2364
|
+
complianceScore: result.report.status.complianceScore,
|
|
2365
|
+
riskScore: result.report.status.riskScore,
|
|
2366
|
+
auditVerification: result.auditVerification ? {
|
|
2367
|
+
verified: result.auditVerification.verified,
|
|
2368
|
+
chainIntegrity: result.auditVerification.chainIntegrity,
|
|
2369
|
+
} : undefined,
|
|
2370
|
+
evidenceBundle: result.evidenceBundle ? {
|
|
2371
|
+
id: result.evidenceBundle.id,
|
|
2372
|
+
bundleDigest: result.evidenceBundle.bundleDigest,
|
|
2373
|
+
signed: !!result.evidenceBundle.signature,
|
|
2374
|
+
} : undefined,
|
|
2375
|
+
evidencePath: result.evidencePath,
|
|
2376
|
+
report: result.report,
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
else if (output_format === "summary") {
|
|
2380
|
+
return textResponse(generateCompactComplianceSummary(result.report));
|
|
2381
|
+
}
|
|
2382
|
+
else {
|
|
2383
|
+
return textResponse(result.markdownReport);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
// Standard report without audit features
|
|
2175
2387
|
const report = generateComplianceReport(allFindings, framework, project_path, certification_id);
|
|
2176
2388
|
if (output_format === "json") {
|
|
2177
2389
|
return jsonResponse(report);
|
|
@@ -2188,16 +2400,20 @@ server.registerTool("compliance_report", {
|
|
|
2188
2400
|
// ---------------------------------------------------------------------------
|
|
2189
2401
|
server.registerTool("compliance_multi_report", {
|
|
2190
2402
|
title: "Multi-Framework Compliance Report",
|
|
2191
|
-
description: `Generate a compliance report across multiple frameworks (SOC 2
|
|
2403
|
+
description: `Generate a compliance report across multiple frameworks. Supports all major frameworks (SOC 2, ISO 27001, PCI-DSS, HIPAA, 42 CFR Part 2, GDPR, NIST 800-53, CIS). Shows comparative status and prioritized recommendations. Enable audit-defensibility options for evidence collection and audit trail verification.`,
|
|
2192
2404
|
inputSchema: {
|
|
2193
2405
|
project_path: z.string().describe("Absolute path to the project root"),
|
|
2194
2406
|
certification_id: z.string().describe("Certification ID to assess"),
|
|
2195
2407
|
frameworks: z
|
|
2196
|
-
.array(z.enum(["SOC2", "ISO27001"]))
|
|
2408
|
+
.array(z.enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"]))
|
|
2197
2409
|
.optional()
|
|
2198
|
-
.describe("Frameworks to assess. Default:
|
|
2410
|
+
.describe("Frameworks to assess. Default: SOC2, ISO27001"),
|
|
2411
|
+
collect_evidence: z.boolean().optional().describe("Collect evidence bundle for audit defensibility. Default: false"),
|
|
2412
|
+
verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: false"),
|
|
2413
|
+
store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true if collecting"),
|
|
2414
|
+
include_attestation: z.boolean().optional().describe("Include attestation section with methodology and scope. Default: true when audit features enabled"),
|
|
2199
2415
|
output_format: z
|
|
2200
|
-
.enum(["markdown", "json"])
|
|
2416
|
+
.enum(["markdown", "json", "summary"])
|
|
2201
2417
|
.optional()
|
|
2202
2418
|
.describe("Output format. Default: markdown"),
|
|
2203
2419
|
},
|
|
@@ -2207,7 +2423,7 @@ server.registerTool("compliance_multi_report", {
|
|
|
2207
2423
|
idempotentHint: true,
|
|
2208
2424
|
openWorldHint: false,
|
|
2209
2425
|
},
|
|
2210
|
-
}, async ({ project_path, certification_id, frameworks, output_format }) => {
|
|
2426
|
+
}, async ({ project_path, certification_id, frameworks, collect_evidence, verify_audit_trail, store_evidence, include_attestation, output_format }) => {
|
|
2211
2427
|
const certification = await getCertification(project_path, certification_id);
|
|
2212
2428
|
if (!certification) {
|
|
2213
2429
|
return errorResponse(`Certification ${certification_id} not found`);
|
|
@@ -2219,6 +2435,53 @@ server.registerTool("compliance_multi_report", {
|
|
|
2219
2435
|
return errorResponse("No findings to assess. Run certification agents first.");
|
|
2220
2436
|
}
|
|
2221
2437
|
const selectedFrameworks = (frameworks || ["SOC2", "ISO27001"]);
|
|
2438
|
+
// Check if audit-defensibility features are requested
|
|
2439
|
+
const useAuditFeatures = collect_evidence || verify_audit_trail;
|
|
2440
|
+
if (useAuditFeatures) {
|
|
2441
|
+
// Use the full compliance bundle for audit-defensible reports
|
|
2442
|
+
const result = await runComplianceAssessment({
|
|
2443
|
+
projectPath: project_path,
|
|
2444
|
+
findings: allFindings,
|
|
2445
|
+
frameworks: selectedFrameworks,
|
|
2446
|
+
certificationId: certification_id,
|
|
2447
|
+
collectEvidence: collect_evidence ?? false,
|
|
2448
|
+
verifyAuditTrail: verify_audit_trail ?? false,
|
|
2449
|
+
storeEvidence: store_evidence !== false,
|
|
2450
|
+
includeAttestation: include_attestation !== false,
|
|
2451
|
+
});
|
|
2452
|
+
if (output_format === "json") {
|
|
2453
|
+
return jsonResponse({
|
|
2454
|
+
status: result.status,
|
|
2455
|
+
combinedScore: result.combinedScore,
|
|
2456
|
+
frameworks: Object.fromEntries(Object.entries(result.reports).map(([fw, report]) => [
|
|
2457
|
+
fw,
|
|
2458
|
+
report ? {
|
|
2459
|
+
complianceScore: report.status.complianceScore,
|
|
2460
|
+
riskScore: report.status.riskScore,
|
|
2461
|
+
controlsNonCompliant: report.status.controlsNonCompliant,
|
|
2462
|
+
} : null,
|
|
2463
|
+
])),
|
|
2464
|
+
auditVerification: result.auditVerification ? {
|
|
2465
|
+
verified: result.auditVerification.verified,
|
|
2466
|
+
chainIntegrity: result.auditVerification.chainIntegrity,
|
|
2467
|
+
} : undefined,
|
|
2468
|
+
evidenceBundle: result.evidenceBundle ? {
|
|
2469
|
+
id: result.evidenceBundle.id,
|
|
2470
|
+
bundleDigest: result.evidenceBundle.bundleDigest,
|
|
2471
|
+
signed: !!result.evidenceBundle.signature,
|
|
2472
|
+
} : undefined,
|
|
2473
|
+
evidencePath: result.evidencePath,
|
|
2474
|
+
multiFrameworkReport: result.multiFrameworkReport,
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
else if (output_format === "summary") {
|
|
2478
|
+
return textResponse(generateComplianceSummary(result));
|
|
2479
|
+
}
|
|
2480
|
+
else {
|
|
2481
|
+
return textResponse(result.markdownReport);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
// Standard report without audit features
|
|
2222
2485
|
const report = generateMultiFrameworkReport(allFindings, selectedFrameworks, project_path, certification_id);
|
|
2223
2486
|
if (output_format === "json") {
|
|
2224
2487
|
return jsonResponse(report);
|
|
@@ -2232,10 +2495,10 @@ server.registerTool("compliance_multi_report", {
|
|
|
2232
2495
|
// ---------------------------------------------------------------------------
|
|
2233
2496
|
server.registerTool("compliance_controls", {
|
|
2234
2497
|
title: "List Compliance Controls",
|
|
2235
|
-
description: `List available compliance controls for a framework. Use to understand what controls are assessed and their mapping to finding categories.`,
|
|
2498
|
+
description: `List available compliance controls for a framework. Use to understand what controls are assessed and their mapping to finding categories. Supports all major frameworks.`,
|
|
2236
2499
|
inputSchema: {
|
|
2237
2500
|
framework: z
|
|
2238
|
-
.enum(["SOC2", "ISO27001"])
|
|
2501
|
+
.enum(["SOC2", "ISO27001", "PCI-DSS", "HIPAA", "42-CFR-PART-2", "GDPR", "NIST-800-53", "CIS"])
|
|
2239
2502
|
.describe("Compliance framework"),
|
|
2240
2503
|
category: z
|
|
2241
2504
|
.string()
|
|
@@ -2253,7 +2516,8 @@ server.registerTool("compliance_controls", {
|
|
|
2253
2516
|
if (category) {
|
|
2254
2517
|
controls = controls.filter((c) => c.category === category);
|
|
2255
2518
|
}
|
|
2256
|
-
|
|
2519
|
+
// Get unique categories from controls
|
|
2520
|
+
const categories = [...new Set(controls.map((c) => c.category))].sort();
|
|
2257
2521
|
return jsonResponse({
|
|
2258
2522
|
framework,
|
|
2259
2523
|
totalControls: controls.length,
|
|
@@ -2269,6 +2533,213 @@ server.registerTool("compliance_controls", {
|
|
|
2269
2533
|
});
|
|
2270
2534
|
});
|
|
2271
2535
|
// ---------------------------------------------------------------------------
|
|
2536
|
+
// Tool: Healthcare Compliance Scan (HIPAA + 42 CFR Part 2)
|
|
2537
|
+
// ---------------------------------------------------------------------------
|
|
2538
|
+
server.registerTool("healthcare_compliance_scan", {
|
|
2539
|
+
title: "Healthcare Compliance Assessment",
|
|
2540
|
+
description: `Run a combined HIPAA and 42 CFR Part 2 compliance assessment. Generates audit-defensible reports with evidence collection and audit trail verification. Designed for SUD (Substance Use Disorder) and healthcare applications.`,
|
|
2541
|
+
inputSchema: {
|
|
2542
|
+
project_path: z.string().describe("Absolute path to the project root"),
|
|
2543
|
+
certification_id: z.string().optional().describe("Certification ID to use findings from"),
|
|
2544
|
+
collect_evidence: z.boolean().optional().describe("Collect evidence bundle. Default: true"),
|
|
2545
|
+
verify_audit_trail: z.boolean().optional().describe("Verify audit trail integrity. Default: true"),
|
|
2546
|
+
store_evidence: z.boolean().optional().describe("Store evidence bundle to disk. Default: true"),
|
|
2547
|
+
output_format: z.enum(["markdown", "json", "summary"]).optional().describe("Output format. Default: markdown"),
|
|
2548
|
+
},
|
|
2549
|
+
annotations: {
|
|
2550
|
+
readOnlyHint: true,
|
|
2551
|
+
destructiveHint: false,
|
|
2552
|
+
idempotentHint: true,
|
|
2553
|
+
openWorldHint: false,
|
|
2554
|
+
},
|
|
2555
|
+
}, async ({ project_path, certification_id, collect_evidence, verify_audit_trail, store_evidence, output_format }) => {
|
|
2556
|
+
try {
|
|
2557
|
+
const validatedPath = await validateProjectPath(project_path);
|
|
2558
|
+
const allFindings = [];
|
|
2559
|
+
const certId = certification_id || undefined;
|
|
2560
|
+
let certificationToUse;
|
|
2561
|
+
if (certId) {
|
|
2562
|
+
certificationToUse = await getCertification(validatedPath, certId);
|
|
2563
|
+
}
|
|
2564
|
+
else {
|
|
2565
|
+
certificationToUse = await getLatestCertification(validatedPath);
|
|
2566
|
+
}
|
|
2567
|
+
if (certificationToUse) {
|
|
2568
|
+
const agents = Object.keys(certificationToUse.agents);
|
|
2569
|
+
for (const agent of agents) {
|
|
2570
|
+
const agentData = certificationToUse.agents[agent];
|
|
2571
|
+
if (agentData?.findings) {
|
|
2572
|
+
// Cast to any to avoid type conflicts between local and imported types
|
|
2573
|
+
allFindings.push(...agentData.findings);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
// Run healthcare compliance assessment
|
|
2578
|
+
const result = await runHealthcareComplianceAssessment({
|
|
2579
|
+
projectPath: validatedPath,
|
|
2580
|
+
// Healthcare bundle expects Finding[] from certification/types
|
|
2581
|
+
findings: allFindings,
|
|
2582
|
+
certificationId: certificationToUse?.metadata.id,
|
|
2583
|
+
collectEvidence: collect_evidence !== false,
|
|
2584
|
+
verifyAuditTrail: verify_audit_trail !== false,
|
|
2585
|
+
storeEvidence: store_evidence !== false,
|
|
2586
|
+
});
|
|
2587
|
+
if (output_format === "json") {
|
|
2588
|
+
return jsonResponse({
|
|
2589
|
+
status: result.status,
|
|
2590
|
+
combinedScore: result.combinedScore,
|
|
2591
|
+
hipaaScore: result.hipaaReport.status.complianceScore,
|
|
2592
|
+
cfr42Score: result.cfr42Report.status.complianceScore,
|
|
2593
|
+
hipaaControls: {
|
|
2594
|
+
total: result.hipaaReport.status.totalControls,
|
|
2595
|
+
compliant: result.hipaaReport.status.controlsCovered,
|
|
2596
|
+
atRisk: result.hipaaReport.status.controlsAtRisk,
|
|
2597
|
+
nonCompliant: result.hipaaReport.status.controlsNonCompliant,
|
|
2598
|
+
},
|
|
2599
|
+
cfr42Controls: {
|
|
2600
|
+
total: result.cfr42Report.status.totalControls,
|
|
2601
|
+
compliant: result.cfr42Report.status.controlsCovered,
|
|
2602
|
+
atRisk: result.cfr42Report.status.controlsAtRisk,
|
|
2603
|
+
nonCompliant: result.cfr42Report.status.controlsNonCompliant,
|
|
2604
|
+
},
|
|
2605
|
+
auditTrailVerified: result.auditVerification?.verified,
|
|
2606
|
+
evidenceBundleId: result.evidenceBundle?.id,
|
|
2607
|
+
evidencePath: result.evidencePath,
|
|
2608
|
+
});
|
|
2609
|
+
}
|
|
2610
|
+
else if (output_format === "summary") {
|
|
2611
|
+
return textResponse(generateHealthcareComplianceSummary(result));
|
|
2612
|
+
}
|
|
2613
|
+
return textResponse(result.markdownReport);
|
|
2614
|
+
}
|
|
2615
|
+
catch (error) {
|
|
2616
|
+
if (error instanceof PathValidationError) {
|
|
2617
|
+
return errorResponse(error.message);
|
|
2618
|
+
}
|
|
2619
|
+
return errorResponse(`Healthcare compliance scan failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2620
|
+
}
|
|
2621
|
+
});
|
|
2622
|
+
// ---------------------------------------------------------------------------
|
|
2623
|
+
// Tool: Verify Audit Trail
|
|
2624
|
+
// ---------------------------------------------------------------------------
|
|
2625
|
+
server.registerTool("verify_audit_trail", {
|
|
2626
|
+
title: "Verify Audit Trail Integrity",
|
|
2627
|
+
description: `Verify the tamper-evident audit trail by checking hash chains. Detects if any historical entries have been modified. Critical for healthcare compliance (HIPAA, 42 CFR Part 2) audit defensibility.`,
|
|
2628
|
+
inputSchema: {
|
|
2629
|
+
project_path: z.string().describe("Absolute path to the project root"),
|
|
2630
|
+
output_format: z.enum(["markdown", "json"]).optional().describe("Output format. Default: markdown"),
|
|
2631
|
+
},
|
|
2632
|
+
annotations: {
|
|
2633
|
+
readOnlyHint: true,
|
|
2634
|
+
destructiveHint: false,
|
|
2635
|
+
idempotentHint: true,
|
|
2636
|
+
openWorldHint: false,
|
|
2637
|
+
},
|
|
2638
|
+
}, async ({ project_path, output_format }) => {
|
|
2639
|
+
try {
|
|
2640
|
+
const validatedPath = await validateProjectPath(project_path);
|
|
2641
|
+
const result = await verifyHistoryIntegrity(validatedPath);
|
|
2642
|
+
if (output_format === "json") {
|
|
2643
|
+
return jsonResponse({
|
|
2644
|
+
verified: result.verified,
|
|
2645
|
+
projectPath: result.projectPath,
|
|
2646
|
+
verifiedAt: result.verifiedAt,
|
|
2647
|
+
totalEntries: result.totalEntries,
|
|
2648
|
+
entriesVerified: result.entriesVerified,
|
|
2649
|
+
entriesPassed: result.entriesPassed,
|
|
2650
|
+
entriesFailed: result.entriesFailed,
|
|
2651
|
+
chainIntegrity: result.chainIntegrity,
|
|
2652
|
+
genesisHash: result.genesisHash,
|
|
2653
|
+
headHash: result.headHash,
|
|
2654
|
+
failures: result.failures,
|
|
2655
|
+
});
|
|
2656
|
+
}
|
|
2657
|
+
return textResponse(formatVerificationResultAsMarkdown(result));
|
|
2658
|
+
}
|
|
2659
|
+
catch (error) {
|
|
2660
|
+
if (error instanceof PathValidationError) {
|
|
2661
|
+
return errorResponse(error.message);
|
|
2662
|
+
}
|
|
2663
|
+
return errorResponse(`Audit trail verification failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2664
|
+
}
|
|
2665
|
+
});
|
|
2666
|
+
// ---------------------------------------------------------------------------
|
|
2667
|
+
// Tool: Collect Evidence Bundle
|
|
2668
|
+
// ---------------------------------------------------------------------------
|
|
2669
|
+
server.registerTool("collect_evidence_bundle", {
|
|
2670
|
+
title: "Collect Evidence Bundle",
|
|
2671
|
+
description: `Collect and package audit evidence for compliance. Creates a cryptographically attested bundle of scan results, compliance reports, SBOM, and history snapshots. Essential for audit defensibility.`,
|
|
2672
|
+
inputSchema: {
|
|
2673
|
+
project_path: z.string().describe("Absolute path to the project root"),
|
|
2674
|
+
certification_id: z.string().optional().describe("Certification ID to associate with"),
|
|
2675
|
+
frameworks: z
|
|
2676
|
+
.array(z.enum(["HIPAA", "42-CFR-PART-2", "SOC2", "ISO27001", "PCI-DSS", "GDPR", "NIST-800-53", "CIS"]))
|
|
2677
|
+
.optional()
|
|
2678
|
+
.describe("Compliance frameworks to include reports for"),
|
|
2679
|
+
include_sbom: z.boolean().optional().describe("Include SBOM. Default: true"),
|
|
2680
|
+
include_history: z.boolean().optional().describe("Include history snapshot. Default: true"),
|
|
2681
|
+
include_scans: z.boolean().optional().describe("Include scan results. Default: true"),
|
|
2682
|
+
store: z.boolean().optional().describe("Store bundle to disk. Default: true"),
|
|
2683
|
+
output_format: z.enum(["markdown", "json"]).optional().describe("Output format. Default: markdown"),
|
|
2684
|
+
},
|
|
2685
|
+
annotations: {
|
|
2686
|
+
readOnlyHint: true,
|
|
2687
|
+
destructiveHint: false,
|
|
2688
|
+
idempotentHint: true,
|
|
2689
|
+
openWorldHint: false,
|
|
2690
|
+
},
|
|
2691
|
+
}, async ({ project_path, certification_id, frameworks, include_sbom, include_history, include_scans, store, output_format }) => {
|
|
2692
|
+
try {
|
|
2693
|
+
const validatedPath = await validateProjectPath(project_path);
|
|
2694
|
+
const result = await collectEvidence({
|
|
2695
|
+
projectPath: validatedPath,
|
|
2696
|
+
certificationId: certification_id,
|
|
2697
|
+
frameworks: frameworks,
|
|
2698
|
+
includeSbom: include_sbom !== false,
|
|
2699
|
+
includeHistory: include_history !== false,
|
|
2700
|
+
includeScanResults: include_scans !== false,
|
|
2701
|
+
});
|
|
2702
|
+
if (!result.success || !result.bundle) {
|
|
2703
|
+
return errorResponse(result.error || "Evidence collection failed");
|
|
2704
|
+
}
|
|
2705
|
+
let storedPath;
|
|
2706
|
+
if (store !== false) {
|
|
2707
|
+
storedPath = await storeEvidenceBundle(validatedPath, result.bundle);
|
|
2708
|
+
}
|
|
2709
|
+
if (output_format === "json") {
|
|
2710
|
+
return jsonResponse({
|
|
2711
|
+
success: true,
|
|
2712
|
+
bundleId: result.bundle.id,
|
|
2713
|
+
createdAt: result.bundle.createdAt,
|
|
2714
|
+
artifactCount: result.bundle.artifacts.length,
|
|
2715
|
+
bundleDigest: result.bundle.bundleDigest,
|
|
2716
|
+
storedPath,
|
|
2717
|
+
warnings: result.warnings,
|
|
2718
|
+
artifacts: result.bundle.artifacts.map((a) => ({
|
|
2719
|
+
type: a.type,
|
|
2720
|
+
name: a.name,
|
|
2721
|
+
sizeBytes: a.sizeBytes,
|
|
2722
|
+
digest: a.contentDigest,
|
|
2723
|
+
})),
|
|
2724
|
+
});
|
|
2725
|
+
}
|
|
2726
|
+
let output = formatEvidenceBundleAsMarkdown(result.bundle);
|
|
2727
|
+
if (storedPath) {
|
|
2728
|
+
output += `\n\n**Stored at:** \`${storedPath}\``;
|
|
2729
|
+
}
|
|
2730
|
+
if (result.warnings.length > 0) {
|
|
2731
|
+
output += `\n\n**Warnings:**\n${result.warnings.map((w) => `- ${w}`).join("\n")}`;
|
|
2732
|
+
}
|
|
2733
|
+
return textResponse(output);
|
|
2734
|
+
}
|
|
2735
|
+
catch (error) {
|
|
2736
|
+
if (error instanceof PathValidationError) {
|
|
2737
|
+
return errorResponse(error.message);
|
|
2738
|
+
}
|
|
2739
|
+
return errorResponse(`Evidence collection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2740
|
+
}
|
|
2741
|
+
});
|
|
2742
|
+
// ---------------------------------------------------------------------------
|
|
2272
2743
|
// Tool: Generate SBOM
|
|
2273
2744
|
// ---------------------------------------------------------------------------
|
|
2274
2745
|
server.registerTool("sbom_generate", {
|
|
@@ -3212,7 +3683,11 @@ Maps findings to AI compliance frameworks (OWASP LLM, NIST AI RMF, EU AI Act).`,
|
|
|
3212
3683
|
if (!authorized) {
|
|
3213
3684
|
return errorResponse("Agent scanning requires explicit authorization. Set authorized=true to confirm you have permission to scan this target.");
|
|
3214
3685
|
}
|
|
3686
|
+
const startTime = Date.now();
|
|
3215
3687
|
try {
|
|
3688
|
+
// Track scan start via telemetry
|
|
3689
|
+
const enabledScanners = scanners || AGENT_SCANNER_TYPES;
|
|
3690
|
+
await trackCertificationStarted(target, enabledScanners, frameworks || [], "agent-cert");
|
|
3216
3691
|
// Build scan target
|
|
3217
3692
|
const scanTarget = {};
|
|
3218
3693
|
if (target.startsWith("http://") || target.startsWith("https://")) {
|
|
@@ -3228,7 +3703,6 @@ Maps findings to AI compliance frameworks (OWASP LLM, NIST AI RMF, EU AI Act).`,
|
|
|
3228
3703
|
scanTarget.npmPackage = target;
|
|
3229
3704
|
}
|
|
3230
3705
|
// Build scanner options
|
|
3231
|
-
const enabledScanners = scanners || AGENT_SCANNER_TYPES;
|
|
3232
3706
|
const scannerFlags = {
|
|
3233
3707
|
manifestAudit: enabledScanners.includes("manifest-audit"),
|
|
3234
3708
|
toolDrift: enabledScanners.includes("tool-description-drift"),
|
|
@@ -3267,6 +3741,28 @@ Maps findings to AI compliance frameworks (OWASP LLM, NIST AI RMF, EU AI Act).`,
|
|
|
3267
3741
|
}
|
|
3268
3742
|
// Generate summary
|
|
3269
3743
|
const summary = generateAgentScannerSummary(result);
|
|
3744
|
+
// Record scan in registry for analytics
|
|
3745
|
+
const registry = getRegistry();
|
|
3746
|
+
await registry.recordScan({
|
|
3747
|
+
certificationId: certification_id,
|
|
3748
|
+
projectPath: target,
|
|
3749
|
+
scanDate: new Date().toISOString(),
|
|
3750
|
+
level: result.certificationReadiness === "ready" ? "CERTIFIED"
|
|
3751
|
+
: result.certificationReadiness === "needs-review" ? "REVIEW_REQUIRED"
|
|
3752
|
+
: "BLOCKED",
|
|
3753
|
+
score: 100 - result.riskScore,
|
|
3754
|
+
duration: Date.now() - startTime,
|
|
3755
|
+
findingsSummary: result.bySeverity,
|
|
3756
|
+
totalFindings: result.totalFindings,
|
|
3757
|
+
scannersRun: result.scanners.map((s) => s.scanner),
|
|
3758
|
+
frameworksAssessed: frameworks || [],
|
|
3759
|
+
success: result.allSucceeded,
|
|
3760
|
+
tags: ["agent-cert", "mcp-security"],
|
|
3761
|
+
});
|
|
3762
|
+
// Track individual scanner runs
|
|
3763
|
+
for (const scanner of result.scanners) {
|
|
3764
|
+
await trackScannerRun(target, scanner.scanner, scanner.duration || 0, scanner.findings.length, scanner.success);
|
|
3765
|
+
}
|
|
3270
3766
|
return jsonResponse({
|
|
3271
3767
|
success: result.allSucceeded,
|
|
3272
3768
|
target,
|