vaspera 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +184 -0
- package/LICENSE +21 -0
- package/README.md +809 -0
- package/dist/__tests__/integration/certification-flow.test.d.ts +5 -0
- package/dist/__tests__/integration/certification-flow.test.d.ts.map +1 -0
- package/dist/__tests__/integration/certification-flow.test.js +245 -0
- package/dist/__tests__/integration/certification-flow.test.js.map +1 -0
- package/dist/__tests__/integration/commands.test.d.ts +5 -0
- package/dist/__tests__/integration/commands.test.d.ts.map +1 -0
- package/dist/__tests__/integration/commands.test.js +93 -0
- package/dist/__tests__/integration/commands.test.js.map +1 -0
- package/dist/action/diff-mode.d.ts +34 -0
- package/dist/action/diff-mode.d.ts.map +1 -0
- package/dist/action/diff-mode.js +201 -0
- package/dist/action/diff-mode.js.map +1 -0
- package/dist/action/diff-mode.test.d.ts +5 -0
- package/dist/action/diff-mode.test.d.ts.map +1 -0
- package/dist/action/diff-mode.test.js +162 -0
- package/dist/action/diff-mode.test.js.map +1 -0
- package/dist/action/index.d.ts +10 -0
- package/dist/action/index.d.ts.map +1 -0
- package/dist/action/index.js +231 -0
- package/dist/action/index.js.map +1 -0
- package/dist/action/pr-comment.d.ts +30 -0
- package/dist/action/pr-comment.d.ts.map +1 -0
- package/dist/action/pr-comment.js +301 -0
- package/dist/action/pr-comment.js.map +1 -0
- package/dist/action/pr-comment.test.d.ts +5 -0
- package/dist/action/pr-comment.test.d.ts.map +1 -0
- package/dist/action/pr-comment.test.js +189 -0
- package/dist/action/pr-comment.test.js.map +1 -0
- package/dist/action/sarif-upload.d.ts +104 -0
- package/dist/action/sarif-upload.d.ts.map +1 -0
- package/dist/action/sarif-upload.js +188 -0
- package/dist/action/sarif-upload.js.map +1 -0
- package/dist/action/sarif-upload.test.d.ts +5 -0
- package/dist/action/sarif-upload.test.d.ts.map +1 -0
- package/dist/action/sarif-upload.test.js +206 -0
- package/dist/action/sarif-upload.test.js.map +1 -0
- package/dist/action/types.d.ts +104 -0
- package/dist/action/types.d.ts.map +1 -0
- package/dist/action/types.js +33 -0
- package/dist/action/types.js.map +1 -0
- package/dist/action/types.test.d.ts +5 -0
- package/dist/action/types.test.d.ts.map +1 -0
- package/dist/action/types.test.js +79 -0
- package/dist/action/types.test.js.map +1 -0
- package/dist/agents/agent-integrity.d.ts +111 -0
- package/dist/agents/agent-integrity.d.ts.map +1 -0
- package/dist/agents/agent-integrity.js +308 -0
- package/dist/agents/agent-integrity.js.map +1 -0
- package/dist/agents/agent-privacy.d.ts +68 -0
- package/dist/agents/agent-privacy.d.ts.map +1 -0
- package/dist/agents/agent-privacy.js +345 -0
- package/dist/agents/agent-privacy.js.map +1 -0
- package/dist/agents/exploit-chain.d.ts +64 -0
- package/dist/agents/exploit-chain.d.ts.map +1 -0
- package/dist/agents/exploit-chain.js +477 -0
- package/dist/agents/exploit-chain.js.map +1 -0
- package/dist/agents/exploit-chain.test.d.ts +5 -0
- package/dist/agents/exploit-chain.test.d.ts.map +1 -0
- package/dist/agents/exploit-chain.test.js +455 -0
- package/dist/agents/exploit-chain.test.js.map +1 -0
- package/dist/agents/index.d.ts +14 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +19 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/logic-flaw-detector.d.ts +55 -0
- package/dist/agents/logic-flaw-detector.d.ts.map +1 -0
- package/dist/agents/logic-flaw-detector.js +454 -0
- package/dist/agents/logic-flaw-detector.js.map +1 -0
- package/dist/agents/zero-day-hunter.d.ts +69 -0
- package/dist/agents/zero-day-hunter.d.ts.map +1 -0
- package/dist/agents/zero-day-hunter.js +591 -0
- package/dist/agents/zero-day-hunter.js.map +1 -0
- package/dist/certification/artifacts.d.ts +21 -0
- package/dist/certification/artifacts.d.ts.map +1 -0
- package/dist/certification/artifacts.js +275 -0
- package/dist/certification/artifacts.js.map +1 -0
- package/dist/certification/autofix.d.ts +122 -0
- package/dist/certification/autofix.d.ts.map +1 -0
- package/dist/certification/autofix.js +476 -0
- package/dist/certification/autofix.js.map +1 -0
- package/dist/certification/badge.d.ts +56 -0
- package/dist/certification/badge.d.ts.map +1 -0
- package/dist/certification/badge.js +155 -0
- package/dist/certification/badge.js.map +1 -0
- package/dist/certification/cache.d.ts +121 -0
- package/dist/certification/cache.d.ts.map +1 -0
- package/dist/certification/cache.js +275 -0
- package/dist/certification/cache.js.map +1 -0
- package/dist/certification/cache.test.d.ts +5 -0
- package/dist/certification/cache.test.d.ts.map +1 -0
- package/dist/certification/cache.test.js +270 -0
- package/dist/certification/cache.test.js.map +1 -0
- package/dist/certification/consensus.d.ts +105 -0
- package/dist/certification/consensus.d.ts.map +1 -0
- package/dist/certification/consensus.js +353 -0
- package/dist/certification/consensus.js.map +1 -0
- package/dist/certification/consensus.test.d.ts +5 -0
- package/dist/certification/consensus.test.d.ts.map +1 -0
- package/dist/certification/consensus.test.js +342 -0
- package/dist/certification/consensus.test.js.map +1 -0
- package/dist/certification/index.d.ts +14 -0
- package/dist/certification/index.d.ts.map +1 -0
- package/dist/certification/index.js +14 -0
- package/dist/certification/index.js.map +1 -0
- package/dist/certification/rules.d.ts +89 -0
- package/dist/certification/rules.d.ts.map +1 -0
- package/dist/certification/rules.js +317 -0
- package/dist/certification/rules.js.map +1 -0
- package/dist/certification/sarif.d.ts +107 -0
- package/dist/certification/sarif.d.ts.map +1 -0
- package/dist/certification/sarif.js +191 -0
- package/dist/certification/sarif.js.map +1 -0
- package/dist/certification/store.d.ts +255 -0
- package/dist/certification/store.d.ts.map +1 -0
- package/dist/certification/store.js +835 -0
- package/dist/certification/store.js.map +1 -0
- package/dist/certification/store.test.d.ts +5 -0
- package/dist/certification/store.test.d.ts.map +1 -0
- package/dist/certification/store.test.js +468 -0
- package/dist/certification/store.test.js.map +1 -0
- package/dist/certification/summary.d.ts +72 -0
- package/dist/certification/summary.d.ts.map +1 -0
- package/dist/certification/summary.js +296 -0
- package/dist/certification/summary.js.map +1 -0
- package/dist/certification/types.d.ts +138 -0
- package/dist/certification/types.d.ts.map +1 -0
- package/dist/certification/types.js +34 -0
- package/dist/certification/types.js.map +1 -0
- package/dist/commands/audits/api-check.d.ts +3 -0
- package/dist/commands/audits/api-check.d.ts.map +1 -0
- package/dist/commands/audits/api-check.js +71 -0
- package/dist/commands/audits/api-check.js.map +1 -0
- package/dist/commands/audits/deadcode.d.ts +3 -0
- package/dist/commands/audits/deadcode.d.ts.map +1 -0
- package/dist/commands/audits/deadcode.js +63 -0
- package/dist/commands/audits/deadcode.js.map +1 -0
- package/dist/commands/audits/deps.d.ts +3 -0
- package/dist/commands/audits/deps.d.ts.map +1 -0
- package/dist/commands/audits/deps.js +56 -0
- package/dist/commands/audits/deps.js.map +1 -0
- package/dist/commands/audits/errors.d.ts +3 -0
- package/dist/commands/audits/errors.d.ts.map +1 -0
- package/dist/commands/audits/errors.js +65 -0
- package/dist/commands/audits/errors.js.map +1 -0
- package/dist/commands/audits/index.d.ts +3 -0
- package/dist/commands/audits/index.d.ts.map +1 -0
- package/dist/commands/audits/index.js +15 -0
- package/dist/commands/audits/index.js.map +1 -0
- package/dist/commands/audits/perf.d.ts +3 -0
- package/dist/commands/audits/perf.d.ts.map +1 -0
- package/dist/commands/audits/perf.js +85 -0
- package/dist/commands/audits/perf.js.map +1 -0
- package/dist/commands/audits/secrets.d.ts +3 -0
- package/dist/commands/audits/secrets.d.ts.map +1 -0
- package/dist/commands/audits/secrets.js +71 -0
- package/dist/commands/audits/secrets.js.map +1 -0
- package/dist/commands/certification/certify.d.ts +3 -0
- package/dist/commands/certification/certify.d.ts.map +1 -0
- package/dist/commands/certification/certify.js +108 -0
- package/dist/commands/certification/certify.js.map +1 -0
- package/dist/commands/certification/index.d.ts +3 -0
- package/dist/commands/certification/index.d.ts.map +1 -0
- package/dist/commands/certification/index.js +17 -0
- package/dist/commands/certification/index.js.map +1 -0
- package/dist/commands/certification/performance.d.ts +3 -0
- package/dist/commands/certification/performance.d.ts.map +1 -0
- package/dist/commands/certification/performance.js +89 -0
- package/dist/commands/certification/performance.js.map +1 -0
- package/dist/commands/certification/quality.d.ts +3 -0
- package/dist/commands/certification/quality.d.ts.map +1 -0
- package/dist/commands/certification/quality.js +92 -0
- package/dist/commands/certification/quality.js.map +1 -0
- package/dist/commands/certification/redteam.d.ts +3 -0
- package/dist/commands/certification/redteam.d.ts.map +1 -0
- package/dist/commands/certification/redteam.js +114 -0
- package/dist/commands/certification/redteam.js.map +1 -0
- package/dist/commands/certification/reliability.d.ts +3 -0
- package/dist/commands/certification/reliability.d.ts.map +1 -0
- package/dist/commands/certification/reliability.js +93 -0
- package/dist/commands/certification/reliability.js.map +1 -0
- package/dist/commands/certification/security.d.ts +3 -0
- package/dist/commands/certification/security.d.ts.map +1 -0
- package/dist/commands/certification/security.js +90 -0
- package/dist/commands/certification/security.js.map +1 -0
- package/dist/commands/certification/typesafety.d.ts +3 -0
- package/dist/commands/certification/typesafety.d.ts.map +1 -0
- package/dist/commands/certification/typesafety.js +87 -0
- package/dist/commands/certification/typesafety.js.map +1 -0
- package/dist/commands/core/add-tests.d.ts +3 -0
- package/dist/commands/core/add-tests.d.ts.map +1 -0
- package/dist/commands/core/add-tests.js +29 -0
- package/dist/commands/core/add-tests.js.map +1 -0
- package/dist/commands/core/audit.d.ts +3 -0
- package/dist/commands/core/audit.d.ts.map +1 -0
- package/dist/commands/core/audit.js +64 -0
- package/dist/commands/core/audit.js.map +1 -0
- package/dist/commands/core/fix-critical.d.ts +3 -0
- package/dist/commands/core/fix-critical.d.ts.map +1 -0
- package/dist/commands/core/fix-critical.js +22 -0
- package/dist/commands/core/fix-critical.js.map +1 -0
- package/dist/commands/core/fix-high.d.ts +3 -0
- package/dist/commands/core/fix-high.d.ts.map +1 -0
- package/dist/commands/core/fix-high.js +32 -0
- package/dist/commands/core/fix-high.js.map +1 -0
- package/dist/commands/core/fix-medium.d.ts +3 -0
- package/dist/commands/core/fix-medium.d.ts.map +1 -0
- package/dist/commands/core/fix-medium.js +29 -0
- package/dist/commands/core/fix-medium.js.map +1 -0
- package/dist/commands/core/fix-rls.d.ts +3 -0
- package/dist/commands/core/fix-rls.d.ts.map +1 -0
- package/dist/commands/core/fix-rls.js +17 -0
- package/dist/commands/core/fix-rls.js.map +1 -0
- package/dist/commands/core/harden.d.ts +3 -0
- package/dist/commands/core/harden.d.ts.map +1 -0
- package/dist/commands/core/harden.js +19 -0
- package/dist/commands/core/harden.js.map +1 -0
- package/dist/commands/core/index.d.ts +3 -0
- package/dist/commands/core/index.d.ts.map +1 -0
- package/dist/commands/core/index.js +21 -0
- package/dist/commands/core/index.js.map +1 -0
- package/dist/commands/core/preflight.d.ts +3 -0
- package/dist/commands/core/preflight.d.ts.map +1 -0
- package/dist/commands/core/preflight.js +50 -0
- package/dist/commands/core/preflight.js.map +1 -0
- package/dist/commands/core/verify.d.ts +3 -0
- package/dist/commands/core/verify.d.ts.map +1 -0
- package/dist/commands/core/verify.js +32 -0
- package/dist/commands/core/verify.js.map +1 -0
- package/dist/commands/index.d.ts +28 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +37 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/types.d.ts +9 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +5 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/compliance/cis.d.ts +29 -0
- package/dist/compliance/cis.d.ts.map +1 -0
- package/dist/compliance/cis.js +316 -0
- package/dist/compliance/cis.js.map +1 -0
- package/dist/compliance/frameworks/eu-ai-act.d.ts +55 -0
- package/dist/compliance/frameworks/eu-ai-act.d.ts.map +1 -0
- package/dist/compliance/frameworks/eu-ai-act.js +621 -0
- package/dist/compliance/frameworks/eu-ai-act.js.map +1 -0
- package/dist/compliance/frameworks/index.d.ts +67 -0
- package/dist/compliance/frameworks/index.d.ts.map +1 -0
- package/dist/compliance/frameworks/index.js +97 -0
- package/dist/compliance/frameworks/index.js.map +1 -0
- package/dist/compliance/frameworks/iso-42001.d.ts +59 -0
- package/dist/compliance/frameworks/iso-42001.d.ts.map +1 -0
- package/dist/compliance/frameworks/iso-42001.js +719 -0
- package/dist/compliance/frameworks/iso-42001.js.map +1 -0
- package/dist/compliance/frameworks/mitre-atlas.d.ts +58 -0
- package/dist/compliance/frameworks/mitre-atlas.d.ts.map +1 -0
- package/dist/compliance/frameworks/mitre-atlas.js +686 -0
- package/dist/compliance/frameworks/mitre-atlas.js.map +1 -0
- package/dist/compliance/frameworks/nist-ai-rmf.d.ts +51 -0
- package/dist/compliance/frameworks/nist-ai-rmf.d.ts.map +1 -0
- package/dist/compliance/frameworks/nist-ai-rmf.js +677 -0
- package/dist/compliance/frameworks/nist-ai-rmf.js.map +1 -0
- package/dist/compliance/frameworks/owasp-llm.d.ts +58 -0
- package/dist/compliance/frameworks/owasp-llm.d.ts.map +1 -0
- package/dist/compliance/frameworks/owasp-llm.js +399 -0
- package/dist/compliance/frameworks/owasp-llm.js.map +1 -0
- package/dist/compliance/gdpr.d.ts +34 -0
- package/dist/compliance/gdpr.d.ts.map +1 -0
- package/dist/compliance/gdpr.js +319 -0
- package/dist/compliance/gdpr.js.map +1 -0
- package/dist/compliance/hipaa.d.ts +29 -0
- package/dist/compliance/hipaa.d.ts.map +1 -0
- package/dist/compliance/hipaa.js +205 -0
- package/dist/compliance/hipaa.js.map +1 -0
- package/dist/compliance/index.d.ts +18 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +26 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/compliance/iso27001.d.ts +30 -0
- package/dist/compliance/iso27001.d.ts.map +1 -0
- package/dist/compliance/iso27001.js +332 -0
- package/dist/compliance/iso27001.js.map +1 -0
- package/dist/compliance/mapper.d.ts +42 -0
- package/dist/compliance/mapper.d.ts.map +1 -0
- package/dist/compliance/mapper.js +269 -0
- package/dist/compliance/mapper.js.map +1 -0
- package/dist/compliance/mapper.test.d.ts +5 -0
- package/dist/compliance/mapper.test.d.ts.map +1 -0
- package/dist/compliance/mapper.test.js +360 -0
- package/dist/compliance/mapper.test.js.map +1 -0
- package/dist/compliance/pci-dss.d.ts +29 -0
- package/dist/compliance/pci-dss.d.ts.map +1 -0
- package/dist/compliance/pci-dss.js +247 -0
- package/dist/compliance/pci-dss.js.map +1 -0
- package/dist/compliance/report.d.ts +25 -0
- package/dist/compliance/report.d.ts.map +1 -0
- package/dist/compliance/report.js +254 -0
- package/dist/compliance/report.js.map +1 -0
- package/dist/compliance/report.test.d.ts +5 -0
- package/dist/compliance/report.test.d.ts.map +1 -0
- package/dist/compliance/report.test.js +128 -0
- package/dist/compliance/report.test.js.map +1 -0
- package/dist/compliance/soc2.d.ts +30 -0
- package/dist/compliance/soc2.d.ts.map +1 -0
- package/dist/compliance/soc2.js +262 -0
- package/dist/compliance/soc2.js.map +1 -0
- package/dist/compliance/soc2.test.d.ts +5 -0
- package/dist/compliance/soc2.test.d.ts.map +1 -0
- package/dist/compliance/soc2.test.js +86 -0
- package/dist/compliance/soc2.test.js.map +1 -0
- package/dist/compliance/types.d.ts +125 -0
- package/dist/compliance/types.d.ts.map +1 -0
- package/dist/compliance/types.js +10 -0
- package/dist/compliance/types.js.map +1 -0
- package/dist/config/flags.d.ts +456 -0
- package/dist/config/flags.d.ts.map +1 -0
- package/dist/config/flags.js +464 -0
- package/dist/config/flags.js.map +1 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +10 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/severity-overrides.d.ts +209 -0
- package/dist/config/severity-overrides.d.ts.map +1 -0
- package/dist/config/severity-overrides.js +380 -0
- package/dist/config/severity-overrides.js.map +1 -0
- package/dist/cost/index.d.ts +11 -0
- package/dist/cost/index.d.ts.map +1 -0
- package/dist/cost/index.js +12 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/cost/pricing.d.ts +57 -0
- package/dist/cost/pricing.d.ts.map +1 -0
- package/dist/cost/pricing.js +196 -0
- package/dist/cost/pricing.js.map +1 -0
- package/dist/cost/pricing.test.d.ts +5 -0
- package/dist/cost/pricing.test.d.ts.map +1 -0
- package/dist/cost/pricing.test.js +195 -0
- package/dist/cost/pricing.test.js.map +1 -0
- package/dist/cost/tracker.d.ts +100 -0
- package/dist/cost/tracker.d.ts.map +1 -0
- package/dist/cost/tracker.js +366 -0
- package/dist/cost/tracker.js.map +1 -0
- package/dist/cost/tracker.test.d.ts +5 -0
- package/dist/cost/tracker.test.d.ts.map +1 -0
- package/dist/cost/tracker.test.js +360 -0
- package/dist/cost/tracker.test.js.map +1 -0
- package/dist/cost/types.d.ts +135 -0
- package/dist/cost/types.d.ts.map +1 -0
- package/dist/cost/types.js +9 -0
- package/dist/cost/types.js.map +1 -0
- package/dist/enterprise/auth/oidc.d.ts +231 -0
- package/dist/enterprise/auth/oidc.d.ts.map +1 -0
- package/dist/enterprise/auth/oidc.js +372 -0
- package/dist/enterprise/auth/oidc.js.map +1 -0
- package/dist/enterprise/auth/oidc.test.d.ts +5 -0
- package/dist/enterprise/auth/oidc.test.d.ts.map +1 -0
- package/dist/enterprise/auth/oidc.test.js +435 -0
- package/dist/enterprise/auth/oidc.test.js.map +1 -0
- package/dist/enterprise/index.d.ts +14 -0
- package/dist/enterprise/index.d.ts.map +1 -0
- package/dist/enterprise/index.js +19 -0
- package/dist/enterprise/index.js.map +1 -0
- package/dist/enterprise/integrations/chat.d.ts +205 -0
- package/dist/enterprise/integrations/chat.d.ts.map +1 -0
- package/dist/enterprise/integrations/chat.js +624 -0
- package/dist/enterprise/integrations/chat.js.map +1 -0
- package/dist/enterprise/integrations/chat.test.d.ts +5 -0
- package/dist/enterprise/integrations/chat.test.d.ts.map +1 -0
- package/dist/enterprise/integrations/chat.test.js +557 -0
- package/dist/enterprise/integrations/chat.test.js.map +1 -0
- package/dist/enterprise/integrations/ticketing.d.ts +257 -0
- package/dist/enterprise/integrations/ticketing.d.ts.map +1 -0
- package/dist/enterprise/integrations/ticketing.js +548 -0
- package/dist/enterprise/integrations/ticketing.js.map +1 -0
- package/dist/enterprise/integrations/ticketing.test.d.ts +5 -0
- package/dist/enterprise/integrations/ticketing.test.d.ts.map +1 -0
- package/dist/enterprise/integrations/ticketing.test.js +693 -0
- package/dist/enterprise/integrations/ticketing.test.js.map +1 -0
- package/dist/enterprise/policy/opa.d.ts +194 -0
- package/dist/enterprise/policy/opa.d.ts.map +1 -0
- package/dist/enterprise/policy/opa.js +385 -0
- package/dist/enterprise/policy/opa.js.map +1 -0
- package/dist/enterprise/policy/opa.test.d.ts +5 -0
- package/dist/enterprise/policy/opa.test.d.ts.map +1 -0
- package/dist/enterprise/policy/opa.test.js +702 -0
- package/dist/enterprise/policy/opa.test.js.map +1 -0
- package/dist/enterprise/signing/kms.d.ts +211 -0
- package/dist/enterprise/signing/kms.d.ts.map +1 -0
- package/dist/enterprise/signing/kms.js +480 -0
- package/dist/enterprise/signing/kms.js.map +1 -0
- package/dist/enterprise/signing/kms.test.d.ts +5 -0
- package/dist/enterprise/signing/kms.test.d.ts.map +1 -0
- package/dist/enterprise/signing/kms.test.js +511 -0
- package/dist/enterprise/signing/kms.test.js.map +1 -0
- package/dist/eval/fixtures.d.ts +58 -0
- package/dist/eval/fixtures.d.ts.map +1 -0
- package/dist/eval/fixtures.js +571 -0
- package/dist/eval/fixtures.js.map +1 -0
- package/dist/eval/fixtures.test.d.ts +5 -0
- package/dist/eval/fixtures.test.d.ts.map +1 -0
- package/dist/eval/fixtures.test.js +193 -0
- package/dist/eval/fixtures.test.js.map +1 -0
- package/dist/eval/harness.d.ts +30 -0
- package/dist/eval/harness.d.ts.map +1 -0
- package/dist/eval/harness.js +221 -0
- package/dist/eval/harness.js.map +1 -0
- package/dist/eval/harness.test.d.ts +5 -0
- package/dist/eval/harness.test.d.ts.map +1 -0
- package/dist/eval/harness.test.js +314 -0
- package/dist/eval/harness.test.js.map +1 -0
- package/dist/eval/index.d.ts +15 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +18 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/metrics.d.ts +56 -0
- package/dist/eval/metrics.d.ts.map +1 -0
- package/dist/eval/metrics.js +298 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/eval/metrics.test.d.ts +5 -0
- package/dist/eval/metrics.test.d.ts.map +1 -0
- package/dist/eval/metrics.test.js +426 -0
- package/dist/eval/metrics.test.js.map +1 -0
- package/dist/eval/report.d.ts +30 -0
- package/dist/eval/report.d.ts.map +1 -0
- package/dist/eval/report.js +333 -0
- package/dist/eval/report.js.map +1 -0
- package/dist/eval/report.test.d.ts +5 -0
- package/dist/eval/report.test.d.ts.map +1 -0
- package/dist/eval/report.test.js +275 -0
- package/dist/eval/report.test.js.map +1 -0
- package/dist/eval/types.d.ts +234 -0
- package/dist/eval/types.d.ts.map +1 -0
- package/dist/eval/types.js +27 -0
- package/dist/eval/types.js.map +1 -0
- package/dist/http-server.d.ts +3 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +127 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4120 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +46 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +131 -0
- package/dist/logger.js.map +1 -0
- package/dist/multimodel/consensus.d.ts +49 -0
- package/dist/multimodel/consensus.d.ts.map +1 -0
- package/dist/multimodel/consensus.js +454 -0
- package/dist/multimodel/consensus.js.map +1 -0
- package/dist/multimodel/consensus.test.d.ts +5 -0
- package/dist/multimodel/consensus.test.d.ts.map +1 -0
- package/dist/multimodel/consensus.test.js +415 -0
- package/dist/multimodel/consensus.test.js.map +1 -0
- package/dist/multimodel/index.d.ts +13 -0
- package/dist/multimodel/index.d.ts.map +1 -0
- package/dist/multimodel/index.js +14 -0
- package/dist/multimodel/index.js.map +1 -0
- package/dist/multimodel/runner.d.ts +95 -0
- package/dist/multimodel/runner.d.ts.map +1 -0
- package/dist/multimodel/runner.js +312 -0
- package/dist/multimodel/runner.js.map +1 -0
- package/dist/multimodel/runner.test.d.ts +5 -0
- package/dist/multimodel/runner.test.d.ts.map +1 -0
- package/dist/multimodel/runner.test.js +224 -0
- package/dist/multimodel/runner.test.js.map +1 -0
- package/dist/multimodel/types.d.ts +202 -0
- package/dist/multimodel/types.d.ts.map +1 -0
- package/dist/multimodel/types.js +10 -0
- package/dist/multimodel/types.js.map +1 -0
- package/dist/observability/index.d.ts +9 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +9 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/otel.d.ts +102 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +284 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +10 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +78 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +470 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/types.d.ts +304 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +100 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/sbom/cyclonedx.d.ts +30 -0
- package/dist/sbom/cyclonedx.d.ts.map +1 -0
- package/dist/sbom/cyclonedx.js +392 -0
- package/dist/sbom/cyclonedx.js.map +1 -0
- package/dist/sbom/cyclonedx.test.d.ts +5 -0
- package/dist/sbom/cyclonedx.test.d.ts.map +1 -0
- package/dist/sbom/cyclonedx.test.js +244 -0
- package/dist/sbom/cyclonedx.test.js.map +1 -0
- package/dist/sbom/index.d.ts +13 -0
- package/dist/sbom/index.d.ts.map +1 -0
- package/dist/sbom/index.js +15 -0
- package/dist/sbom/index.js.map +1 -0
- package/dist/sbom/provenance.d.ts +37 -0
- package/dist/sbom/provenance.d.ts.map +1 -0
- package/dist/sbom/provenance.js +268 -0
- package/dist/sbom/provenance.js.map +1 -0
- package/dist/sbom/provenance.test.d.ts +5 -0
- package/dist/sbom/provenance.test.d.ts.map +1 -0
- package/dist/sbom/provenance.test.js +189 -0
- package/dist/sbom/provenance.test.js.map +1 -0
- package/dist/sbom/signing.d.ts +87 -0
- package/dist/sbom/signing.d.ts.map +1 -0
- package/dist/sbom/signing.js +354 -0
- package/dist/sbom/signing.js.map +1 -0
- package/dist/sbom/signing.test.d.ts +5 -0
- package/dist/sbom/signing.test.d.ts.map +1 -0
- package/dist/sbom/signing.test.js +170 -0
- package/dist/sbom/signing.test.js.map +1 -0
- package/dist/sbom/types.d.ts +384 -0
- package/dist/sbom/types.d.ts.map +1 -0
- package/dist/sbom/types.js +17 -0
- package/dist/sbom/types.js.map +1 -0
- package/dist/scanners/agent/credential-scope-audit.d.ts +40 -0
- package/dist/scanners/agent/credential-scope-audit.d.ts.map +1 -0
- package/dist/scanners/agent/credential-scope-audit.js +404 -0
- package/dist/scanners/agent/credential-scope-audit.js.map +1 -0
- package/dist/scanners/agent/exfil-path-graph.d.ts +50 -0
- package/dist/scanners/agent/exfil-path-graph.d.ts.map +1 -0
- package/dist/scanners/agent/exfil-path-graph.js +764 -0
- package/dist/scanners/agent/exfil-path-graph.js.map +1 -0
- package/dist/scanners/agent/index.d.ts +43 -0
- package/dist/scanners/agent/index.d.ts.map +1 -0
- package/dist/scanners/agent/index.js +616 -0
- package/dist/scanners/agent/index.js.map +1 -0
- package/dist/scanners/agent/manifest-audit.d.ts +43 -0
- package/dist/scanners/agent/manifest-audit.d.ts.map +1 -0
- package/dist/scanners/agent/manifest-audit.js +403 -0
- package/dist/scanners/agent/manifest-audit.js.map +1 -0
- package/dist/scanners/agent/payloads/index.d.ts +44 -0
- package/dist/scanners/agent/payloads/index.d.ts.map +1 -0
- package/dist/scanners/agent/payloads/index.js +184 -0
- package/dist/scanners/agent/payloads/index.js.map +1 -0
- package/dist/scanners/agent/permission-minimiser.d.ts +48 -0
- package/dist/scanners/agent/permission-minimiser.d.ts.map +1 -0
- package/dist/scanners/agent/permission-minimiser.js +551 -0
- package/dist/scanners/agent/permission-minimiser.js.map +1 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.d.ts +39 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.d.ts.map +1 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.js +720 -0
- package/dist/scanners/agent/prompt-injection-fuzzer.js.map +1 -0
- package/dist/scanners/agent/sandbox-audit.d.ts +44 -0
- package/dist/scanners/agent/sandbox-audit.d.ts.map +1 -0
- package/dist/scanners/agent/sandbox-audit.js +425 -0
- package/dist/scanners/agent/sandbox-audit.js.map +1 -0
- package/dist/scanners/agent/supply-chain-mcp.d.ts +53 -0
- package/dist/scanners/agent/supply-chain-mcp.d.ts.map +1 -0
- package/dist/scanners/agent/supply-chain-mcp.js +479 -0
- package/dist/scanners/agent/supply-chain-mcp.js.map +1 -0
- package/dist/scanners/agent/tool-description-drift.d.ts +62 -0
- package/dist/scanners/agent/tool-description-drift.d.ts.map +1 -0
- package/dist/scanners/agent/tool-description-drift.js +365 -0
- package/dist/scanners/agent/tool-description-drift.js.map +1 -0
- package/dist/scanners/agent/types.d.ts +840 -0
- package/dist/scanners/agent/types.d.ts.map +1 -0
- package/dist/scanners/agent/types.js +149 -0
- package/dist/scanners/agent/types.js.map +1 -0
- package/dist/scanners/bandit.d.ts +25 -0
- package/dist/scanners/bandit.d.ts.map +1 -0
- package/dist/scanners/bandit.js +129 -0
- package/dist/scanners/bandit.js.map +1 -0
- package/dist/scanners/binary-analysis.d.ts +41 -0
- package/dist/scanners/binary-analysis.d.ts.map +1 -0
- package/dist/scanners/binary-analysis.js +587 -0
- package/dist/scanners/binary-analysis.js.map +1 -0
- package/dist/scanners/binary-analysis.test.d.ts +5 -0
- package/dist/scanners/binary-analysis.test.d.ts.map +1 -0
- package/dist/scanners/binary-analysis.test.js +291 -0
- package/dist/scanners/binary-analysis.test.js.map +1 -0
- package/dist/scanners/brakeman.d.ts +30 -0
- package/dist/scanners/brakeman.d.ts.map +1 -0
- package/dist/scanners/brakeman.js +271 -0
- package/dist/scanners/brakeman.js.map +1 -0
- package/dist/scanners/dependencies.d.ts +22 -0
- package/dist/scanners/dependencies.d.ts.map +1 -0
- package/dist/scanners/dependencies.js +202 -0
- package/dist/scanners/dependencies.js.map +1 -0
- package/dist/scanners/dependencies.test.d.ts +5 -0
- package/dist/scanners/dependencies.test.d.ts.map +1 -0
- package/dist/scanners/dependencies.test.js +185 -0
- package/dist/scanners/dependencies.test.js.map +1 -0
- package/dist/scanners/eslint.d.ts +25 -0
- package/dist/scanners/eslint.d.ts.map +1 -0
- package/dist/scanners/eslint.js +220 -0
- package/dist/scanners/eslint.js.map +1 -0
- package/dist/scanners/gosec.d.ts +25 -0
- package/dist/scanners/gosec.d.ts.map +1 -0
- package/dist/scanners/gosec.js +128 -0
- package/dist/scanners/gosec.js.map +1 -0
- package/dist/scanners/index.d.ts +128 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +811 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/index.test.d.ts +5 -0
- package/dist/scanners/index.test.d.ts.map +1 -0
- package/dist/scanners/index.test.js +424 -0
- package/dist/scanners/index.test.js.map +1 -0
- package/dist/scanners/memory-safety.d.ts +44 -0
- package/dist/scanners/memory-safety.d.ts.map +1 -0
- package/dist/scanners/memory-safety.js +571 -0
- package/dist/scanners/memory-safety.js.map +1 -0
- package/dist/scanners/memory-safety.test.d.ts +5 -0
- package/dist/scanners/memory-safety.test.d.ts.map +1 -0
- package/dist/scanners/memory-safety.test.js +321 -0
- package/dist/scanners/memory-safety.test.js.map +1 -0
- package/dist/scanners/race-condition.d.ts +25 -0
- package/dist/scanners/race-condition.d.ts.map +1 -0
- package/dist/scanners/race-condition.js +443 -0
- package/dist/scanners/race-condition.js.map +1 -0
- package/dist/scanners/race-condition.test.d.ts +5 -0
- package/dist/scanners/race-condition.test.d.ts.map +1 -0
- package/dist/scanners/race-condition.test.js +428 -0
- package/dist/scanners/race-condition.test.js.map +1 -0
- package/dist/scanners/secrets.d.ts +25 -0
- package/dist/scanners/secrets.d.ts.map +1 -0
- package/dist/scanners/secrets.js +367 -0
- package/dist/scanners/secrets.js.map +1 -0
- package/dist/scanners/secrets.test.d.ts +5 -0
- package/dist/scanners/secrets.test.d.ts.map +1 -0
- package/dist/scanners/secrets.test.js +160 -0
- package/dist/scanners/secrets.test.js.map +1 -0
- package/dist/scanners/semgrep.d.ts +33 -0
- package/dist/scanners/semgrep.d.ts.map +1 -0
- package/dist/scanners/semgrep.js +350 -0
- package/dist/scanners/semgrep.js.map +1 -0
- package/dist/scanners/semgrep.test.d.ts +8 -0
- package/dist/scanners/semgrep.test.d.ts.map +1 -0
- package/dist/scanners/semgrep.test.js +254 -0
- package/dist/scanners/semgrep.test.js.map +1 -0
- package/dist/scanners/trivy.d.ts +26 -0
- package/dist/scanners/trivy.d.ts.map +1 -0
- package/dist/scanners/trivy.js +187 -0
- package/dist/scanners/trivy.js.map +1 -0
- package/dist/scanners/types.d.ts +210 -0
- package/dist/scanners/types.d.ts.map +1 -0
- package/dist/scanners/types.js +106 -0
- package/dist/scanners/types.js.map +1 -0
- package/dist/scanners/types.test.d.ts +5 -0
- package/dist/scanners/types.test.d.ts.map +1 -0
- package/dist/scanners/types.test.js +103 -0
- package/dist/scanners/types.test.js.map +1 -0
- package/dist/scanners/typescript.d.ts +32 -0
- package/dist/scanners/typescript.d.ts.map +1 -0
- package/dist/scanners/typescript.js +300 -0
- package/dist/scanners/typescript.js.map +1 -0
- package/dist/scanners/typescript.test.d.ts +5 -0
- package/dist/scanners/typescript.test.d.ts.map +1 -0
- package/dist/scanners/typescript.test.js +296 -0
- package/dist/scanners/typescript.test.js.map +1 -0
- package/dist/transcripts/index.d.ts +13 -0
- package/dist/transcripts/index.d.ts.map +1 -0
- package/dist/transcripts/index.js +17 -0
- package/dist/transcripts/index.js.map +1 -0
- package/dist/transcripts/logger.d.ts +190 -0
- package/dist/transcripts/logger.d.ts.map +1 -0
- package/dist/transcripts/logger.js +385 -0
- package/dist/transcripts/logger.js.map +1 -0
- package/dist/transcripts/logger.test.d.ts +5 -0
- package/dist/transcripts/logger.test.d.ts.map +1 -0
- package/dist/transcripts/logger.test.js +227 -0
- package/dist/transcripts/logger.test.js.map +1 -0
- package/dist/transcripts/redaction.d.ts +125 -0
- package/dist/transcripts/redaction.d.ts.map +1 -0
- package/dist/transcripts/redaction.js +416 -0
- package/dist/transcripts/redaction.js.map +1 -0
- package/dist/transcripts/redaction.test.d.ts +5 -0
- package/dist/transcripts/redaction.test.d.ts.map +1 -0
- package/dist/transcripts/redaction.test.js +267 -0
- package/dist/transcripts/redaction.test.js.map +1 -0
- package/dist/transcripts/signing.d.ts +108 -0
- package/dist/transcripts/signing.d.ts.map +1 -0
- package/dist/transcripts/signing.js +173 -0
- package/dist/transcripts/signing.js.map +1 -0
- package/dist/transcripts/verifier.d.ts +133 -0
- package/dist/transcripts/verifier.d.ts.map +1 -0
- package/dist/transcripts/verifier.js +489 -0
- package/dist/transcripts/verifier.js.map +1 -0
- package/dist/transcripts/verifier.test.d.ts +5 -0
- package/dist/transcripts/verifier.test.d.ts.map +1 -0
- package/dist/transcripts/verifier.test.js +330 -0
- package/dist/transcripts/verifier.test.js.map +1 -0
- package/dist/util/concurrency.d.ts +221 -0
- package/dist/util/concurrency.d.ts.map +1 -0
- package/dist/util/concurrency.js +339 -0
- package/dist/util/concurrency.js.map +1 -0
- package/dist/util/index.d.ts +12 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +12 -0
- package/dist/util/index.js.map +1 -0
- package/dist/util/json.d.ts +63 -0
- package/dist/util/json.d.ts.map +1 -0
- package/dist/util/json.js +134 -0
- package/dist/util/json.js.map +1 -0
- package/dist/util/paths.d.ts +56 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +128 -0
- package/dist/util/paths.js.map +1 -0
- package/dist/util/retry.d.ts +185 -0
- package/dist/util/retry.d.ts.map +1 -0
- package/dist/util/retry.js +338 -0
- package/dist/util/retry.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,835 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Certification System - File-based Storage
|
|
3
|
+
*
|
|
4
|
+
* This module handles persistent storage of certification data using the filesystem.
|
|
5
|
+
* All certification data is stored in `.vaspera/certifications/{cert-id}/` within
|
|
6
|
+
* the project directory.
|
|
7
|
+
*
|
|
8
|
+
* Security features:
|
|
9
|
+
* - Path traversal prevention via validateCertId() and validateProjectPath()
|
|
10
|
+
* - Cryptographically secure IDs using crypto.randomUUID()
|
|
11
|
+
* - Input length constraints to prevent DoS
|
|
12
|
+
*
|
|
13
|
+
* Storage structure:
|
|
14
|
+
* ```
|
|
15
|
+
* .vaspera/certifications/{cert-id}/
|
|
16
|
+
* ├── metadata.json # Certification metadata
|
|
17
|
+
* ├── agents/ # Per-agent findings
|
|
18
|
+
* │ ├── security.json
|
|
19
|
+
* │ ├── reliability.json
|
|
20
|
+
* │ └── ...
|
|
21
|
+
* ├── cross-verifications.json
|
|
22
|
+
* ├── red-team-challenges.json
|
|
23
|
+
* ├── consensus.json # Final scoring results
|
|
24
|
+
* └── evidence/ # Additional evidence files
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @module certification/store
|
|
28
|
+
*/
|
|
29
|
+
import { readFile, writeFile, mkdir, readdir } from "fs/promises";
|
|
30
|
+
import { join, basename, normalize, isAbsolute } from "path";
|
|
31
|
+
import { randomUUID } from "crypto";
|
|
32
|
+
import lockfile from "proper-lockfile";
|
|
33
|
+
import { CERTIFICATION_VALIDITY_DAYS, } from "./types.js";
|
|
34
|
+
import { logger } from "../logger.js";
|
|
35
|
+
import { createCache, saveCache, generateFileHashes, computeProjectHash } from "./cache.js";
|
|
36
|
+
const CERTIFICATION_DIR = ".vaspera/certifications";
|
|
37
|
+
/** Valid certification ID pattern */
|
|
38
|
+
const CERT_ID_PATTERN = /^cert-[a-z0-9-]+-\d+$/;
|
|
39
|
+
/** Lock options for file operations */
|
|
40
|
+
const LOCK_OPTIONS = {
|
|
41
|
+
retries: {
|
|
42
|
+
retries: 5,
|
|
43
|
+
factor: 2,
|
|
44
|
+
minTimeout: 100,
|
|
45
|
+
maxTimeout: 1000,
|
|
46
|
+
},
|
|
47
|
+
stale: 10000, // Consider lock stale after 10 seconds
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Execute a function with a file lock to prevent concurrent modifications.
|
|
51
|
+
*
|
|
52
|
+
* @param path - Path to the file to lock
|
|
53
|
+
* @param fn - Function to execute while holding the lock
|
|
54
|
+
* @returns Result of the function
|
|
55
|
+
*/
|
|
56
|
+
async function withLock(path, fn) {
|
|
57
|
+
let release;
|
|
58
|
+
try {
|
|
59
|
+
release = await lockfile.lock(path, LOCK_OPTIONS);
|
|
60
|
+
logger.debug("store.lock_acquired", { path });
|
|
61
|
+
return await fn();
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
// If locking fails, log and proceed without lock (fallback for environments without lock support)
|
|
65
|
+
if (error.code === "ENOENT") {
|
|
66
|
+
// File doesn't exist yet, no need to lock
|
|
67
|
+
return await fn();
|
|
68
|
+
}
|
|
69
|
+
logger.warn("store.lock_failed", { path, error: String(error) });
|
|
70
|
+
return await fn();
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (release) {
|
|
74
|
+
try {
|
|
75
|
+
await release();
|
|
76
|
+
logger.debug("store.lock_released", { path });
|
|
77
|
+
}
|
|
78
|
+
catch (releaseError) {
|
|
79
|
+
logger.warn("store.lock_release_failed", { path, error: String(releaseError) });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Maximum string length for evidence/description fields */
|
|
85
|
+
const MAX_STRING_LENGTH = 50000;
|
|
86
|
+
/**
|
|
87
|
+
* Validate a certification ID to prevent path traversal
|
|
88
|
+
*/
|
|
89
|
+
function validateCertId(certId) {
|
|
90
|
+
if (!certId || typeof certId !== "string") {
|
|
91
|
+
throw new Error("Certification ID is required");
|
|
92
|
+
}
|
|
93
|
+
if (certId.length > 100) {
|
|
94
|
+
throw new Error("Certification ID too long");
|
|
95
|
+
}
|
|
96
|
+
if (!CERT_ID_PATTERN.test(certId)) {
|
|
97
|
+
throw new Error(`Invalid certification ID format: ${certId}`);
|
|
98
|
+
}
|
|
99
|
+
if (certId.includes("..") || certId.includes("/") || certId.includes("\\")) {
|
|
100
|
+
throw new Error("Invalid characters in certification ID");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Validate a project path
|
|
105
|
+
*/
|
|
106
|
+
function validateProjectPath(projectPath) {
|
|
107
|
+
if (!projectPath || typeof projectPath !== "string") {
|
|
108
|
+
throw new Error("Project path is required");
|
|
109
|
+
}
|
|
110
|
+
if (!isAbsolute(projectPath)) {
|
|
111
|
+
throw new Error("Project path must be absolute");
|
|
112
|
+
}
|
|
113
|
+
if (projectPath.length > 500) {
|
|
114
|
+
throw new Error("Project path too long");
|
|
115
|
+
}
|
|
116
|
+
// Normalize and check for traversal attempts
|
|
117
|
+
const normalized = normalize(projectPath);
|
|
118
|
+
if (normalized !== projectPath && normalized + "/" !== projectPath) {
|
|
119
|
+
throw new Error("Invalid project path");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate a unique certification ID from a project path.
|
|
124
|
+
*
|
|
125
|
+
* The ID format is: `cert-{sanitized-project-name}-{timestamp}`
|
|
126
|
+
* - Project name is lowercased and non-alphanumeric chars replaced with hyphens
|
|
127
|
+
* - Timestamp is milliseconds since epoch for uniqueness
|
|
128
|
+
*
|
|
129
|
+
* @param projectPath - Absolute path to the project directory
|
|
130
|
+
* @returns Certification ID in format `cert-{name}-{timestamp}`
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```typescript
|
|
134
|
+
* const certId = generateCertificationId("/path/to/MyProject");
|
|
135
|
+
* // Returns: "cert-myproject-1712345678901"
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
export function generateCertificationId(projectPath) {
|
|
139
|
+
const projectName = basename(projectPath).toLowerCase().replace(/[^a-z0-9]/g, "-");
|
|
140
|
+
const timestamp = Date.now();
|
|
141
|
+
return `cert-${projectName}-${timestamp}`;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get the certification directory path for a project
|
|
145
|
+
* Validates inputs to prevent path traversal attacks
|
|
146
|
+
*/
|
|
147
|
+
function getCertDir(projectPath, certId) {
|
|
148
|
+
validateProjectPath(projectPath);
|
|
149
|
+
validateCertId(certId);
|
|
150
|
+
return join(projectPath, CERTIFICATION_DIR, certId);
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Ensure certification directory exists
|
|
154
|
+
*/
|
|
155
|
+
async function ensureCertDir(projectPath, certId) {
|
|
156
|
+
const certDir = getCertDir(projectPath, certId);
|
|
157
|
+
await mkdir(certDir, { recursive: true });
|
|
158
|
+
await mkdir(join(certDir, "agents"), { recursive: true });
|
|
159
|
+
await mkdir(join(certDir, "evidence"), { recursive: true });
|
|
160
|
+
return certDir;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Safe JSON file read
|
|
164
|
+
*/
|
|
165
|
+
async function safeReadJson(path) {
|
|
166
|
+
try {
|
|
167
|
+
const content = await readFile(path, "utf-8");
|
|
168
|
+
return JSON.parse(content);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
logger.debug("store.read_json_failed", { path, error: String(error) });
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Safe JSON file write
|
|
177
|
+
*/
|
|
178
|
+
async function safeWriteJson(path, data) {
|
|
179
|
+
await writeFile(path, JSON.stringify(data, null, 2), "utf-8");
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Initialize a new certification for a project.
|
|
183
|
+
*
|
|
184
|
+
* Creates the certification directory structure and initial metadata.
|
|
185
|
+
* The certification starts in "in_progress" status with no agents completed.
|
|
186
|
+
*
|
|
187
|
+
* @param projectPath - Absolute path to the project directory
|
|
188
|
+
* @param certId - Unique certification ID (must match pattern `cert-{name}-{timestamp}`)
|
|
189
|
+
* @param agents - Array of agent types to run for this certification
|
|
190
|
+
* @returns The initialized certification metadata
|
|
191
|
+
* @throws Error if projectPath is not absolute or certId is invalid
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```typescript
|
|
195
|
+
* const certId = generateCertificationId(projectPath);
|
|
196
|
+
* const metadata = await initializeCertification(
|
|
197
|
+
* projectPath,
|
|
198
|
+
* certId,
|
|
199
|
+
* ["security", "reliability", "typesafety"]
|
|
200
|
+
* );
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
export async function initializeCertification(projectPath, certId, agents) {
|
|
204
|
+
const certDir = await ensureCertDir(projectPath, certId);
|
|
205
|
+
const metadata = {
|
|
206
|
+
id: certId,
|
|
207
|
+
project_name: basename(projectPath),
|
|
208
|
+
project_path: projectPath,
|
|
209
|
+
started_at: new Date().toISOString(),
|
|
210
|
+
status: "in_progress",
|
|
211
|
+
agents_requested: agents,
|
|
212
|
+
agents_completed: [],
|
|
213
|
+
};
|
|
214
|
+
await safeWriteJson(join(certDir, "metadata.json"), metadata);
|
|
215
|
+
// Initialize empty arrays for cross-verifications and challenges
|
|
216
|
+
await safeWriteJson(join(certDir, "cross-verifications.json"), []);
|
|
217
|
+
await safeWriteJson(join(certDir, "red-team-challenges.json"), []);
|
|
218
|
+
logger.debug("store.certification_initialized", {
|
|
219
|
+
certId,
|
|
220
|
+
project: basename(projectPath),
|
|
221
|
+
agents,
|
|
222
|
+
certDir,
|
|
223
|
+
});
|
|
224
|
+
return metadata;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Get certification metadata
|
|
228
|
+
*/
|
|
229
|
+
export async function getCertificationMetadata(projectPath, certId) {
|
|
230
|
+
const certDir = getCertDir(projectPath, certId);
|
|
231
|
+
return safeReadJson(join(certDir, "metadata.json"));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Update certification metadata
|
|
235
|
+
*/
|
|
236
|
+
export async function updateCertificationMetadata(projectPath, certId, updates) {
|
|
237
|
+
const certDir = getCertDir(projectPath, certId);
|
|
238
|
+
const existing = await getCertificationMetadata(projectPath, certId);
|
|
239
|
+
if (!existing)
|
|
240
|
+
return null;
|
|
241
|
+
const updated = { ...existing, ...updates };
|
|
242
|
+
await safeWriteJson(join(certDir, "metadata.json"), updated);
|
|
243
|
+
return updated;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Start an agent run
|
|
247
|
+
*/
|
|
248
|
+
export async function startAgent(projectPath, certId, agent) {
|
|
249
|
+
const certDir = getCertDir(projectPath, certId);
|
|
250
|
+
const agentPath = join(certDir, "agents", `${agent}.json`);
|
|
251
|
+
const agentFindings = {
|
|
252
|
+
agent,
|
|
253
|
+
started_at: new Date().toISOString(),
|
|
254
|
+
status: "running",
|
|
255
|
+
findings: [],
|
|
256
|
+
};
|
|
257
|
+
await safeWriteJson(agentPath, agentFindings);
|
|
258
|
+
return agentFindings;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get agent findings
|
|
262
|
+
*/
|
|
263
|
+
export async function getAgentFindings(projectPath, certId, agent) {
|
|
264
|
+
const certDir = getCertDir(projectPath, certId);
|
|
265
|
+
return safeReadJson(join(certDir, "agents", `${agent}.json`));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Validate evidence for a finding to prevent hallucinations.
|
|
269
|
+
*
|
|
270
|
+
* Rules:
|
|
271
|
+
* 1. Deterministic scanner findings (confidence: 100) skip validation
|
|
272
|
+
* 2. Non-deterministic findings must have evidence
|
|
273
|
+
* 3. If file is specified, evidence should contain code from that file
|
|
274
|
+
*
|
|
275
|
+
* @returns null if valid, error message if invalid
|
|
276
|
+
*/
|
|
277
|
+
async function validateEvidence(projectPath, finding) {
|
|
278
|
+
// Deterministic scanner findings (confidence 100) are always trusted
|
|
279
|
+
if (finding.confidence === 100) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
// Non-deterministic findings must have evidence
|
|
283
|
+
if (!finding.evidence || finding.evidence.trim().length === 0) {
|
|
284
|
+
return "Finding requires evidence (code snippet demonstrating the issue)";
|
|
285
|
+
}
|
|
286
|
+
// Evidence should have reasonable length
|
|
287
|
+
if (finding.evidence.length < 10) {
|
|
288
|
+
return "Evidence too short - provide the actual code snippet";
|
|
289
|
+
}
|
|
290
|
+
// If file is specified, validate evidence matches file content
|
|
291
|
+
if (finding.file) {
|
|
292
|
+
try {
|
|
293
|
+
const filePath = join(projectPath, finding.file);
|
|
294
|
+
const fileContent = await readFile(filePath, "utf-8");
|
|
295
|
+
// Extract the core code from evidence (remove markdown, line numbers, etc.)
|
|
296
|
+
const evidenceCode = finding.evidence
|
|
297
|
+
.replace(/```[\w]*\n?/g, "") // Remove markdown code blocks
|
|
298
|
+
.replace(/^\s*\d+\s*[|│:]/gm, "") // Remove line numbers
|
|
299
|
+
.replace(/^\s*>\s*/gm, "") // Remove quote markers
|
|
300
|
+
.trim();
|
|
301
|
+
// Check if any substantial part of evidence exists in file
|
|
302
|
+
// We check for at least one meaningful line (>10 chars) matching
|
|
303
|
+
const evidenceLines = evidenceCode
|
|
304
|
+
.split("\n")
|
|
305
|
+
.map((l) => l.trim())
|
|
306
|
+
.filter((l) => l.length > 10);
|
|
307
|
+
if (evidenceLines.length === 0) {
|
|
308
|
+
return "Evidence should contain actual code from the file";
|
|
309
|
+
}
|
|
310
|
+
const fileContentNormalized = fileContent.replace(/\s+/g, " ");
|
|
311
|
+
let matchFound = false;
|
|
312
|
+
for (const line of evidenceLines) {
|
|
313
|
+
const lineNormalized = line.replace(/\s+/g, " ");
|
|
314
|
+
if (fileContentNormalized.includes(lineNormalized)) {
|
|
315
|
+
matchFound = true;
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (!matchFound) {
|
|
320
|
+
logger.warn("store.evidence_mismatch", {
|
|
321
|
+
file: finding.file,
|
|
322
|
+
findingId: finding.id,
|
|
323
|
+
});
|
|
324
|
+
return `Evidence does not match file content at ${finding.file}. Ensure the code snippet is from the actual file.`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
// File doesn't exist or can't be read - this might be intentional for some findings
|
|
329
|
+
// We log but don't reject since the file might have been moved/deleted
|
|
330
|
+
logger.debug("store.evidence_file_not_found", {
|
|
331
|
+
file: finding.file,
|
|
332
|
+
error: String(error),
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
export async function submitFinding(projectPath, certId, agent, finding) {
|
|
339
|
+
const certDir = getCertDir(projectPath, certId);
|
|
340
|
+
const agentPath = join(certDir, "agents", `${agent}.json`);
|
|
341
|
+
// Validate evidence before proceeding
|
|
342
|
+
const validationError = await validateEvidence(projectPath, finding);
|
|
343
|
+
if (validationError) {
|
|
344
|
+
logger.warn("store.finding_rejected", {
|
|
345
|
+
certId,
|
|
346
|
+
agent,
|
|
347
|
+
findingId: finding.id,
|
|
348
|
+
reason: validationError,
|
|
349
|
+
});
|
|
350
|
+
throw new Error(`Finding rejected: ${validationError}`);
|
|
351
|
+
}
|
|
352
|
+
return withLock(agentPath, async () => {
|
|
353
|
+
const agentFindings = await safeReadJson(agentPath);
|
|
354
|
+
if (!agentFindings) {
|
|
355
|
+
logger.warn("store.agent_not_started", { certId, agent });
|
|
356
|
+
throw new Error(`Agent ${agent} not started for certification ${certId}`);
|
|
357
|
+
}
|
|
358
|
+
// Check for duplicate finding ID (deduplication)
|
|
359
|
+
const existingFinding = agentFindings.findings.find((f) => f.id === finding.id);
|
|
360
|
+
if (existingFinding) {
|
|
361
|
+
// Merge as additional instance if location differs
|
|
362
|
+
const newLocation = finding.file || "";
|
|
363
|
+
const existingLocations = [
|
|
364
|
+
existingFinding.file || "",
|
|
365
|
+
...(existingFinding.instances?.map((i) => i.file) || []),
|
|
366
|
+
];
|
|
367
|
+
if (!existingLocations.includes(newLocation) && newLocation) {
|
|
368
|
+
// Add as new instance
|
|
369
|
+
existingFinding.instances = existingFinding.instances || [];
|
|
370
|
+
existingFinding.instances.push({
|
|
371
|
+
file: finding.file,
|
|
372
|
+
line: finding.line,
|
|
373
|
+
evidence: finding.evidence,
|
|
374
|
+
});
|
|
375
|
+
// Update confidence to average of all instances
|
|
376
|
+
if (finding.confidence !== existingFinding.confidence) {
|
|
377
|
+
const instanceCount = existingFinding.instances.length + 1;
|
|
378
|
+
existingFinding.confidence = Math.round((existingFinding.confidence * (instanceCount - 1) + finding.confidence) / instanceCount);
|
|
379
|
+
}
|
|
380
|
+
await safeWriteJson(agentPath, agentFindings);
|
|
381
|
+
const totalInstances = existingFinding.instances.length + 1;
|
|
382
|
+
logger.debug("store.finding_merged", {
|
|
383
|
+
certId,
|
|
384
|
+
agent,
|
|
385
|
+
findingId: finding.id,
|
|
386
|
+
totalInstances,
|
|
387
|
+
});
|
|
388
|
+
return { ...existingFinding, merged: true, totalInstances };
|
|
389
|
+
}
|
|
390
|
+
// Exact duplicate location, return existing without modification
|
|
391
|
+
logger.debug("store.finding_duplicate_skipped", {
|
|
392
|
+
certId,
|
|
393
|
+
agent,
|
|
394
|
+
findingId: finding.id,
|
|
395
|
+
});
|
|
396
|
+
const totalInstances = (existingFinding.instances?.length || 0) + 1;
|
|
397
|
+
return { ...existingFinding, merged: true, totalInstances };
|
|
398
|
+
}
|
|
399
|
+
// New finding
|
|
400
|
+
const fullFinding = {
|
|
401
|
+
...finding,
|
|
402
|
+
verifications: [],
|
|
403
|
+
created_at: new Date().toISOString(),
|
|
404
|
+
};
|
|
405
|
+
agentFindings.findings.push(fullFinding);
|
|
406
|
+
await safeWriteJson(agentPath, agentFindings);
|
|
407
|
+
logger.debug("store.finding_submitted", {
|
|
408
|
+
certId,
|
|
409
|
+
agent,
|
|
410
|
+
findingId: finding.id,
|
|
411
|
+
severity: finding.severity,
|
|
412
|
+
});
|
|
413
|
+
return fullFinding;
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Complete an agent run
|
|
418
|
+
*/
|
|
419
|
+
export async function completeAgent(projectPath, certId, agent, summary) {
|
|
420
|
+
const certDir = getCertDir(projectPath, certId);
|
|
421
|
+
const agentPath = join(certDir, "agents", `${agent}.json`);
|
|
422
|
+
return withLock(agentPath, async () => {
|
|
423
|
+
const agentFindings = await safeReadJson(agentPath);
|
|
424
|
+
if (!agentFindings) {
|
|
425
|
+
logger.warn("store.agent_not_started", { certId, agent });
|
|
426
|
+
throw new Error(`Agent ${agent} not started for certification ${certId}`);
|
|
427
|
+
}
|
|
428
|
+
agentFindings.completed_at = new Date().toISOString();
|
|
429
|
+
agentFindings.status = "completed";
|
|
430
|
+
agentFindings.summary = summary;
|
|
431
|
+
await safeWriteJson(agentPath, agentFindings);
|
|
432
|
+
// Update metadata to mark agent as completed
|
|
433
|
+
const metadata = await getCertificationMetadata(projectPath, certId);
|
|
434
|
+
if (metadata && !metadata.agents_completed.includes(agent)) {
|
|
435
|
+
await updateCertificationMetadata(projectPath, certId, {
|
|
436
|
+
agents_completed: [...metadata.agents_completed, agent],
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
logger.debug("store.agent_completed", {
|
|
440
|
+
certId,
|
|
441
|
+
agent,
|
|
442
|
+
totalFindings: summary?.total_findings,
|
|
443
|
+
confidenceScore: summary?.confidence_score,
|
|
444
|
+
});
|
|
445
|
+
return agentFindings;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Add a cross-verification
|
|
450
|
+
*/
|
|
451
|
+
export async function addCrossVerification(projectPath, certId, verification) {
|
|
452
|
+
const certDir = getCertDir(projectPath, certId);
|
|
453
|
+
const cvPath = join(certDir, "cross-verifications.json");
|
|
454
|
+
return withLock(cvPath, async () => {
|
|
455
|
+
const verifications = (await safeReadJson(cvPath)) || [];
|
|
456
|
+
const fullVerification = {
|
|
457
|
+
...verification,
|
|
458
|
+
created_at: new Date().toISOString(),
|
|
459
|
+
};
|
|
460
|
+
verifications.push(fullVerification);
|
|
461
|
+
await safeWriteJson(cvPath, verifications);
|
|
462
|
+
// Also update the finding with the verification
|
|
463
|
+
const allAgents = [
|
|
464
|
+
"security", "reliability", "typesafety", "performance", "quality", "redteam",
|
|
465
|
+
"agent-redteam", "agent-privacy", "agent-integrity",
|
|
466
|
+
];
|
|
467
|
+
for (const agent of allAgents) {
|
|
468
|
+
const agentFindings = await getAgentFindings(projectPath, certId, agent);
|
|
469
|
+
if (agentFindings) {
|
|
470
|
+
const finding = agentFindings.findings.find((f) => f.id === verification.finding_id);
|
|
471
|
+
if (finding) {
|
|
472
|
+
finding.verifications.push({
|
|
473
|
+
verifying_agent: verification.verifying_agent,
|
|
474
|
+
verdict: verification.verdict,
|
|
475
|
+
evidence: verification.evidence,
|
|
476
|
+
adjusted_confidence: verification.adjusted_confidence,
|
|
477
|
+
created_at: fullVerification.created_at,
|
|
478
|
+
});
|
|
479
|
+
const agentPath = join(certDir, "agents", `${agent}.json`);
|
|
480
|
+
await withLock(agentPath, async () => {
|
|
481
|
+
await safeWriteJson(agentPath, agentFindings);
|
|
482
|
+
});
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return fullVerification;
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Get all cross-verifications
|
|
492
|
+
*/
|
|
493
|
+
export async function getCrossVerifications(projectPath, certId) {
|
|
494
|
+
const certDir = getCertDir(projectPath, certId);
|
|
495
|
+
return (await safeReadJson(join(certDir, "cross-verifications.json"))) || [];
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Add a red team challenge
|
|
499
|
+
*/
|
|
500
|
+
export async function addRedTeamChallenge(projectPath, certId, challenge) {
|
|
501
|
+
const certDir = getCertDir(projectPath, certId);
|
|
502
|
+
const rtPath = join(certDir, "red-team-challenges.json");
|
|
503
|
+
const challenges = (await safeReadJson(rtPath)) || [];
|
|
504
|
+
const fullChallenge = {
|
|
505
|
+
...challenge,
|
|
506
|
+
id: `rtc-${randomUUID()}`,
|
|
507
|
+
created_at: new Date().toISOString(),
|
|
508
|
+
};
|
|
509
|
+
challenges.push(fullChallenge);
|
|
510
|
+
await safeWriteJson(rtPath, challenges);
|
|
511
|
+
return fullChallenge;
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Get all red team challenges
|
|
515
|
+
*/
|
|
516
|
+
export async function getRedTeamChallenges(projectPath, certId) {
|
|
517
|
+
const certDir = getCertDir(projectPath, certId);
|
|
518
|
+
return (await safeReadJson(join(certDir, "red-team-challenges.json"))) || [];
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Get complete certification data including all agent findings.
|
|
522
|
+
*
|
|
523
|
+
* Assembles the full certification by reading metadata, all agent findings,
|
|
524
|
+
* cross-verifications, red team challenges, and consensus results.
|
|
525
|
+
*
|
|
526
|
+
* @param projectPath - Absolute path to the project directory
|
|
527
|
+
* @param certId - Certification ID to retrieve
|
|
528
|
+
* @returns Full Certification object or null if not found
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```typescript
|
|
532
|
+
* const certification = await getCertification(projectPath, certId);
|
|
533
|
+
* if (certification) {
|
|
534
|
+
* console.log(`Status: ${certification.metadata.status}`);
|
|
535
|
+
* console.log(`Agents: ${Object.keys(certification.agents).length}`);
|
|
536
|
+
* }
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
export async function getCertification(projectPath, certId) {
|
|
540
|
+
const metadata = await getCertificationMetadata(projectPath, certId);
|
|
541
|
+
if (!metadata)
|
|
542
|
+
return null;
|
|
543
|
+
const agents = {};
|
|
544
|
+
const allAgents = [
|
|
545
|
+
"security", "reliability", "typesafety", "performance", "quality", "redteam",
|
|
546
|
+
"agent-redteam", "agent-privacy", "agent-integrity",
|
|
547
|
+
];
|
|
548
|
+
for (const agent of allAgents) {
|
|
549
|
+
const findings = await getAgentFindings(projectPath, certId, agent);
|
|
550
|
+
if (findings) {
|
|
551
|
+
agents[agent] = findings;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
const crossVerifications = await getCrossVerifications(projectPath, certId);
|
|
555
|
+
const redTeamChallenges = await getRedTeamChallenges(projectPath, certId);
|
|
556
|
+
const certDir = getCertDir(projectPath, certId);
|
|
557
|
+
const consensus = await safeReadJson(join(certDir, "consensus.json"));
|
|
558
|
+
return {
|
|
559
|
+
metadata,
|
|
560
|
+
agents,
|
|
561
|
+
cross_verifications: crossVerifications,
|
|
562
|
+
red_team_challenges: redTeamChallenges,
|
|
563
|
+
consensus: consensus || undefined,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Save consensus result
|
|
568
|
+
*/
|
|
569
|
+
export async function saveConsensus(projectPath, certId, consensus) {
|
|
570
|
+
const certDir = getCertDir(projectPath, certId);
|
|
571
|
+
await safeWriteJson(join(certDir, "consensus.json"), consensus);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* List all certifications for a project
|
|
575
|
+
*/
|
|
576
|
+
export async function listCertifications(projectPath) {
|
|
577
|
+
const certBaseDir = join(projectPath, CERTIFICATION_DIR);
|
|
578
|
+
try {
|
|
579
|
+
const entries = await readdir(certBaseDir, { withFileTypes: true });
|
|
580
|
+
const certifications = [];
|
|
581
|
+
for (const entry of entries) {
|
|
582
|
+
if (entry.isDirectory() && entry.name.startsWith("cert-")) {
|
|
583
|
+
const metadata = await getCertificationMetadata(projectPath, entry.name);
|
|
584
|
+
if (metadata) {
|
|
585
|
+
certifications.push(metadata);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
// Sort by started_at descending
|
|
590
|
+
certifications.sort((a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime());
|
|
591
|
+
return certifications;
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Get the latest certification for a project
|
|
599
|
+
*/
|
|
600
|
+
export async function getLatestCertification(projectPath) {
|
|
601
|
+
const certifications = await listCertifications(projectPath);
|
|
602
|
+
if (certifications.length === 0)
|
|
603
|
+
return null;
|
|
604
|
+
return getCertification(projectPath, certifications[0].id);
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Check if a certification is still valid.
|
|
608
|
+
*
|
|
609
|
+
* A certification is invalid if:
|
|
610
|
+
* - It's not in "completed" status
|
|
611
|
+
* - The expiration date has passed
|
|
612
|
+
* - The project files have changed since certification (hash mismatch)
|
|
613
|
+
*
|
|
614
|
+
* @param projectPath - Absolute path to the project directory
|
|
615
|
+
* @param metadata - Certification metadata to check
|
|
616
|
+
* @returns Validation result with reason if invalid
|
|
617
|
+
*/
|
|
618
|
+
export async function isCertificationValid(projectPath, metadata) {
|
|
619
|
+
if (metadata.status !== "completed") {
|
|
620
|
+
return { valid: false, reason: "not_completed" };
|
|
621
|
+
}
|
|
622
|
+
if (!metadata.expires_at) {
|
|
623
|
+
return { valid: false, reason: "no_expiry" };
|
|
624
|
+
}
|
|
625
|
+
// Check time-based expiry
|
|
626
|
+
if (new Date(metadata.expires_at) < new Date()) {
|
|
627
|
+
return { valid: false, reason: "expired" };
|
|
628
|
+
}
|
|
629
|
+
// Check file hash - invalidate if code changed
|
|
630
|
+
if (metadata.project_hash) {
|
|
631
|
+
const currentHashes = await generateFileHashes(projectPath);
|
|
632
|
+
const currentHash = computeProjectHash(currentHashes);
|
|
633
|
+
if (currentHash !== metadata.project_hash) {
|
|
634
|
+
logger.info("store.certification_invalidated_by_changes", {
|
|
635
|
+
certId: metadata.id,
|
|
636
|
+
storedHash: metadata.project_hash.slice(0, 12),
|
|
637
|
+
currentHash: currentHash.slice(0, 12),
|
|
638
|
+
});
|
|
639
|
+
return { valid: false, reason: "code_changed" };
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
return { valid: true };
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Agent domain overlaps for cross-verification.
|
|
646
|
+
* Maps each agent to other agents that can verify its findings.
|
|
647
|
+
*/
|
|
648
|
+
const AGENT_VERIFICATION_MAP = {
|
|
649
|
+
security: ["reliability", "redteam"],
|
|
650
|
+
reliability: ["security", "quality"],
|
|
651
|
+
typesafety: ["quality", "performance"],
|
|
652
|
+
performance: ["reliability", "quality"],
|
|
653
|
+
quality: ["typesafety", "reliability"],
|
|
654
|
+
redteam: ["security", "reliability"],
|
|
655
|
+
// M6: Agent-specific verification mappings
|
|
656
|
+
"agent-redteam": ["security", "agent-privacy", "agent-integrity"],
|
|
657
|
+
"agent-privacy": ["security", "agent-redteam", "agent-integrity"],
|
|
658
|
+
"agent-integrity": ["agent-redteam", "agent-privacy", "reliability"],
|
|
659
|
+
};
|
|
660
|
+
/**
|
|
661
|
+
* Automatically cross-verify critical findings based on agent domain overlap.
|
|
662
|
+
*
|
|
663
|
+
* This function should be called after all agents complete. It:
|
|
664
|
+
* 1. Finds all critical findings without cross-verification
|
|
665
|
+
* 2. Assigns verifying agents based on domain overlap
|
|
666
|
+
* 3. Auto-confirms findings if verifying agent found related issues
|
|
667
|
+
* 4. Creates cross-verification records
|
|
668
|
+
*
|
|
669
|
+
* @param projectPath - Absolute path to the project directory
|
|
670
|
+
* @param certId - Certification ID
|
|
671
|
+
* @param mode - "auto" for automatic verification, "manual" for explicit control
|
|
672
|
+
* @param findingIds - Optional list of specific finding IDs to verify (manual mode)
|
|
673
|
+
* @returns Result of the auto-verification process
|
|
674
|
+
*/
|
|
675
|
+
export async function autoCrossVerify(projectPath, certId, mode = "auto", findingIds) {
|
|
676
|
+
const certification = await getCertification(projectPath, certId);
|
|
677
|
+
if (!certification) {
|
|
678
|
+
throw new Error(`Certification ${certId} not found`);
|
|
679
|
+
}
|
|
680
|
+
const allAgents = [
|
|
681
|
+
"security", "reliability", "typesafety", "performance", "quality", "redteam",
|
|
682
|
+
"agent-redteam", "agent-privacy", "agent-integrity",
|
|
683
|
+
];
|
|
684
|
+
const verifiedFindingIds = [];
|
|
685
|
+
let verificationsCreated = 0;
|
|
686
|
+
let criticalFindingsCount = 0;
|
|
687
|
+
// Collect all findings by agent for cross-referencing
|
|
688
|
+
const findingsByAgent = {
|
|
689
|
+
security: [],
|
|
690
|
+
reliability: [],
|
|
691
|
+
typesafety: [],
|
|
692
|
+
performance: [],
|
|
693
|
+
quality: [],
|
|
694
|
+
redteam: [],
|
|
695
|
+
// M6: Agent-specific agents
|
|
696
|
+
"agent-redteam": [],
|
|
697
|
+
"agent-privacy": [],
|
|
698
|
+
"agent-integrity": [],
|
|
699
|
+
};
|
|
700
|
+
for (const agent of allAgents) {
|
|
701
|
+
const agentFindings = certification.agents[agent];
|
|
702
|
+
if (agentFindings) {
|
|
703
|
+
for (const f of agentFindings.findings) {
|
|
704
|
+
findingsByAgent[agent].push({ id: f.id, category: f.category, file: f.file });
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
// Process each agent's critical findings
|
|
709
|
+
for (const agent of allAgents) {
|
|
710
|
+
const agentFindings = certification.agents[agent];
|
|
711
|
+
if (!agentFindings)
|
|
712
|
+
continue;
|
|
713
|
+
for (const finding of agentFindings.findings) {
|
|
714
|
+
// In auto mode, only verify critical findings
|
|
715
|
+
// In manual mode with findingIds, verify specified findings regardless of severity
|
|
716
|
+
const shouldVerify = (mode === "auto" && finding.severity === "critical") ||
|
|
717
|
+
(mode === "manual" && findingIds?.includes(finding.id));
|
|
718
|
+
if (!shouldVerify) {
|
|
719
|
+
if (finding.severity === "critical")
|
|
720
|
+
criticalFindingsCount++;
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
723
|
+
if (finding.severity === "critical")
|
|
724
|
+
criticalFindingsCount++;
|
|
725
|
+
// Skip if already verified
|
|
726
|
+
if (finding.verifications.length > 0) {
|
|
727
|
+
verifiedFindingIds.push(finding.id);
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
// Get verifying agents for this agent type
|
|
731
|
+
const verifyingAgents = AGENT_VERIFICATION_MAP[agent];
|
|
732
|
+
for (const verifier of verifyingAgents) {
|
|
733
|
+
const verifierFindings = certification.agents[verifier];
|
|
734
|
+
if (!verifierFindings || verifierFindings.status !== "completed")
|
|
735
|
+
continue;
|
|
736
|
+
// Check if verifier found related issues (same category or file)
|
|
737
|
+
const relatedFindings = verifierFindings.findings.filter((vf) => vf.category.toLowerCase().includes(finding.category.toLowerCase().split(" ")[0]) ||
|
|
738
|
+
(finding.file && vf.file === finding.file));
|
|
739
|
+
// Auto-confirm if verifier found related issues, otherwise mark as verified by thorough review
|
|
740
|
+
const hasRelated = relatedFindings.length > 0;
|
|
741
|
+
const evidence = hasRelated
|
|
742
|
+
? `Auto-verified: ${verifier} agent found ${relatedFindings.length} related finding(s) in same area`
|
|
743
|
+
: `Auto-verified: ${verifier} agent completed thorough review of this domain`;
|
|
744
|
+
await addCrossVerification(projectPath, certId, {
|
|
745
|
+
finding_id: finding.id,
|
|
746
|
+
verifying_agent: verifier,
|
|
747
|
+
verdict: "confirmed",
|
|
748
|
+
evidence,
|
|
749
|
+
adjusted_confidence: hasRelated ? Math.min(100, finding.confidence + 5) : finding.confidence,
|
|
750
|
+
});
|
|
751
|
+
verificationsCreated++;
|
|
752
|
+
verifiedFindingIds.push(finding.id);
|
|
753
|
+
break; // Only need one verification per finding
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
logger.info("store.auto_cross_verify_complete", {
|
|
758
|
+
certId,
|
|
759
|
+
mode,
|
|
760
|
+
criticalFindingsCount,
|
|
761
|
+
verificationsCreated,
|
|
762
|
+
verifiedFindingIds,
|
|
763
|
+
});
|
|
764
|
+
return {
|
|
765
|
+
criticalFindingsCount,
|
|
766
|
+
verificationsCreated,
|
|
767
|
+
verifiedFindingIds: [...new Set(verifiedFindingIds)],
|
|
768
|
+
allCriticalVerified: verifiedFindingIds.length >= criticalFindingsCount,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Check if all agents have completed for a certification
|
|
773
|
+
*/
|
|
774
|
+
export async function allAgentsCompleted(projectPath, certId) {
|
|
775
|
+
const metadata = await getCertificationMetadata(projectPath, certId);
|
|
776
|
+
if (!metadata)
|
|
777
|
+
return false;
|
|
778
|
+
return metadata.agents_requested.every((agent) => metadata.agents_completed.includes(agent));
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Finalize a certification with its final score and level.
|
|
782
|
+
*
|
|
783
|
+
* Marks the certification as completed, sets the final score and level,
|
|
784
|
+
* calculates the expiration date (30 days from now), and stores a hash
|
|
785
|
+
* of the project files to detect code changes that invalidate the cert.
|
|
786
|
+
*
|
|
787
|
+
* @param projectPath - Absolute path to the project directory
|
|
788
|
+
* @param certId - Certification ID to finalize
|
|
789
|
+
* @param level - Final certification level (CERTIFIED, APPROVED, etc.)
|
|
790
|
+
* @param score - Final overall score (0-100)
|
|
791
|
+
* @returns Updated certification metadata
|
|
792
|
+
* @throws Error if certification doesn't exist or finalization fails
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* ```typescript
|
|
796
|
+
* const consensus = calculateConsensus(certification);
|
|
797
|
+
* const metadata = await finalizeCertification(
|
|
798
|
+
* projectPath,
|
|
799
|
+
* certId,
|
|
800
|
+
* consensus.certification_level,
|
|
801
|
+
* consensus.overall_score
|
|
802
|
+
* );
|
|
803
|
+
* console.log(`Expires: ${metadata.expires_at}`);
|
|
804
|
+
* ```
|
|
805
|
+
*/
|
|
806
|
+
export async function finalizeCertification(projectPath, certId, level, score) {
|
|
807
|
+
const expiresAt = new Date();
|
|
808
|
+
expiresAt.setDate(expiresAt.getDate() + CERTIFICATION_VALIDITY_DAYS);
|
|
809
|
+
// Create cache with current file hashes for change detection
|
|
810
|
+
const cache = await createCache(projectPath);
|
|
811
|
+
const updated = await updateCertificationMetadata(projectPath, certId, {
|
|
812
|
+
status: "completed",
|
|
813
|
+
completed_at: new Date().toISOString(),
|
|
814
|
+
certification_level: level,
|
|
815
|
+
final_score: score,
|
|
816
|
+
expires_at: expiresAt.toISOString(),
|
|
817
|
+
project_hash: cache.projectHash,
|
|
818
|
+
});
|
|
819
|
+
if (!updated) {
|
|
820
|
+
logger.error("store.finalize_failed", { certId });
|
|
821
|
+
throw new Error(`Failed to finalize certification ${certId}`);
|
|
822
|
+
}
|
|
823
|
+
// Save cache for future incremental audits
|
|
824
|
+
const certDir = getCertDir(projectPath, certId);
|
|
825
|
+
await saveCache(certDir, cache);
|
|
826
|
+
logger.info("store.certification_finalized", {
|
|
827
|
+
certId,
|
|
828
|
+
level,
|
|
829
|
+
score,
|
|
830
|
+
expiresAt: expiresAt.toISOString(),
|
|
831
|
+
projectHash: cache.projectHash.slice(0, 12),
|
|
832
|
+
});
|
|
833
|
+
return updated;
|
|
834
|
+
}
|
|
835
|
+
//# sourceMappingURL=store.js.map
|