vaspera 2.14.0 → 2.15.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/CHANGELOG.md +45 -0
- package/README.md +15 -2
- package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts +2 -0
- package/dist/__tests__/certification/agent-certificate-e2e.test.d.ts.map +1 -0
- package/dist/__tests__/certification/agent-certificate-e2e.test.js +90 -0
- package/dist/__tests__/certification/agent-certificate-e2e.test.js.map +1 -0
- package/dist/__tests__/certification/agent-certificate-map.test.d.ts +2 -0
- package/dist/__tests__/certification/agent-certificate-map.test.d.ts.map +1 -0
- package/dist/__tests__/certification/agent-certificate-map.test.js +107 -0
- package/dist/__tests__/certification/agent-certificate-map.test.js.map +1 -0
- package/dist/__tests__/certification/agent-certificate.test.d.ts +2 -0
- package/dist/__tests__/certification/agent-certificate.test.d.ts.map +1 -0
- package/dist/__tests__/certification/agent-certificate.test.js +78 -0
- package/dist/__tests__/certification/agent-certificate.test.js.map +1 -0
- package/dist/__tests__/certification/verify-endpoint.test.d.ts +2 -0
- package/dist/__tests__/certification/verify-endpoint.test.d.ts.map +1 -0
- package/dist/__tests__/certification/verify-endpoint.test.js +81 -0
- package/dist/__tests__/certification/verify-endpoint.test.js.map +1 -0
- package/dist/__tests__/compliance/ai-frameworks.test.d.ts +2 -0
- package/dist/__tests__/compliance/ai-frameworks.test.d.ts.map +1 -0
- package/dist/__tests__/compliance/ai-frameworks.test.js +87 -0
- package/dist/__tests__/compliance/ai-frameworks.test.js.map +1 -0
- package/dist/__tests__/eval/llm-analyzer.test.d.ts +2 -0
- package/dist/__tests__/eval/llm-analyzer.test.d.ts.map +1 -0
- package/dist/__tests__/eval/llm-analyzer.test.js +93 -0
- package/dist/__tests__/eval/llm-analyzer.test.js.map +1 -0
- package/dist/__tests__/eval/redteam-harness.test.d.ts +2 -0
- package/dist/__tests__/eval/redteam-harness.test.d.ts.map +1 -0
- package/dist/__tests__/eval/redteam-harness.test.js +136 -0
- package/dist/__tests__/eval/redteam-harness.test.js.map +1 -0
- package/dist/__tests__/evidence/evidence.test.d.ts +2 -0
- package/dist/__tests__/evidence/evidence.test.d.ts.map +1 -0
- package/dist/__tests__/evidence/evidence.test.js +240 -0
- package/dist/__tests__/evidence/evidence.test.js.map +1 -0
- package/dist/__tests__/history/decisions.test.d.ts +2 -0
- package/dist/__tests__/history/decisions.test.d.ts.map +1 -0
- package/dist/__tests__/history/decisions.test.js +54 -0
- package/dist/__tests__/history/decisions.test.js.map +1 -0
- package/dist/__tests__/http-auth.test.d.ts +2 -0
- package/dist/__tests__/http-auth.test.d.ts.map +1 -0
- package/dist/__tests__/http-auth.test.js +55 -0
- package/dist/__tests__/http-auth.test.js.map +1 -0
- package/dist/__tests__/http-policy.test.d.ts +2 -0
- package/dist/__tests__/http-policy.test.d.ts.map +1 -0
- package/dist/__tests__/http-policy.test.js +69 -0
- package/dist/__tests__/http-policy.test.js.map +1 -0
- package/dist/__tests__/http-server-transport.test.d.ts +2 -0
- package/dist/__tests__/http-server-transport.test.d.ts.map +1 -0
- package/dist/__tests__/http-server-transport.test.js +132 -0
- package/dist/__tests__/http-server-transport.test.js.map +1 -0
- package/dist/__tests__/integration/destructive-guards.test.d.ts +2 -0
- package/dist/__tests__/integration/destructive-guards.test.d.ts.map +1 -0
- package/dist/__tests__/integration/destructive-guards.test.js +49 -0
- package/dist/__tests__/integration/destructive-guards.test.js.map +1 -0
- package/dist/__tests__/logger-redaction.test.d.ts +2 -0
- package/dist/__tests__/logger-redaction.test.d.ts.map +1 -0
- package/dist/__tests__/logger-redaction.test.js +74 -0
- package/dist/__tests__/logger-redaction.test.js.map +1 -0
- package/dist/__tests__/manifest-schema.test.d.ts +2 -0
- package/dist/__tests__/manifest-schema.test.d.ts.map +1 -0
- package/dist/__tests__/manifest-schema.test.js +43 -0
- package/dist/__tests__/manifest-schema.test.js.map +1 -0
- package/dist/__tests__/scanners/builtin-rules.test.d.ts +2 -0
- package/dist/__tests__/scanners/builtin-rules.test.d.ts.map +1 -0
- package/dist/__tests__/scanners/builtin-rules.test.js +51 -0
- package/dist/__tests__/scanners/builtin-rules.test.js.map +1 -0
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js +13 -1
- package/dist/__tests__/scanners/runtime/golden-path-runner.test.js.map +1 -1
- package/dist/__tests__/tool-guard.test.d.ts +2 -0
- package/dist/__tests__/tool-guard.test.d.ts.map +1 -0
- package/dist/__tests__/tool-guard.test.js +97 -0
- package/dist/__tests__/tool-guard.test.js.map +1 -0
- package/dist/__tests__/util/contained-file.test.d.ts +2 -0
- package/dist/__tests__/util/contained-file.test.d.ts.map +1 -0
- package/dist/__tests__/util/contained-file.test.js +78 -0
- package/dist/__tests__/util/contained-file.test.js.map +1 -0
- package/dist/__tests__/util/subprocess.test.d.ts +2 -0
- package/dist/__tests__/util/subprocess.test.d.ts.map +1 -0
- package/dist/__tests__/util/subprocess.test.js +48 -0
- package/dist/__tests__/util/subprocess.test.js.map +1 -0
- package/dist/action/diff-mode.d.ts.map +1 -1
- package/dist/action/diff-mode.js +31 -12
- package/dist/action/diff-mode.js.map +1 -1
- package/dist/certification/agent-certificate-map.d.ts +51 -0
- package/dist/certification/agent-certificate-map.d.ts.map +1 -0
- package/dist/certification/agent-certificate-map.js +265 -0
- package/dist/certification/agent-certificate-map.js.map +1 -0
- package/dist/certification/agent-certificate-sample.d.ts +25 -0
- package/dist/certification/agent-certificate-sample.d.ts.map +1 -0
- package/dist/certification/agent-certificate-sample.js +207 -0
- package/dist/certification/agent-certificate-sample.js.map +1 -0
- package/dist/certification/agent-certificate.d.ts +1981 -0
- package/dist/certification/agent-certificate.d.ts.map +1 -0
- package/dist/certification/agent-certificate.js +309 -0
- package/dist/certification/agent-certificate.js.map +1 -0
- package/dist/certification/autofix.d.ts.map +1 -1
- package/dist/certification/autofix.js +5 -3
- package/dist/certification/autofix.js.map +1 -1
- package/dist/certification/store.d.ts.map +1 -1
- package/dist/certification/store.js +5 -2
- package/dist/certification/store.js.map +1 -1
- package/dist/certification/verify-endpoint.d.ts +48 -0
- package/dist/certification/verify-endpoint.d.ts.map +1 -0
- package/dist/certification/verify-endpoint.js +79 -0
- package/dist/certification/verify-endpoint.js.map +1 -0
- package/dist/compliance/index.d.ts +2 -0
- package/dist/compliance/index.d.ts.map +1 -1
- package/dist/compliance/index.js +4 -0
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/iso42001.d.ts +21 -0
- package/dist/compliance/iso42001.d.ts.map +1 -0
- package/dist/compliance/iso42001.js +160 -0
- package/dist/compliance/iso42001.js.map +1 -0
- package/dist/compliance/mapper.d.ts.map +1 -1
- package/dist/compliance/mapper.js +12 -0
- package/dist/compliance/mapper.js.map +1 -1
- package/dist/compliance/nist-ai-rmf.d.ts +20 -0
- package/dist/compliance/nist-ai-rmf.d.ts.map +1 -0
- package/dist/compliance/nist-ai-rmf.js +140 -0
- package/dist/compliance/nist-ai-rmf.js.map +1 -0
- package/dist/config/flags.d.ts +4 -4
- package/dist/eval/fixtures.d.ts.map +1 -1
- package/dist/eval/fixtures.js +161 -119
- package/dist/eval/fixtures.js.map +1 -1
- package/dist/eval/fixtures.test.js +4 -2
- package/dist/eval/fixtures.test.js.map +1 -1
- package/dist/eval/llm-analyzer.d.ts +40 -0
- package/dist/eval/llm-analyzer.d.ts.map +1 -0
- package/dist/eval/llm-analyzer.js +154 -0
- package/dist/eval/llm-analyzer.js.map +1 -0
- package/dist/eval/redteam-harness.d.ts +95 -0
- package/dist/eval/redteam-harness.d.ts.map +1 -0
- package/dist/eval/redteam-harness.js +137 -0
- package/dist/eval/redteam-harness.js.map +1 -0
- package/dist/evidence/collector.d.ts.map +1 -1
- package/dist/evidence/collector.js +21 -1
- package/dist/evidence/collector.js.map +1 -1
- package/dist/evidence/store.d.ts.map +1 -1
- package/dist/evidence/store.js +29 -5
- package/dist/evidence/store.js.map +1 -1
- package/dist/evidence/types.d.ts +16 -9
- package/dist/evidence/types.d.ts.map +1 -1
- package/dist/history/decisions.d.ts +63 -0
- package/dist/history/decisions.d.ts.map +1 -0
- package/dist/history/decisions.js +60 -0
- package/dist/history/decisions.js.map +1 -0
- package/dist/history/index.d.ts +2 -0
- package/dist/history/index.d.ts.map +1 -1
- package/dist/history/index.js +2 -0
- package/dist/history/index.js.map +1 -1
- package/dist/history/types.d.ts +34 -5
- package/dist/history/types.d.ts.map +1 -1
- package/dist/history/types.js +2 -0
- package/dist/history/types.js.map +1 -1
- package/dist/http-auth.d.ts +22 -0
- package/dist/http-auth.d.ts.map +1 -0
- package/dist/http-auth.js +58 -0
- package/dist/http-auth.js.map +1 -0
- package/dist/http-policy.d.ts +30 -0
- package/dist/http-policy.d.ts.map +1 -0
- package/dist/http-policy.js +54 -0
- package/dist/http-policy.js.map +1 -0
- package/dist/http-server.js +195 -12
- package/dist/http-server.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +247 -15
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +56 -2
- package/dist/logger.js.map +1 -1
- package/dist/plugins/types.d.ts +2 -2
- package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -1
- package/dist/scanners/agent/prompt-injection-fuzzer.js +26 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -1
- package/dist/scanners/agent/types.d.ts +10 -10
- package/dist/scanners/bandit.d.ts.map +1 -1
- package/dist/scanners/bandit.js +35 -29
- package/dist/scanners/bandit.js.map +1 -1
- package/dist/scanners/binary-analysis.d.ts.map +1 -1
- package/dist/scanners/binary-analysis.js +24 -49
- package/dist/scanners/binary-analysis.js.map +1 -1
- package/dist/scanners/brakeman.d.ts.map +1 -1
- package/dist/scanners/brakeman.js +19 -33
- package/dist/scanners/brakeman.js.map +1 -1
- package/dist/scanners/builtin-rules.d.ts +24 -0
- package/dist/scanners/builtin-rules.d.ts.map +1 -0
- package/dist/scanners/builtin-rules.js +175 -0
- package/dist/scanners/builtin-rules.js.map +1 -0
- package/dist/scanners/dast.d.ts.map +1 -1
- package/dist/scanners/dast.js +24 -34
- package/dist/scanners/dast.js.map +1 -1
- package/dist/scanners/deploy/types.d.ts +6 -6
- package/dist/scanners/eslint.d.ts.map +1 -1
- package/dist/scanners/eslint.js +15 -24
- package/dist/scanners/eslint.js.map +1 -1
- package/dist/scanners/gosec.d.ts.map +1 -1
- package/dist/scanners/gosec.js +14 -62
- package/dist/scanners/gosec.js.map +1 -1
- package/dist/scanners/index.d.ts.map +1 -1
- package/dist/scanners/index.js +38 -7
- package/dist/scanners/index.js.map +1 -1
- package/dist/scanners/memory-safety.d.ts.map +1 -1
- package/dist/scanners/memory-safety.js +27 -28
- package/dist/scanners/memory-safety.js.map +1 -1
- package/dist/scanners/openapi.d.ts.map +1 -1
- package/dist/scanners/openapi.js +14 -22
- package/dist/scanners/openapi.js.map +1 -1
- package/dist/scanners/race-condition.d.ts.map +1 -1
- package/dist/scanners/race-condition.js +17 -16
- package/dist/scanners/race-condition.js.map +1 -1
- package/dist/scanners/runtime/types.d.ts +4 -4
- package/dist/scanners/rust.d.ts.map +1 -1
- package/dist/scanners/rust.js +38 -37
- package/dist/scanners/rust.js.map +1 -1
- package/dist/scanners/scale/types.d.ts +16 -16
- package/dist/scanners/secrets.d.ts.map +1 -1
- package/dist/scanners/secrets.js +66 -78
- package/dist/scanners/secrets.js.map +1 -1
- package/dist/scanners/semgrep.d.ts +2 -0
- package/dist/scanners/semgrep.d.ts.map +1 -1
- package/dist/scanners/semgrep.js +12 -0
- package/dist/scanners/semgrep.js.map +1 -1
- package/dist/scanners/terraform.d.ts.map +1 -1
- package/dist/scanners/terraform.js +47 -40
- package/dist/scanners/terraform.js.map +1 -1
- package/dist/scanners/trivy.d.ts.map +1 -1
- package/dist/scanners/trivy.js +38 -30
- package/dist/scanners/trivy.js.map +1 -1
- package/dist/tool-guard.d.ts +40 -0
- package/dist/tool-guard.d.ts.map +1 -0
- package/dist/tool-guard.js +55 -0
- package/dist/tool-guard.js.map +1 -0
- package/dist/util/index.d.ts +2 -1
- package/dist/util/index.d.ts.map +1 -1
- package/dist/util/index.js +2 -1
- package/dist/util/index.js.map +1 -1
- package/dist/util/paths.d.ts +20 -3
- package/dist/util/paths.d.ts.map +1 -1
- package/dist/util/paths.js +84 -4
- package/dist/util/paths.js.map +1 -1
- package/dist/util/subprocess.d.ts +51 -0
- package/dist/util/subprocess.d.ts.map +1 -0
- package/dist/util/subprocess.js +77 -0
- package/dist/util/subprocess.js.map +1 -0
- package/package.json +12 -2
- package/dist/eval/fixtures/healthcare/audit-gaps.d.ts +0 -28
- package/dist/eval/fixtures/healthcare/audit-gaps.d.ts.map +0 -1
- package/dist/eval/fixtures/healthcare/audit-gaps.js +0 -90
- package/dist/eval/fixtures/healthcare/audit-gaps.js.map +0 -1
- package/dist/eval/fixtures/healthcare/consent-bypass.d.ts +0 -31
- package/dist/eval/fixtures/healthcare/consent-bypass.d.ts.map +0 -1
- package/dist/eval/fixtures/healthcare/consent-bypass.js +0 -61
- package/dist/eval/fixtures/healthcare/consent-bypass.js.map +0 -1
- package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts +0 -24
- package/dist/eval/fixtures/healthcare/phi-in-logs.d.ts.map +0 -1
- package/dist/eval/fixtures/healthcare/phi-in-logs.js +0 -41
- package/dist/eval/fixtures/healthcare/phi-in-logs.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.15.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#61](https://github.com/RCOLKITT/hardening-mcp/pull/61) [`1ecf11d`](https://github.com/RCOLKITT/hardening-mcp/commit/1ecf11dbc073af3430e6df17d0792e2b87ad2568) Thanks [@RCOLKITT](https://github.com/RCOLKITT)! - Agent Certification, independent verification, accuracy + red-team benchmarks, and hardening.
|
|
8
|
+
|
|
9
|
+
**Agent Certification**
|
|
10
|
+
|
|
11
|
+
- Versioned, signable agent certificate schema (six dimensions) with deterministic content digest; `agent_certificate_generate` / `agent_certificate_verify` MCP tools.
|
|
12
|
+
- ISO 42001 + NIST AI RMF compliance mappings and tamper-evident decision provenance (`decision_record`) on the hash chain.
|
|
13
|
+
- EU AI Act control mapping wired into the certification path (31 controls).
|
|
14
|
+
|
|
15
|
+
**Independent verification (don't trust us — verify)**
|
|
16
|
+
|
|
17
|
+
- Standalone certificate verifier: `npm run verify:cert` CLI and a public, unauthenticated `POST /verify` HTTP endpoint that re-checks schema, content digest, and signature without trusting the issuer.
|
|
18
|
+
|
|
19
|
+
**Measured accuracy + red-team**
|
|
20
|
+
|
|
21
|
+
- Accuracy benchmark (`npm run benchmark`, `npm run benchmark:llm`) over labeled fixtures with precision/recall/F1; built-in Semgrep taint rules took deterministic recall from ~10% to ~63% (added SQLi/cmd/SSRF, then insecure-deserialization + XXE), precision 100%.
|
|
22
|
+
- LLM-layer + Anthropic/OpenAI cross-model consensus benchmark.
|
|
23
|
+
- Red-team resistance harness (`npm run benchmark:redteam`) — reproducible prompt-injection resistance score + tool-scope/exfil exposure; fixed a false-positive bug that flagged 100% of tools.
|
|
24
|
+
|
|
25
|
+
**Integrity + supply chain**
|
|
26
|
+
|
|
27
|
+
- Evidence bundles can now be Sigstore-signed and their signatures are really verified (was a presence-only stub).
|
|
28
|
+
- Published manifest now exposes real per-tool input schemas (was an empty placeholder for all tools).
|
|
29
|
+
- Resolved a transitive esbuild advisory.
|
|
30
|
+
|
|
31
|
+
**Hardening (potentially breaking for three tools)**
|
|
32
|
+
|
|
33
|
+
- `deploy_vercel_promote`, `deploy_vercel_rollback`, and `consensus_clear` are now fail-closed: they return a no-op preview unless called with `confirm: true`. Callers that previously relied on these executing immediately must now pass `confirm: true`.
|
|
34
|
+
|
|
3
35
|
## [2.14.0] - 2026-06-05
|
|
4
36
|
|
|
5
37
|
### Added
|
|
6
38
|
|
|
7
39
|
#### Antagonist Agent
|
|
40
|
+
|
|
8
41
|
- New meta-analysis agent that runs after all other agents complete
|
|
9
42
|
- **Synthesis mode**: Chains findings into attack narratives mapped to MITRE ATT&CK kill chain
|
|
10
43
|
- **Challenger mode**: Internal critic that flags false positives, coverage gaps, and inconsistencies
|
|
@@ -13,22 +46,26 @@
|
|
|
13
46
|
- New `antagonist_challenge` tool - manually challenge specific findings
|
|
14
47
|
|
|
15
48
|
#### Attack Narrative Features
|
|
49
|
+
|
|
16
50
|
- Builds attack graphs from findings and exploit chains
|
|
17
51
|
- Maps vulnerabilities to 14 MITRE ATT&CK kill chain phases
|
|
18
52
|
- Identifies bottleneck findings that block multiple attack paths
|
|
19
53
|
- Generates human-readable attack stories with difficulty/likelihood ratings
|
|
20
54
|
|
|
21
55
|
#### Challenger Features
|
|
56
|
+
|
|
22
57
|
- Detects potential false positives (test files, low confidence, generic descriptions)
|
|
23
58
|
- Identifies untested attack vectors (17 categories tracked)
|
|
24
59
|
- Flags agents with zero findings as potentially incomplete
|
|
25
60
|
- Calculates coverage score across attack surface
|
|
26
61
|
|
|
27
62
|
### Fixed
|
|
63
|
+
|
|
28
64
|
- Empty catch blocks in `store.ts` and `signing.ts` now log errors
|
|
29
65
|
- Antagonist agent integration test types corrected
|
|
30
66
|
|
|
31
67
|
### Changed
|
|
68
|
+
|
|
32
69
|
- MCP tools increased from 108 to 110
|
|
33
70
|
- New agent type `antagonist` with weight 0.15 (informs but doesn't dominate consensus)
|
|
34
71
|
- Added to AGENT_VERIFICATION_MAP (verified by security, adversary, redteam)
|
|
@@ -38,17 +75,20 @@
|
|
|
38
75
|
### Added
|
|
39
76
|
|
|
40
77
|
#### False Positive Feedback System
|
|
78
|
+
|
|
41
79
|
- New `feedback_submit` tool to mark findings as true/false positives
|
|
42
80
|
- New `feedback_report` tool to view FP rates by scanner and rule
|
|
43
81
|
- New `feedback_suppressions` tool to get rule suppression suggestions based on feedback
|
|
44
82
|
- Feedback stored in `.vaspera/fp-feedback.json` with full audit trail
|
|
45
83
|
|
|
46
84
|
#### Diff-Aware CI Scanning
|
|
85
|
+
|
|
47
86
|
- New `certification_scan_diff` tool scans only changed files (git diff)
|
|
48
87
|
- Estimates scan time savings vs full scan
|
|
49
88
|
- Auto-detects security-critical files that always get scanned
|
|
50
89
|
|
|
51
90
|
#### Standalone Autofix Preview
|
|
91
|
+
|
|
52
92
|
- `autofix_preview` now works without certification_id
|
|
53
93
|
- Provide file + pattern_id to preview fixes directly
|
|
54
94
|
- Use `autofix_list_patterns` to see available fix patterns
|
|
@@ -56,27 +96,32 @@
|
|
|
56
96
|
### Fixed
|
|
57
97
|
|
|
58
98
|
#### Persistence DB Fallback
|
|
99
|
+
|
|
59
100
|
- Added JSON file fallback when SQLite is unavailable
|
|
60
101
|
- New `src/persistence/json-fallback.ts` with atomic writes
|
|
61
102
|
- Graceful degradation: warns but continues operating
|
|
62
103
|
|
|
63
104
|
#### scale_bottlenecks False Positives
|
|
105
|
+
|
|
64
106
|
- Added semantic analysis for workflow/pipeline patterns
|
|
65
107
|
- Confidence scoring (60-100) based on context
|
|
66
108
|
- Sequential workflows no longer flagged as N+1 queries
|
|
67
109
|
|
|
68
110
|
#### ai_code_verify Diagnostics
|
|
111
|
+
|
|
69
112
|
- Returns detailed diagnostics when 0 files found
|
|
70
113
|
- Shows which extensions were searched
|
|
71
114
|
- Reports which exclude patterns matched
|
|
72
115
|
- Suggests alternative file extensions
|
|
73
116
|
|
|
74
117
|
#### Scanner Error Messages
|
|
118
|
+
|
|
75
119
|
- Added `ScannerErrorDetails` with actionable suggestions
|
|
76
120
|
- tsc/eslint now report phase (init/scan/parse) and fix steps
|
|
77
121
|
- Full error output available for debugging
|
|
78
122
|
|
|
79
123
|
### Changed
|
|
124
|
+
|
|
80
125
|
- MCP tools increased from 103 to 108
|
|
81
126
|
|
|
82
127
|
## 2.10.0
|
package/README.md
CHANGED
|
@@ -2,12 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
Enterprise-grade security certification for codebases **and AI agent systems** with deterministic scanners, LLM-powered analysis, and signed attestations.
|
|
4
4
|
|
|
5
|
+
[](https://github.com/RCOLKITT/hardening-mcp/actions/workflows/certify.yml)
|
|
6
|
+
[](https://github.com/RCOLKITT/hardening-mcp/actions/workflows/ci.yml)
|
|
5
7
|

|
|
6
8
|

|
|
7
|
-

|
|
8
10
|

|
|
9
11
|

|
|
10
|
-

|
|
13
|
+
|
|
14
|
+
> **We pass our own strictest certification on every commit.** The
|
|
15
|
+
> Self-Certification badge above is the live result of running this
|
|
16
|
+
> product against its own codebase as a blocking CI gate — the one claim
|
|
17
|
+
> a scanner-wrapper can't fake. [How it works »](docs/SELF-CERTIFICATION.md)
|
|
18
|
+
>
|
|
19
|
+
> **Don't trust us — verify.** Any agent certificate can be checked
|
|
20
|
+
> independently (`npm run verify:cert -- cert.json`, or `POST /verify`)
|
|
21
|
+
> with no token and no trust in Vaspera: it recomputes the content digest
|
|
22
|
+
> and checks the signature from the certificate itself.
|
|
23
|
+
> [Verifying a certificate »](docs/VERIFYING-A-CERTIFICATE.md)
|
|
11
24
|
|
|
12
25
|
---
|
|
13
26
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate-e2e.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate-e2e.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { mkdtemp, rm } from "fs/promises";
|
|
3
|
+
import { tmpdir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
import { recordDecision, getDecisionProvenance } from "../../history/decisions.js";
|
|
6
|
+
import { certificationToCertificateBody } from "../../certification/agent-certificate-map.js";
|
|
7
|
+
import { finalizeCertificate, verifyCertificate } from "../../certification/agent-certificate.js";
|
|
8
|
+
function certification() {
|
|
9
|
+
return {
|
|
10
|
+
metadata: {
|
|
11
|
+
id: "cert_e2e",
|
|
12
|
+
project_name: "e2e-agent",
|
|
13
|
+
project_path: "/tmp/e2e-agent",
|
|
14
|
+
started_at: "2026-06-12T00:00:00.000Z",
|
|
15
|
+
completed_at: "2026-06-12T00:05:00.000Z",
|
|
16
|
+
status: "completed",
|
|
17
|
+
agents_requested: ["security"],
|
|
18
|
+
agents_completed: ["security"],
|
|
19
|
+
certification_level: "APPROVED",
|
|
20
|
+
final_score: 84,
|
|
21
|
+
project_hash: "deadbeef",
|
|
22
|
+
},
|
|
23
|
+
agents: {
|
|
24
|
+
security: {
|
|
25
|
+
agent: "security",
|
|
26
|
+
started_at: "2026-06-12T00:00:00.000Z",
|
|
27
|
+
completed_at: "2026-06-12T00:03:00.000Z",
|
|
28
|
+
status: "completed",
|
|
29
|
+
findings: [
|
|
30
|
+
{
|
|
31
|
+
id: "f1",
|
|
32
|
+
severity: "high",
|
|
33
|
+
category: "exfil-path",
|
|
34
|
+
description: "Secret can reach the network",
|
|
35
|
+
evidence: "…",
|
|
36
|
+
confidence: 95,
|
|
37
|
+
verifications: [],
|
|
38
|
+
created_at: "2026-06-12T00:01:00.000Z",
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
cross_verifications: [],
|
|
44
|
+
red_team_challenges: [],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
describe("agent certificate — full flow (decisions + frameworks + provenance)", () => {
|
|
48
|
+
let dir;
|
|
49
|
+
beforeEach(async () => {
|
|
50
|
+
dir = await mkdtemp(join(tmpdir(), "cert-e2e-"));
|
|
51
|
+
});
|
|
52
|
+
afterEach(async () => {
|
|
53
|
+
await rm(dir, { recursive: true, force: true });
|
|
54
|
+
});
|
|
55
|
+
it("records decisions, builds a certificate with real frameworks + provenance, verifies", async () => {
|
|
56
|
+
// 1) capture decision provenance on the hash chain
|
|
57
|
+
await recordDecision(dir, { decisionType: "tool_call", model: "m", input: "x", output: "y" });
|
|
58
|
+
await recordDecision(dir, { decisionType: "gen", model: "m", input: "p", output: "q" });
|
|
59
|
+
const provenance = await getDecisionProvenance(dir);
|
|
60
|
+
expect(provenance.decisionRecords).toBe(2);
|
|
61
|
+
// 2) build a certificate from a real certification + AI frameworks + provenance
|
|
62
|
+
const body = certificationToCertificateBody(certification(), {
|
|
63
|
+
toolVersion: "2.14.0",
|
|
64
|
+
issuedAt: "2026-06-12T00:00:00.000Z",
|
|
65
|
+
expiresAt: "2026-09-10T00:00:00.000Z",
|
|
66
|
+
certificateId: "vac_e2e_1",
|
|
67
|
+
complianceFrameworks: ["ISO-42001", "NIST-AI-RMF"],
|
|
68
|
+
provenance,
|
|
69
|
+
});
|
|
70
|
+
// compliance dimension is real (mapped controls, not a label)
|
|
71
|
+
expect(body.dimensions.compliance.frameworks.map((f) => f.framework)).toEqual([
|
|
72
|
+
"ISO-42001",
|
|
73
|
+
"NIST-AI-RMF",
|
|
74
|
+
]);
|
|
75
|
+
expect(body.dimensions.compliance.frameworks[0].controlsTotal).toBeGreaterThan(0);
|
|
76
|
+
// the exfil-path finding should fail at least one control
|
|
77
|
+
const totalFailed = body.dimensions.compliance.frameworks.reduce((n, f) => n + f.controlsFailed, 0);
|
|
78
|
+
expect(totalFailed).toBeGreaterThan(0);
|
|
79
|
+
// explainability reflects the recorded decisions
|
|
80
|
+
expect(body.dimensions.explainability.checks.some((c) => c.id === "decision-provenance")).toBe(true);
|
|
81
|
+
expect(body.provenance.decisionRecords).toBe(2);
|
|
82
|
+
expect(body.provenance.auditTrailHead).toBe(provenance.auditTrailHead);
|
|
83
|
+
// 3) finalize + verify independently
|
|
84
|
+
const cert = await finalizeCertificate(body);
|
|
85
|
+
const result = await verifyCertificate(cert);
|
|
86
|
+
expect(result.valid).toBe(true);
|
|
87
|
+
expect(result.contentDigestValid).toBe(true);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
//# sourceMappingURL=agent-certificate-e2e.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate-e2e.test.js","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate-e2e.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate-map.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate-map.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { certificationToCertificateBody, baselineCertificateBody, } from "../../certification/agent-certificate-map.js";
|
|
3
|
+
import { finalizeCertificate, verifyCertificate, } from "../../certification/agent-certificate.js";
|
|
4
|
+
const opts = {
|
|
5
|
+
toolVersion: "2.14.0",
|
|
6
|
+
issuedAt: "2026-06-11T00:00:00.000Z",
|
|
7
|
+
expiresAt: "2026-09-09T00:00:00.000Z",
|
|
8
|
+
certificateId: "vac_map_0001",
|
|
9
|
+
};
|
|
10
|
+
function fakeCertification() {
|
|
11
|
+
return {
|
|
12
|
+
metadata: {
|
|
13
|
+
id: "cert_1",
|
|
14
|
+
project_name: "demo-agent",
|
|
15
|
+
project_path: "/tmp/demo-agent",
|
|
16
|
+
started_at: "2026-06-11T00:00:00.000Z",
|
|
17
|
+
completed_at: "2026-06-11T00:05:00.000Z",
|
|
18
|
+
status: "completed",
|
|
19
|
+
agents_requested: ["security", "quality"],
|
|
20
|
+
agents_completed: ["security", "quality"],
|
|
21
|
+
certification_level: "APPROVED",
|
|
22
|
+
final_score: 82,
|
|
23
|
+
project_hash: "abc123def456",
|
|
24
|
+
},
|
|
25
|
+
agents: {
|
|
26
|
+
security: {
|
|
27
|
+
agent: "security",
|
|
28
|
+
started_at: "2026-06-11T00:00:00.000Z",
|
|
29
|
+
completed_at: "2026-06-11T00:03:00.000Z",
|
|
30
|
+
status: "completed",
|
|
31
|
+
findings: [
|
|
32
|
+
{
|
|
33
|
+
id: "f1",
|
|
34
|
+
severity: "high",
|
|
35
|
+
category: "prompt-injection",
|
|
36
|
+
file: "src/agent.ts",
|
|
37
|
+
line: 42,
|
|
38
|
+
description: "Untrusted input flows into the system prompt",
|
|
39
|
+
evidence: "…",
|
|
40
|
+
confidence: 90,
|
|
41
|
+
verifications: [],
|
|
42
|
+
created_at: "2026-06-11T00:01:00.000Z",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "f2",
|
|
46
|
+
severity: "low",
|
|
47
|
+
category: "logging-failure",
|
|
48
|
+
description: "Missing structured logging",
|
|
49
|
+
evidence: "…",
|
|
50
|
+
confidence: 70,
|
|
51
|
+
verifications: [],
|
|
52
|
+
created_at: "2026-06-11T00:02:00.000Z",
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
quality: {
|
|
57
|
+
agent: "quality",
|
|
58
|
+
started_at: "2026-06-11T00:00:00.000Z",
|
|
59
|
+
completed_at: "2026-06-11T00:04:00.000Z",
|
|
60
|
+
status: "completed",
|
|
61
|
+
findings: [],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
cross_verifications: [],
|
|
65
|
+
red_team_challenges: [],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
describe("certificationToCertificateBody", () => {
|
|
69
|
+
it("maps a real certification into a verifiable certificate", async () => {
|
|
70
|
+
const body = certificationToCertificateBody(fakeCertification(), opts);
|
|
71
|
+
expect(body.subject.name).toBe("demo-agent");
|
|
72
|
+
expect(body.subject.digest).toBe("abc123def456");
|
|
73
|
+
expect(body.level).toBe("APPROVED");
|
|
74
|
+
expect(body.overallScore).toBe(82);
|
|
75
|
+
// security has a high finding -> fail status, surfaced as a check
|
|
76
|
+
expect(body.dimensions.security.status).toBe("fail");
|
|
77
|
+
expect(body.dimensions.security.checks.some((c) => c.category === "prompt-injection")).toBe(true);
|
|
78
|
+
// quality had no findings -> pass
|
|
79
|
+
expect(body.dimensions.quality.status).toBe("pass");
|
|
80
|
+
// compliance not run -> not_assessed (never fabricated)
|
|
81
|
+
expect(body.dimensions.compliance.status).toBe("not_assessed");
|
|
82
|
+
const cert = await finalizeCertificate(body);
|
|
83
|
+
const result = await verifyCertificate(cert);
|
|
84
|
+
expect(result.valid).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it("surfaces the most severe findings first and caps the list", () => {
|
|
87
|
+
const c = fakeCertification();
|
|
88
|
+
const body = certificationToCertificateBody(c, opts);
|
|
89
|
+
expect(body.dimensions.security.checks[0].severity).toBe("high");
|
|
90
|
+
});
|
|
91
|
+
it("baseline body is honest — all dimensions not_assessed and verifiable", async () => {
|
|
92
|
+
const body = baselineCertificateBody({
|
|
93
|
+
...opts,
|
|
94
|
+
subjectName: "fresh-agent",
|
|
95
|
+
subjectKind: "agent",
|
|
96
|
+
identifier: "/tmp/fresh-agent",
|
|
97
|
+
});
|
|
98
|
+
expect(body.overallScore).toBe(0);
|
|
99
|
+
expect(body.level).toBe("REVIEW_REQUIRED");
|
|
100
|
+
for (const dim of Object.values(body.dimensions)) {
|
|
101
|
+
expect(dim.status).toBe("not_assessed");
|
|
102
|
+
}
|
|
103
|
+
const cert = await finalizeCertificate(body);
|
|
104
|
+
expect((await verifyCertificate(cert)).valid).toBe(true);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=agent-certificate-map.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate-map.test.js","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate-map.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { finalizeCertificate, verifyCertificate, canonicalize, computeContentDigest, parseCertificate, CertificateError, AgentCertificateSchema, AGENT_CERTIFICATE_SCHEMA, } from "../../certification/agent-certificate.js";
|
|
3
|
+
import { buildSampleCertificateBody } from "../../certification/agent-certificate-sample.js";
|
|
4
|
+
const sampleOpts = {
|
|
5
|
+
toolVersion: "2.14.0",
|
|
6
|
+
issuedAt: "2026-06-11T00:00:00.000Z",
|
|
7
|
+
expiresAt: "2026-09-09T00:00:00.000Z",
|
|
8
|
+
certificateId: "vac_test_0001",
|
|
9
|
+
};
|
|
10
|
+
function body() {
|
|
11
|
+
return buildSampleCertificateBody(sampleOpts);
|
|
12
|
+
}
|
|
13
|
+
describe("agent certificate", () => {
|
|
14
|
+
it("finalizes a valid body with a content digest", async () => {
|
|
15
|
+
const cert = await finalizeCertificate(body());
|
|
16
|
+
expect(cert.schemaVersion).toBe(AGENT_CERTIFICATE_SCHEMA);
|
|
17
|
+
expect(cert.integrity.algorithm).toBe("sha256");
|
|
18
|
+
expect(cert.integrity.contentDigest).toMatch(/^[a-f0-9]{64}$/);
|
|
19
|
+
// digest is over the body alone (no signature when unsigned)
|
|
20
|
+
expect(cert.signature).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
it("produces a deterministic digest regardless of key order", async () => {
|
|
23
|
+
const a = await finalizeCertificate(body());
|
|
24
|
+
// shuffle top-level key order of the body
|
|
25
|
+
const shuffled = Object.fromEntries(Object.entries(body()).reverse());
|
|
26
|
+
const b = await finalizeCertificate(shuffled);
|
|
27
|
+
expect(a.integrity.contentDigest).toBe(b.integrity.contentDigest);
|
|
28
|
+
});
|
|
29
|
+
it("verifies an untampered certificate", async () => {
|
|
30
|
+
const cert = await finalizeCertificate(body());
|
|
31
|
+
const result = await verifyCertificate(cert);
|
|
32
|
+
expect(result.valid).toBe(true);
|
|
33
|
+
expect(result.schemaValid).toBe(true);
|
|
34
|
+
expect(result.contentDigestValid).toBe(true);
|
|
35
|
+
expect(result.signaturePresent).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
it("detects tampering — any field change breaks the digest", async () => {
|
|
38
|
+
const cert = await finalizeCertificate(body());
|
|
39
|
+
const tampered = { ...cert, overallScore: 100 };
|
|
40
|
+
const result = await verifyCertificate(tampered);
|
|
41
|
+
expect(result.contentDigestValid).toBe(false);
|
|
42
|
+
expect(result.valid).toBe(false);
|
|
43
|
+
expect(result.errors.join(" ")).toMatch(/digest mismatch/i);
|
|
44
|
+
});
|
|
45
|
+
it("detects tampering inside a nested dimension", async () => {
|
|
46
|
+
const cert = await finalizeCertificate(body());
|
|
47
|
+
const tampered = JSON.parse(JSON.stringify(cert));
|
|
48
|
+
tampered.dimensions.security.score = 10;
|
|
49
|
+
const result = await verifyCertificate(tampered);
|
|
50
|
+
expect(result.valid).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
it("rejects a structurally invalid certificate", async () => {
|
|
53
|
+
const result = await verifyCertificate({ not: "a certificate" });
|
|
54
|
+
expect(result.valid).toBe(false);
|
|
55
|
+
expect(result.schemaValid).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
it("round-trips through parseCertificate", async () => {
|
|
58
|
+
const cert = await finalizeCertificate(body());
|
|
59
|
+
const json = JSON.parse(JSON.stringify(cert));
|
|
60
|
+
const parsed = parseCertificate(json);
|
|
61
|
+
expect(parsed.certificateId).toBe(cert.certificateId);
|
|
62
|
+
});
|
|
63
|
+
it("throws a typed error for an invalid body", async () => {
|
|
64
|
+
const bad = { ...body(), overallScore: 999 };
|
|
65
|
+
await expect(finalizeCertificate(bad)).rejects.toBeInstanceOf(CertificateError);
|
|
66
|
+
});
|
|
67
|
+
it("the sample body validates against the full schema once finalized", async () => {
|
|
68
|
+
const cert = await finalizeCertificate(body());
|
|
69
|
+
expect(AgentCertificateSchema.safeParse(cert).success).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
it("canonicalize + computeContentDigest agree with finalize", async () => {
|
|
72
|
+
const b = body();
|
|
73
|
+
const cert = await finalizeCertificate(b);
|
|
74
|
+
expect(computeContentDigest(b)).toBe(cert.integrity.contentDigest);
|
|
75
|
+
expect(typeof canonicalize(b)).toBe("string");
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=agent-certificate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-certificate.test.js","sourceRoot":"","sources":["../../../src/__tests__/certification/agent-certificate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-endpoint.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/certification/verify-endpoint.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
2
|
+
import { finalizeCertificate, AGENT_CERTIFICATE_SCHEMA, } from "../../certification/agent-certificate.js";
|
|
3
|
+
import { verifyCertificatePayload } from "../../certification/verify-endpoint.js";
|
|
4
|
+
const NOW = new Date("2026-06-15T00:00:00.000Z");
|
|
5
|
+
function bodyFixture(over = {}) {
|
|
6
|
+
const dim = {
|
|
7
|
+
status: "pass",
|
|
8
|
+
score: 95,
|
|
9
|
+
summary: "ok",
|
|
10
|
+
checks: [],
|
|
11
|
+
};
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: AGENT_CERTIFICATE_SCHEMA,
|
|
14
|
+
certificateId: "vac_test_0001",
|
|
15
|
+
subject: { kind: "mcp-server", name: "test-subject", version: "1.0.0" },
|
|
16
|
+
issuer: { name: "Vaspera", tool: "vaspera-hardening", toolVersion: "2.14.0" },
|
|
17
|
+
issuedAt: "2026-06-10T00:00:00.000Z",
|
|
18
|
+
expiresAt: "2026-09-10T00:00:00.000Z",
|
|
19
|
+
level: "CERTIFIED",
|
|
20
|
+
overallScore: 95,
|
|
21
|
+
dimensions: {
|
|
22
|
+
security: dim,
|
|
23
|
+
scalability: dim,
|
|
24
|
+
quality: dim,
|
|
25
|
+
explainability: dim,
|
|
26
|
+
compliance: { status: "pass", score: 95, summary: "ok", frameworks: [] },
|
|
27
|
+
aiBom: { status: "pass", score: 95, summary: "ok", components: [] },
|
|
28
|
+
},
|
|
29
|
+
provenance: {},
|
|
30
|
+
evidence: [],
|
|
31
|
+
...over,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
describe("verifyCertificatePayload", () => {
|
|
35
|
+
let validCert;
|
|
36
|
+
beforeAll(async () => {
|
|
37
|
+
validCert = await finalizeCertificate(bodyFixture());
|
|
38
|
+
});
|
|
39
|
+
it("verifies a well-formed, untampered certificate", async () => {
|
|
40
|
+
const r = await verifyCertificatePayload(validCert, NOW);
|
|
41
|
+
expect(r.valid).toBe(true);
|
|
42
|
+
expect(r.schemaValid).toBe(true);
|
|
43
|
+
expect(r.contentDigestValid).toBe(true);
|
|
44
|
+
expect(r.summary).toMatch(/^VALID/);
|
|
45
|
+
});
|
|
46
|
+
it("surfaces the certificate's claims when structurally valid", async () => {
|
|
47
|
+
const r = await verifyCertificatePayload(validCert, NOW);
|
|
48
|
+
expect(r.claims).toBeDefined();
|
|
49
|
+
expect(r.claims.subject.name).toBe("test-subject");
|
|
50
|
+
expect(r.claims.level).toBe("CERTIFIED");
|
|
51
|
+
expect(r.claims.overallScore).toBe(95);
|
|
52
|
+
});
|
|
53
|
+
it("rejects a tampered certificate (digest mismatch)", async () => {
|
|
54
|
+
const tampered = JSON.parse(JSON.stringify(validCert));
|
|
55
|
+
tampered.overallScore = 100; // mutate body without recomputing the digest
|
|
56
|
+
const r = await verifyCertificatePayload(tampered, NOW);
|
|
57
|
+
expect(r.valid).toBe(false);
|
|
58
|
+
expect(r.contentDigestValid).toBe(false);
|
|
59
|
+
expect(r.summary).toMatch(/tampered/i);
|
|
60
|
+
});
|
|
61
|
+
it("rejects a non-certificate document", async () => {
|
|
62
|
+
const r = await verifyCertificatePayload({ hello: "world" }, NOW);
|
|
63
|
+
expect(r.valid).toBe(false);
|
|
64
|
+
expect(r.schemaValid).toBe(false);
|
|
65
|
+
expect(r.summary).toMatch(/not a well-formed/i);
|
|
66
|
+
});
|
|
67
|
+
it("flags an expired certificate as VALID but EXPIRED", async () => {
|
|
68
|
+
const expired = await finalizeCertificate(bodyFixture({ expiresAt: "2026-01-01T00:00:00.000Z" }));
|
|
69
|
+
const r = await verifyCertificatePayload(expired, NOW);
|
|
70
|
+
expect(r.valid).toBe(true); // integrity is independent of expiry
|
|
71
|
+
expect(r.expired).toBe(true);
|
|
72
|
+
expect(r.warnings.some((w) => /expired/i.test(w))).toBe(true);
|
|
73
|
+
expect(r.summary).toMatch(/EXPIRED/);
|
|
74
|
+
});
|
|
75
|
+
it("warns that a digest-only certificate is unsigned", async () => {
|
|
76
|
+
const r = await verifyCertificatePayload(validCert, NOW);
|
|
77
|
+
expect(r.signaturePresent).toBe(false);
|
|
78
|
+
expect(r.warnings.some((w) => /unsigned/i.test(w))).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
//# sourceMappingURL=verify-endpoint.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-endpoint.test.js","sourceRoot":"","sources":["../../../src/__tests__/certification/verify-endpoint.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-frameworks.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/compliance/ai-frameworks.test.ts"],"names":[],"mappings":""}
|