@zivis/mcp 0.1.0-alpha.9 → 0.1.6
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/LICENSE +201 -0
- package/README.md +19 -0
- package/dist/api-client.d.ts +1 -31
- package/dist/api-client.js +26 -66
- package/dist/auth/index.d.ts +1 -22
- package/dist/auth/index.js +15 -46
- package/dist/auth/jwt.d.ts +0 -16
- package/dist/auth/jwt.js +0 -13
- package/dist/auth/keychain.d.ts +6 -32
- package/dist/auth/keychain.js +83 -114
- package/dist/auth/oauth.d.ts +1 -42
- package/dist/auth/oauth.js +22 -64
- package/dist/auth/sessions.d.ts +5 -25
- package/dist/auth/sessions.js +20 -39
- package/dist/auth/token-refresh.d.ts +2 -22
- package/dist/auth/token-refresh.js +12 -47
- package/dist/cli.d.ts +1 -18
- package/dist/cli.js +30 -908
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -7
- package/dist/lib/inspect-cache.d.ts +10 -0
- package/dist/lib/inspect-cache.js +75 -0
- package/dist/lib/next-steps.d.ts +27 -0
- package/dist/lib/next-steps.js +21 -0
- package/dist/matcher/ast-eval.d.ts +8 -0
- package/dist/matcher/ast-eval.js +95 -0
- package/dist/matcher/finding.d.ts +55 -0
- package/dist/matcher/finding.js +1 -0
- package/dist/matcher/index.d.ts +8 -0
- package/dist/matcher/index.js +202 -0
- package/dist/matcher/inference-candidates.d.ts +26 -0
- package/dist/matcher/inference-candidates.js +81 -0
- package/dist/matcher/walker.d.ts +7 -0
- package/dist/matcher/walker.js +71 -0
- package/dist/pattern-pack/index.d.ts +125 -0
- package/dist/pattern-pack/index.js +189 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/agents/privilege-separation.yaml +224 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/prompting/self-consistency-no-isolation.yaml +237 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/retrieval/context-injection-no-validator.yaml +348 -0
- package/dist/pattern-packs/zivis-public-0.2.0/capsules/security/late-org-filter.yaml +266 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/external_validator_on_facts.yaml +37 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/fact_validator_present.yaml +68 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/human_approval_gate.yaml +44 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/langgraph_state_machine_with_per_node_tools.yaml +35 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/per_sample_retrieval_diversification.yaml +38 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/prisma_extension_or_middleware_attaching_org_filter.yaml +31 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/row_level_security_policy.yaml +37 -0
- package/dist/pattern-packs/zivis-public-0.2.0/controls/source_attribution_present.yaml +58 -0
- package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +167 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/agents/privilege-separation/identify.md +54 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/retrieval/context-injection-no-validator/identify.md +109 -0
- package/dist/pattern-packs/zivis-public-0.2.0/prompts/security/late-org-filter/identify.md +78 -0
- package/dist/project-binding.d.ts +2 -19
- package/dist/project-binding.js +38 -21
- package/dist/prompts/audit-dependencies.d.ts +2 -0
- package/dist/prompts/audit-dependencies.js +47 -0
- package/dist/prompts/getting-started.d.ts +2 -0
- package/dist/prompts/getting-started.js +37 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +6 -0
- package/dist/resolve-application-id.d.ts +0 -4
- package/dist/resolve-application-id.js +0 -5
- package/dist/sanitize.d.ts +1 -21
- package/dist/sanitize.js +7 -41
- package/dist/server.d.ts +1 -13
- package/dist/server.js +134 -253
- package/dist/tools/artifacts.d.ts +76 -0
- package/dist/tools/artifacts.js +178 -0
- package/dist/tools/check-project.d.ts +5 -18
- package/dist/tools/check-project.js +120 -111
- package/dist/tools/check-repo-trust.d.ts +4 -19
- package/dist/tools/check-repo-trust.js +56 -47
- package/dist/tools/create-diagram.d.ts +0 -5
- package/dist/tools/create-diagram.js +0 -10
- package/dist/tools/create-document.d.ts +0 -5
- package/dist/tools/create-document.js +3 -9
- package/dist/tools/create-finding.d.ts +85 -0
- package/dist/tools/create-finding.js +136 -0
- package/dist/tools/delete-finding.d.ts +19 -0
- package/dist/tools/delete-finding.js +36 -0
- package/dist/tools/discover-local-infra.d.ts +0 -10
- package/dist/tools/discover-local-infra.js +3 -73
- package/dist/tools/enterprise/get-org-zat.d.ts +0 -5
- package/dist/tools/enterprise/get-org-zat.js +0 -6
- package/dist/tools/enterprise/get-threat-model.d.ts +1 -8
- package/dist/tools/enterprise/get-threat-model.js +9 -31
- package/dist/tools/enterprise/list-attack-scenarios.d.ts +24 -0
- package/dist/tools/enterprise/list-attack-scenarios.js +63 -0
- package/dist/tools/enterprise/list-threat-models.d.ts +1 -6
- package/dist/tools/enterprise/list-threat-models.js +1 -9
- package/dist/tools/enterprise/manage-actor.d.ts +2 -7
- package/dist/tools/enterprise/manage-actor.js +13 -7
- package/dist/tools/enterprise/manage-attack-scenario.d.ts +1 -6
- package/dist/tools/enterprise/manage-attack-scenario.js +12 -7
- package/dist/tools/enterprise/manage-data-asset.d.ts +2 -7
- package/dist/tools/enterprise/manage-data-asset.js +16 -7
- package/dist/tools/enterprise/manage-security-control.d.ts +1 -6
- package/dist/tools/enterprise/manage-security-control.js +17 -7
- package/dist/tools/explain-signal-for-diff.d.ts +34 -0
- package/dist/tools/explain-signal-for-diff.js +75 -0
- package/dist/tools/generate-diagram.d.ts +0 -6
- package/dist/tools/generate-diagram.js +21 -13
- package/dist/tools/get-application-overview.d.ts +0 -5
- package/dist/tools/get-application-overview.js +0 -6
- package/dist/tools/get-application.d.ts +0 -5
- package/dist/tools/get-application.js +0 -6
- package/dist/tools/get-diagram.d.ts +0 -5
- package/dist/tools/get-diagram.js +1 -11
- package/dist/tools/get-document.d.ts +0 -5
- package/dist/tools/get-document.js +0 -6
- package/dist/tools/get-oss-zat.d.ts +0 -5
- package/dist/tools/get-oss-zat.js +0 -7
- package/dist/tools/get-signal.d.ts +24 -0
- package/dist/tools/get-signal.js +75 -0
- package/dist/tools/get-started.d.ts +18 -0
- package/dist/tools/get-started.js +470 -0
- package/dist/tools/get-trust-keys.d.ts +0 -5
- package/dist/tools/get-trust-keys.js +0 -6
- package/dist/tools/import-openapi-endpoints.d.ts +0 -5
- package/dist/tools/import-openapi-endpoints.js +0 -6
- package/dist/tools/inspect-zat.d.ts +0 -5
- package/dist/tools/inspect-zat.js +0 -19
- package/dist/tools/inspect.d.ts +21 -0
- package/dist/tools/inspect.js +222 -0
- package/dist/tools/list-applications.d.ts +1 -6
- package/dist/tools/list-applications.js +0 -6
- package/dist/tools/list-diagrams.d.ts +0 -5
- package/dist/tools/list-diagrams.js +0 -6
- package/dist/tools/list-documents.d.ts +0 -5
- package/dist/tools/list-documents.js +0 -6
- package/dist/tools/list-endpoints.d.ts +1 -6
- package/dist/tools/list-endpoints.js +0 -6
- package/dist/tools/list-signals.d.ts +37 -0
- package/dist/tools/list-signals.js +83 -0
- package/dist/tools/manage-application.d.ts +64 -0
- package/dist/tools/manage-application.js +129 -0
- package/dist/tools/manage-diagram.d.ts +0 -5
- package/dist/tools/manage-diagram.js +0 -16
- package/dist/tools/manage-endpoint-lifecycle.d.ts +80 -0
- package/dist/tools/manage-endpoint-lifecycle.js +180 -0
- package/dist/tools/open-in-ide.d.ts +2 -14
- package/dist/tools/open-in-ide.js +0 -13
- package/dist/tools/review-change.d.ts +34 -0
- package/dist/tools/review-change.js +93 -0
- package/dist/tools/security-review.d.ts +0 -16
- package/dist/tools/security-review.js +63 -77
- package/dist/tools/threat-get-capsule.d.ts +15 -0
- package/dist/tools/threat-get-capsule.js +53 -0
- package/dist/tools/threat-get-inference-prompt.d.ts +15 -0
- package/dist/tools/threat-get-inference-prompt.js +73 -0
- package/dist/tools/threat-list-relevant-capsules.d.ts +17 -0
- package/dist/tools/threat-list-relevant-capsules.js +158 -0
- package/dist/tools/threat-run-matcher.d.ts +17 -0
- package/dist/tools/threat-run-matcher.js +145 -0
- package/dist/tools/update-document.d.ts +0 -5
- package/dist/tools/update-document.js +3 -9
- package/dist/tools/update-endpoint.d.ts +1 -6
- package/dist/tools/update-endpoint.js +0 -7
- package/dist/tools/update-finding.d.ts +61 -0
- package/dist/tools/update-finding.js +80 -0
- package/dist/tools/update-mermaid-source.d.ts +0 -13
- package/dist/tools/update-mermaid-source.js +0 -14
- package/dist/tools/verify-trust-mark.d.ts +0 -5
- package/dist/tools/verify-trust-mark.js +0 -6
- package/dist/types.d.ts +13 -13
- package/dist/types.js +22 -28
- package/package.json +28 -5
- package/dist/api-client.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/jwt.js.map +0 -1
- package/dist/auth/keychain.js.map +0 -1
- package/dist/auth/oauth.js.map +0 -1
- package/dist/auth/sessions.js.map +0 -1
- package/dist/auth/token-refresh.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/project-binding.js.map +0 -1
- package/dist/resolve-application-id.js.map +0 -1
- package/dist/sanitize.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/tools/check-project.js.map +0 -1
- package/dist/tools/check-repo-trust.js.map +0 -1
- package/dist/tools/create-diagram.js.map +0 -1
- package/dist/tools/create-document.js.map +0 -1
- package/dist/tools/discover-local-infra.js.map +0 -1
- package/dist/tools/enterprise/capture-evidence.d.ts +0 -54
- package/dist/tools/enterprise/capture-evidence.js +0 -72
- package/dist/tools/enterprise/capture-evidence.js.map +0 -1
- package/dist/tools/enterprise/create-report-ticket.d.ts +0 -34
- package/dist/tools/enterprise/create-report-ticket.js +0 -44
- package/dist/tools/enterprise/create-report-ticket.js.map +0 -1
- package/dist/tools/enterprise/end-pentest-session.d.ts +0 -33
- package/dist/tools/enterprise/end-pentest-session.js +0 -42
- package/dist/tools/enterprise/end-pentest-session.js.map +0 -1
- package/dist/tools/enterprise/generate-report.d.ts +0 -55
- package/dist/tools/enterprise/generate-report.js +0 -111
- package/dist/tools/enterprise/generate-report.js.map +0 -1
- package/dist/tools/enterprise/get-org-zat.js.map +0 -1
- package/dist/tools/enterprise/get-report-status.d.ts +0 -27
- package/dist/tools/enterprise/get-report-status.js +0 -38
- package/dist/tools/enterprise/get-report-status.js.map +0 -1
- package/dist/tools/enterprise/get-threat-model.js.map +0 -1
- package/dist/tools/enterprise/list-agents.d.ts +0 -42
- package/dist/tools/enterprise/list-agents.js +0 -95
- package/dist/tools/enterprise/list-agents.js.map +0 -1
- package/dist/tools/enterprise/list-report-issues.d.ts +0 -36
- package/dist/tools/enterprise/list-report-issues.js +0 -50
- package/dist/tools/enterprise/list-report-issues.js.map +0 -1
- package/dist/tools/enterprise/list-threat-models.js.map +0 -1
- package/dist/tools/enterprise/manage-actor.js.map +0 -1
- package/dist/tools/enterprise/manage-attack-scenario.js.map +0 -1
- package/dist/tools/enterprise/manage-component.d.ts +0 -58
- package/dist/tools/enterprise/manage-component.js +0 -90
- package/dist/tools/enterprise/manage-component.js.map +0 -1
- package/dist/tools/enterprise/manage-data-asset.js.map +0 -1
- package/dist/tools/enterprise/manage-data-flow.d.ts +0 -57
- package/dist/tools/enterprise/manage-data-flow.js +0 -98
- package/dist/tools/enterprise/manage-data-flow.js.map +0 -1
- package/dist/tools/enterprise/manage-finding.d.ts +0 -69
- package/dist/tools/enterprise/manage-finding.js +0 -106
- package/dist/tools/enterprise/manage-finding.js.map +0 -1
- package/dist/tools/enterprise/manage-security-control.js.map +0 -1
- package/dist/tools/enterprise/manage-test-case.d.ts +0 -88
- package/dist/tools/enterprise/manage-test-case.js +0 -119
- package/dist/tools/enterprise/manage-test-case.js.map +0 -1
- package/dist/tools/enterprise/promote-finding-to-issue.d.ts +0 -36
- package/dist/tools/enterprise/promote-finding-to-issue.js +0 -65
- package/dist/tools/enterprise/promote-finding-to-issue.js.map +0 -1
- package/dist/tools/enterprise/publish-report-version.d.ts +0 -34
- package/dist/tools/enterprise/publish-report-version.js +0 -75
- package/dist/tools/enterprise/publish-report-version.js.map +0 -1
- package/dist/tools/enterprise/publish-test-to-library.d.ts +0 -31
- package/dist/tools/enterprise/publish-test-to-library.js +0 -40
- package/dist/tools/enterprise/publish-test-to-library.js.map +0 -1
- package/dist/tools/enterprise/record-test-result.d.ts +0 -67
- package/dist/tools/enterprise/record-test-result.js +0 -75
- package/dist/tools/enterprise/record-test-result.js.map +0 -1
- package/dist/tools/enterprise/start-pentest-session.d.ts +0 -35
- package/dist/tools/enterprise/start-pentest-session.js +0 -50
- package/dist/tools/enterprise/start-pentest-session.js.map +0 -1
- package/dist/tools/enterprise/sync-report-section.d.ts +0 -41
- package/dist/tools/enterprise/sync-report-section.js +0 -79
- package/dist/tools/enterprise/sync-report-section.js.map +0 -1
- package/dist/tools/enterprise/update-report-issue.d.ts +0 -55
- package/dist/tools/enterprise/update-report-issue.js +0 -69
- package/dist/tools/enterprise/update-report-issue.js.map +0 -1
- package/dist/tools/generate-diagram.js.map +0 -1
- package/dist/tools/get-agent-test-results.d.ts +0 -41
- package/dist/tools/get-agent-test-results.js +0 -86
- package/dist/tools/get-agent-test-results.js.map +0 -1
- package/dist/tools/get-application-overview.js.map +0 -1
- package/dist/tools/get-application.js.map +0 -1
- package/dist/tools/get-artifact-content.d.ts +0 -29
- package/dist/tools/get-artifact-content.js +0 -86
- package/dist/tools/get-artifact-content.js.map +0 -1
- package/dist/tools/get-diagram.js.map +0 -1
- package/dist/tools/get-document.js.map +0 -1
- package/dist/tools/get-finding-details.d.ts +0 -28
- package/dist/tools/get-finding-details.js +0 -43
- package/dist/tools/get-finding-details.js.map +0 -1
- package/dist/tools/get-findings.d.ts +0 -57
- package/dist/tools/get-findings.js +0 -103
- package/dist/tools/get-findings.js.map +0 -1
- package/dist/tools/get-oss-zat.js.map +0 -1
- package/dist/tools/get-recon-scan.d.ts +0 -27
- package/dist/tools/get-recon-scan.js +0 -46
- package/dist/tools/get-recon-scan.js.map +0 -1
- package/dist/tools/get-scan-output.d.ts +0 -27
- package/dist/tools/get-scan-output.js +0 -64
- package/dist/tools/get-scan-output.js.map +0 -1
- package/dist/tools/get-scenario-details.d.ts +0 -27
- package/dist/tools/get-scenario-details.js +0 -46
- package/dist/tools/get-scenario-details.js.map +0 -1
- package/dist/tools/get-test-case-results.d.ts +0 -37
- package/dist/tools/get-test-case-results.js +0 -66
- package/dist/tools/get-test-case-results.js.map +0 -1
- package/dist/tools/get-test-details.d.ts +0 -29
- package/dist/tools/get-test-details.js +0 -49
- package/dist/tools/get-test-details.js.map +0 -1
- package/dist/tools/get-trust-keys.js.map +0 -1
- package/dist/tools/import-openapi-endpoints.js.map +0 -1
- package/dist/tools/inspect-zat.js.map +0 -1
- package/dist/tools/list-agent-test-cases.d.ts +0 -41
- package/dist/tools/list-agent-test-cases.js +0 -73
- package/dist/tools/list-agent-test-cases.js.map +0 -1
- package/dist/tools/list-applications.js.map +0 -1
- package/dist/tools/list-diagrams.js.map +0 -1
- package/dist/tools/list-documents.js.map +0 -1
- package/dist/tools/list-endpoints.js.map +0 -1
- package/dist/tools/list-recon-scans.d.ts +0 -36
- package/dist/tools/list-recon-scans.js +0 -74
- package/dist/tools/list-recon-scans.js.map +0 -1
- package/dist/tools/list-scan-artifacts.d.ts +0 -41
- package/dist/tools/list-scan-artifacts.js +0 -63
- package/dist/tools/list-scan-artifacts.js.map +0 -1
- package/dist/tools/list-scans.d.ts +0 -44
- package/dist/tools/list-scans.js +0 -91
- package/dist/tools/list-scans.js.map +0 -1
- package/dist/tools/list-test-library.d.ts +0 -44
- package/dist/tools/list-test-library.js +0 -83
- package/dist/tools/list-test-library.js.map +0 -1
- package/dist/tools/list-test-scenarios.d.ts +0 -31
- package/dist/tools/list-test-scenarios.js +0 -66
- package/dist/tools/list-test-scenarios.js.map +0 -1
- package/dist/tools/local-scan.d.ts +0 -40
- package/dist/tools/local-scan.js +0 -261
- package/dist/tools/local-scan.js.map +0 -1
- package/dist/tools/manage-diagram.js.map +0 -1
- package/dist/tools/open-in-ide.js.map +0 -1
- package/dist/tools/run-test-scenario.d.ts +0 -37
- package/dist/tools/run-test-scenario.js +0 -70
- package/dist/tools/run-test-scenario.js.map +0 -1
- package/dist/tools/scan-pr.d.ts +0 -27
- package/dist/tools/scan-pr.js +0 -51
- package/dist/tools/scan-pr.js.map +0 -1
- package/dist/tools/security-review.js.map +0 -1
- package/dist/tools/setup-red-team-target.d.ts +0 -79
- package/dist/tools/setup-red-team-target.js +0 -430
- package/dist/tools/setup-red-team-target.js.map +0 -1
- package/dist/tools/triage-finding.d.ts +0 -47
- package/dist/tools/triage-finding.js +0 -116
- package/dist/tools/triage-finding.js.map +0 -1
- package/dist/tools/update-document.js.map +0 -1
- package/dist/tools/update-endpoint.js.map +0 -1
- package/dist/tools/update-mermaid-source.js.map +0 -1
- package/dist/tools/verify-trust-mark.js.map +0 -1
- package/dist/types.js.map +0 -1
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* zivis_security_review — AI-powered security code review with ZIVIS intelligence
|
|
3
|
-
*
|
|
4
|
-
* Composite tool that gathers security context from multiple ZIVIS sources
|
|
5
|
-
* and returns it as structured input for Claude to use during code review.
|
|
6
|
-
*
|
|
7
|
-
* Sources:
|
|
8
|
-
* 1. Historical findings (resolved) — regression check patterns
|
|
9
|
-
* 2. Open findings — known vulnerabilities to verify aren't reintroduced
|
|
10
|
-
* 3. Threat model security controls — what's expected to be in place
|
|
11
|
-
* 4. Threat model attack scenarios — known attack vectors
|
|
12
|
-
* 5. OSS trust data — dependency risk signals
|
|
13
|
-
*
|
|
14
|
-
* This tool does NOT run scans itself. It assembles intelligence from ZIVIS
|
|
15
|
-
* so Claude can perform an informed, context-aware code review.
|
|
16
|
-
*/
|
|
17
1
|
import { z } from "zod";
|
|
18
2
|
import type { ApiClient } from "../api-client.js";
|
|
19
3
|
import type { ZivisConfig } from "../types.js";
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* zivis_security_review — AI-powered security code review with ZIVIS intelligence
|
|
3
|
-
*
|
|
4
|
-
* Composite tool that gathers security context from multiple ZIVIS sources
|
|
5
|
-
* and returns it as structured input for Claude to use during code review.
|
|
6
|
-
*
|
|
7
|
-
* Sources:
|
|
8
|
-
* 1. Historical findings (resolved) — regression check patterns
|
|
9
|
-
* 2. Open findings — known vulnerabilities to verify aren't reintroduced
|
|
10
|
-
* 3. Threat model security controls — what's expected to be in place
|
|
11
|
-
* 4. Threat model attack scenarios — known attack vectors
|
|
12
|
-
* 5. OSS trust data — dependency risk signals
|
|
13
|
-
*
|
|
14
|
-
* This tool does NOT run scans itself. It assembles intelligence from ZIVIS
|
|
15
|
-
* so Claude can perform an informed, context-aware code review.
|
|
16
|
-
*/
|
|
17
1
|
import { z } from "zod";
|
|
18
2
|
import { resolveApplicationId } from "../resolve-application-id.js";
|
|
19
3
|
import { sanitizeResponse } from "../sanitize.js";
|
|
@@ -60,7 +44,6 @@ export const SECURITY_REVIEW_SCHEMA = {
|
|
|
60
44
|
.optional()
|
|
61
45
|
.describe("Specific dependencies to check trust scores for (owner/repo format)"),
|
|
62
46
|
};
|
|
63
|
-
// Severity ordering for threshold filtering
|
|
64
47
|
const SEVERITY_ORDER = {
|
|
65
48
|
critical: 5,
|
|
66
49
|
high: 4,
|
|
@@ -89,7 +72,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
89
72
|
parameters: { repo, application_id, threat_model_id, campaign_id },
|
|
90
73
|
};
|
|
91
74
|
const errors = [];
|
|
92
|
-
// ── 1. Historical findings (regression check) ──
|
|
93
75
|
if (shouldInclude("regression") && (repo || application_id)) {
|
|
94
76
|
try {
|
|
95
77
|
const resolvedFindings = await fetchFindings(apiClient, {
|
|
@@ -102,7 +84,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
102
84
|
status: "false_positive",
|
|
103
85
|
limit: 20,
|
|
104
86
|
});
|
|
105
|
-
// Build regression patterns: group by category/CWE
|
|
106
87
|
const regressionPatterns = buildRegressionPatterns(resolvedFindings);
|
|
107
88
|
context.regressionCheck = {
|
|
108
89
|
_instruction: "Check code changes against these previously fixed vulnerabilities. Flag if similar patterns appear.",
|
|
@@ -116,7 +97,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
116
97
|
errors.push(`Regression data: ${err instanceof Error ? err.message : "failed"}`);
|
|
117
98
|
}
|
|
118
99
|
}
|
|
119
|
-
// ── 2. Open findings (known vulnerabilities) ──
|
|
120
100
|
if (shouldInclude("regression") && (repo || application_id)) {
|
|
121
101
|
try {
|
|
122
102
|
const minSeverity = SEVERITY_ORDER[severity_threshold] || 2;
|
|
@@ -125,7 +105,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
125
105
|
status: "open",
|
|
126
106
|
limit: 50,
|
|
127
107
|
});
|
|
128
|
-
// Filter by severity threshold
|
|
129
108
|
const filtered = openFindings.filter((f) => (SEVERITY_ORDER[f.severity] || 1) >= minSeverity);
|
|
130
109
|
context.openVulnerabilities = {
|
|
131
110
|
_instruction: "These are KNOWN open vulnerabilities. Check if code changes interact with or worsen these issues.",
|
|
@@ -138,64 +117,76 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
138
117
|
errors.push(`Open findings: ${err instanceof Error ? err.message : "failed"}`);
|
|
139
118
|
}
|
|
140
119
|
}
|
|
141
|
-
|
|
142
|
-
|
|
120
|
+
if ((shouldInclude("controls") || shouldInclude("attack_scenarios")) && threat_model_id) {
|
|
121
|
+
let tm = null;
|
|
143
122
|
try {
|
|
144
|
-
|
|
145
|
-
const controls = tm.securityControls || [];
|
|
146
|
-
const notImplemented = controls.filter((c) => c.status === "not_implemented");
|
|
147
|
-
const partial = controls.filter((c) => c.status === "partial");
|
|
148
|
-
const implemented = controls.filter((c) => c.status === "implemented");
|
|
149
|
-
context.securityControls = {
|
|
150
|
-
_instruction: "Verify that code implements these expected security controls. Flag missing or weak implementations.",
|
|
151
|
-
summary: {
|
|
152
|
-
implemented: implemented.length,
|
|
153
|
-
partial: partial.length,
|
|
154
|
-
notImplemented: notImplemented.length,
|
|
155
|
-
},
|
|
156
|
-
gapControls: [...notImplemented, ...partial].map((c) => ({
|
|
157
|
-
name: c.name,
|
|
158
|
-
type: c.controlType,
|
|
159
|
-
status: c.status,
|
|
160
|
-
description: c.description,
|
|
161
|
-
effectiveness: c.effectivenessRating,
|
|
162
|
-
})),
|
|
163
|
-
implementedControls: implemented.map((c) => ({
|
|
164
|
-
name: c.name,
|
|
165
|
-
type: c.controlType,
|
|
166
|
-
description: c.description,
|
|
167
|
-
})),
|
|
168
|
-
};
|
|
123
|
+
tm = await apiClient.get(`/api/threat-models/${threat_model_id}?include=all`);
|
|
169
124
|
}
|
|
170
125
|
catch (err) {
|
|
171
|
-
errors.push(`
|
|
126
|
+
errors.push(`Threat model fetch: ${err instanceof Error ? err.message : "failed"}`);
|
|
172
127
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
128
|
+
const versions = Array.isArray(tm?.versions) ? tm.versions : [];
|
|
129
|
+
const latestVersion = versions[0] || {};
|
|
130
|
+
if (tm && shouldInclude("controls")) {
|
|
131
|
+
try {
|
|
132
|
+
const controls = Array.isArray(latestVersion.securityControls)
|
|
133
|
+
? latestVersion.securityControls
|
|
134
|
+
: [];
|
|
135
|
+
const notImplemented = controls.filter((c) => c.status === "not_implemented");
|
|
136
|
+
const partial = controls.filter((c) => c.status === "partial");
|
|
137
|
+
const implemented = controls.filter((c) => c.status === "implemented");
|
|
138
|
+
context.securityControls = {
|
|
139
|
+
_instruction: "Verify that code implements these expected security controls. Flag missing or weak implementations.",
|
|
140
|
+
summary: {
|
|
141
|
+
implemented: implemented.length,
|
|
142
|
+
partial: partial.length,
|
|
143
|
+
notImplemented: notImplemented.length,
|
|
144
|
+
},
|
|
145
|
+
gapControls: [...notImplemented, ...partial].map((c) => ({
|
|
146
|
+
name: c.name,
|
|
147
|
+
type: c.controlType,
|
|
148
|
+
status: c.status,
|
|
149
|
+
description: c.description,
|
|
150
|
+
effectiveness: c.effectivenessRating,
|
|
151
|
+
})),
|
|
152
|
+
implementedControls: implemented.map((c) => ({
|
|
153
|
+
name: c.name,
|
|
154
|
+
type: c.controlType,
|
|
155
|
+
description: c.description,
|
|
156
|
+
})),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
catch (err) {
|
|
160
|
+
errors.push(`Security controls: ${err instanceof Error ? err.message : "failed"}`);
|
|
161
|
+
}
|
|
193
162
|
}
|
|
194
|
-
|
|
195
|
-
|
|
163
|
+
if (tm && shouldInclude("attack_scenarios")) {
|
|
164
|
+
try {
|
|
165
|
+
const scenarios = Array.isArray(latestVersion.attackScenarios)
|
|
166
|
+
? latestVersion.attackScenarios
|
|
167
|
+
: [];
|
|
168
|
+
const minSeverity = SEVERITY_ORDER[severity_threshold] || 2;
|
|
169
|
+
const filtered = scenarios.filter((s) => (SEVERITY_ORDER[s.severity] || 1) >= minSeverity);
|
|
170
|
+
context.attackScenarios = {
|
|
171
|
+
_instruction: "Review code for susceptibility to these known attack vectors. Check that mitigations are in place.",
|
|
172
|
+
count: filtered.length,
|
|
173
|
+
scenarios: filtered.map((s) => ({
|
|
174
|
+
displayId: s.displayId,
|
|
175
|
+
title: s.title,
|
|
176
|
+
strideCategory: s.strideCategory,
|
|
177
|
+
severity: s.severity,
|
|
178
|
+
likelihood: s.likelihood,
|
|
179
|
+
riskScore: s.riskScore,
|
|
180
|
+
status: s.status,
|
|
181
|
+
narrative: s.narrative,
|
|
182
|
+
})),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
errors.push(`Attack scenarios: ${err instanceof Error ? err.message : "failed"}`);
|
|
187
|
+
}
|
|
196
188
|
}
|
|
197
189
|
}
|
|
198
|
-
// ── 5. Dependency trust scores ──
|
|
199
190
|
if (shouldInclude("dependencies") && dependency_list && dependency_list.length > 0) {
|
|
200
191
|
const depResults = [];
|
|
201
192
|
const baseUrl = config.apiBaseUrl;
|
|
@@ -238,7 +229,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
238
229
|
dependencies: depResults,
|
|
239
230
|
};
|
|
240
231
|
}
|
|
241
|
-
// ── 6. Campaign findings (if campaign_id provided) ──
|
|
242
232
|
if (campaign_id) {
|
|
243
233
|
try {
|
|
244
234
|
const campaignFindings = await apiClient.get(`/api/campaigns/${campaign_id}/findings?limit=50`);
|
|
@@ -256,7 +246,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
256
246
|
errors.push(`Campaign findings: ${err instanceof Error ? err.message : "failed"}`);
|
|
257
247
|
}
|
|
258
248
|
}
|
|
259
|
-
// ── Build review guidance ──
|
|
260
249
|
context.reviewGuidance = buildReviewGuidance(context);
|
|
261
250
|
if (errors.length > 0) {
|
|
262
251
|
context.warnings = errors;
|
|
@@ -269,7 +258,6 @@ export function createSecurityReviewHandler(apiClient, config) {
|
|
|
269
258
|
};
|
|
270
259
|
};
|
|
271
260
|
}
|
|
272
|
-
// ── Helpers ──
|
|
273
261
|
async function fetchFindings(apiClient, params) {
|
|
274
262
|
const query = new URLSearchParams();
|
|
275
263
|
if (params.repo)
|
|
@@ -303,7 +291,6 @@ function countBySeverity(findings) {
|
|
|
303
291
|
return counts;
|
|
304
292
|
}
|
|
305
293
|
function buildRegressionPatterns(resolvedFindings) {
|
|
306
|
-
// Group by category + CWE to find recurring vulnerability patterns
|
|
307
294
|
const patternMap = new Map();
|
|
308
295
|
for (const f of resolvedFindings) {
|
|
309
296
|
const key = `${f.category || "uncategorized"}::${f.cweId || "no-cwe"}`;
|
|
@@ -375,4 +362,3 @@ function parseRepo(input) {
|
|
|
375
362
|
}
|
|
376
363
|
return null;
|
|
377
364
|
}
|
|
378
|
-
//# sourceMappingURL=security-review.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const THREAT_GET_CAPSULE_NAME = "zivis_threat_get_capsule";
|
|
3
|
+
export declare const THREAT_GET_CAPSULE_DESCRIPTION = "Return the full capsule for a single threat-model pattern.\n\nUse after zivis_threat_list_relevant_capsules has surfaced an id the user wants to dig into. The capsule includes:\n- safe_summary, detect_when, risk_hints, architectural_signals \u2014 for explaining the pattern in threat-model language\n- threats[] with STRIDE categories and remediations \u2014 for grounding the conversation in component/flow/boundary terms\n- repair_contract.allowed / forbidden \u2014 what refactors are safe\n- related_patterns \u2014 adjacent ids in the library\n- model_task_prompt_ref \u2014 pass to zivis_threat_get_inference_prompt to get the prompt the host LLM should run for a deeper check\n\nCapsule data is read from the local pack (~/Library/Caches/zivis/pattern-packs/) with SHA256 integrity verification on every read.";
|
|
4
|
+
export declare const THREAT_GET_CAPSULE_SCHEMA: {
|
|
5
|
+
capsule_id: z.ZodString;
|
|
6
|
+
};
|
|
7
|
+
export declare function createThreatGetCapsuleHandler(): (params: {
|
|
8
|
+
capsule_id: string;
|
|
9
|
+
}) => Promise<{
|
|
10
|
+
content: Array<{
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
}>;
|
|
14
|
+
isError?: boolean;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { loadActivePack, getCapsule, listCapsuleIds } from "../pattern-pack/index.js";
|
|
3
|
+
import { withNextSteps, withNextStepsError } from "../lib/next-steps.js";
|
|
4
|
+
export const THREAT_GET_CAPSULE_NAME = "zivis_threat_get_capsule";
|
|
5
|
+
export const THREAT_GET_CAPSULE_DESCRIPTION = `Return the full capsule for a single threat-model pattern.
|
|
6
|
+
|
|
7
|
+
Use after zivis_threat_list_relevant_capsules has surfaced an id the user wants to dig into. The capsule includes:
|
|
8
|
+
- safe_summary, detect_when, risk_hints, architectural_signals — for explaining the pattern in threat-model language
|
|
9
|
+
- threats[] with STRIDE categories and remediations — for grounding the conversation in component/flow/boundary terms
|
|
10
|
+
- repair_contract.allowed / forbidden — what refactors are safe
|
|
11
|
+
- related_patterns — adjacent ids in the library
|
|
12
|
+
- model_task_prompt_ref — pass to zivis_threat_get_inference_prompt to get the prompt the host LLM should run for a deeper check
|
|
13
|
+
|
|
14
|
+
Capsule data is read from the local pack (~/Library/Caches/zivis/pattern-packs/) with SHA256 integrity verification on every read.`;
|
|
15
|
+
export const THREAT_GET_CAPSULE_SCHEMA = {
|
|
16
|
+
capsule_id: z
|
|
17
|
+
.string()
|
|
18
|
+
.describe("Capsule id, e.g. 'agents.privilege-separation'. Discoverable via zivis_threat_list_relevant_capsules."),
|
|
19
|
+
};
|
|
20
|
+
export function createThreatGetCapsuleHandler() {
|
|
21
|
+
return async (params) => {
|
|
22
|
+
const handle = await loadActivePack();
|
|
23
|
+
let capsule;
|
|
24
|
+
try {
|
|
25
|
+
capsule = await getCapsule(handle, params.capsule_id);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
const ids = await listCapsuleIds(handle);
|
|
29
|
+
return withNextStepsError(`Capsule '${params.capsule_id}' not found in pack ${handle.manifest.pack_id}@${handle.manifest.version}. ${err.message}`, [
|
|
30
|
+
{
|
|
31
|
+
id: "list_relevant_capsules_first",
|
|
32
|
+
label: "Find relevant capsules for the current repo first",
|
|
33
|
+
tool: "zivis_threat_list_relevant_capsules",
|
|
34
|
+
why: "Returns ids you can pass back into zivis_threat_get_capsule.",
|
|
35
|
+
},
|
|
36
|
+
], `Available capsule ids in this pack: ${ids.join(", ")}`);
|
|
37
|
+
}
|
|
38
|
+
return withNextSteps({
|
|
39
|
+
pack: { id: handle.manifest.pack_id, version: handle.manifest.version },
|
|
40
|
+
capsule,
|
|
41
|
+
}, capsule.model_task_prompt_ref
|
|
42
|
+
? [
|
|
43
|
+
{
|
|
44
|
+
id: "get_inference_prompt",
|
|
45
|
+
label: "Get the inference prompt template the host LLM should run",
|
|
46
|
+
tool: "zivis_threat_get_inference_prompt",
|
|
47
|
+
args_hint: { capsule_id: capsule.id },
|
|
48
|
+
why: "Inference prompt + expected_output_schema together form the prompt bundle the IDE LLM executes.",
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
: [], `Capsule ${capsule.id}@${capsule.version} (${capsule.lifecycle}, ${capsule.sensitivity_level ?? "unspecified-tier"}). Threats: ${(capsule.threats?.length ?? 0)}.`);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const THREAT_GET_INFERENCE_PROMPT_NAME = "zivis_threat_get_inference_prompt";
|
|
3
|
+
export declare const THREAT_GET_INFERENCE_PROMPT_DESCRIPTION = "Return the prompt bundle for the host LLM to run local inference for a capsule.\n\nZIVIS doesn't run an LLM itself \u2014 the host (Cursor, Claude Code, etc.) does. This tool returns the prompt template + structured output schema + ambient capsule context so the host model can run the inference and produce JSON the inferred lane accepts.\n\nUse this when:\n- After zivis_threat_get_capsule, the user wants the host LLM to actually evaluate whether the pattern is present in the code\n- The user says \"go check if my code does this\" / \"is this pattern actually in my repo\"\n- The matcher emits an INFER candidate that needs host-LLM evaluation\n\nThe bundle includes:\n- prompt: the markdown inference prompt\n- expected_output_schema: JSON Schema for the structured response\n- safe_summary: ambient capsule context\n- minimum_context_required: hint to the host for how much code to attach\n- evidence_focus: spans the deterministic strategies already flagged\n\nThe host LLM is expected to gather the indicated code spans, fill in the prompt, return JSON matching the schema. That output then flows back into the inferred lane.";
|
|
4
|
+
export declare const THREAT_GET_INFERENCE_PROMPT_SCHEMA: {
|
|
5
|
+
capsule_id: z.ZodString;
|
|
6
|
+
};
|
|
7
|
+
export declare function createThreatGetInferencePromptHandler(): (params: {
|
|
8
|
+
capsule_id: string;
|
|
9
|
+
}) => Promise<{
|
|
10
|
+
content: Array<{
|
|
11
|
+
type: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
}>;
|
|
14
|
+
isError?: boolean;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { loadActivePack, getCapsule, getInferencePrompt } from "../pattern-pack/index.js";
|
|
3
|
+
import { withNextSteps, withNextStepsError } from "../lib/next-steps.js";
|
|
4
|
+
export const THREAT_GET_INFERENCE_PROMPT_NAME = "zivis_threat_get_inference_prompt";
|
|
5
|
+
export const THREAT_GET_INFERENCE_PROMPT_DESCRIPTION = `Return the prompt bundle for the host LLM to run local inference for a capsule.
|
|
6
|
+
|
|
7
|
+
ZIVIS doesn't run an LLM itself — the host (Cursor, Claude Code, etc.) does. This tool returns the prompt template + structured output schema + ambient capsule context so the host model can run the inference and produce JSON the inferred lane accepts.
|
|
8
|
+
|
|
9
|
+
Use this when:
|
|
10
|
+
- After zivis_threat_get_capsule, the user wants the host LLM to actually evaluate whether the pattern is present in the code
|
|
11
|
+
- The user says "go check if my code does this" / "is this pattern actually in my repo"
|
|
12
|
+
- The matcher emits an INFER candidate that needs host-LLM evaluation
|
|
13
|
+
|
|
14
|
+
The bundle includes:
|
|
15
|
+
- prompt: the markdown inference prompt
|
|
16
|
+
- expected_output_schema: JSON Schema for the structured response
|
|
17
|
+
- safe_summary: ambient capsule context
|
|
18
|
+
- minimum_context_required: hint to the host for how much code to attach
|
|
19
|
+
- evidence_focus: spans the deterministic strategies already flagged
|
|
20
|
+
|
|
21
|
+
The host LLM is expected to gather the indicated code spans, fill in the prompt, return JSON matching the schema. That output then flows back into the inferred lane.`;
|
|
22
|
+
export const THREAT_GET_INFERENCE_PROMPT_SCHEMA = {
|
|
23
|
+
capsule_id: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe("Capsule id whose INFER prompt should be returned (e.g. 'agents.privilege-separation')."),
|
|
26
|
+
};
|
|
27
|
+
export function createThreatGetInferencePromptHandler() {
|
|
28
|
+
return async (params) => {
|
|
29
|
+
const handle = await loadActivePack();
|
|
30
|
+
let capsule;
|
|
31
|
+
try {
|
|
32
|
+
capsule = await getCapsule(handle, params.capsule_id);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
return withNextStepsError(`Capsule '${params.capsule_id}' not found. ${err.message}`, [
|
|
36
|
+
{
|
|
37
|
+
id: "list_relevant_capsules_first",
|
|
38
|
+
label: "List relevant capsules for the current repo first",
|
|
39
|
+
tool: "zivis_threat_list_relevant_capsules",
|
|
40
|
+
why: "Returns ids you can pass back here.",
|
|
41
|
+
},
|
|
42
|
+
], "Capsule not found — list first to discover ids.");
|
|
43
|
+
}
|
|
44
|
+
if (!capsule.model_task_prompt_ref) {
|
|
45
|
+
return withNextStepsError(`Capsule '${capsule.id}' has no inference prompt defined (model_task_prompt_ref missing). This capsule is deterministic-only.`, [
|
|
46
|
+
{
|
|
47
|
+
id: "get_capsule",
|
|
48
|
+
label: "Read the full capsule to see its deterministic strategies",
|
|
49
|
+
tool: "zivis_threat_get_capsule",
|
|
50
|
+
args_hint: { capsule_id: capsule.id },
|
|
51
|
+
why: "Some capsules have no INFER strategy — only AST/GRAPH/META/etc. that the matcher runs locally.",
|
|
52
|
+
},
|
|
53
|
+
], "No inference prompt for this capsule (deterministic only).");
|
|
54
|
+
}
|
|
55
|
+
const promptText = await getInferencePrompt(handle, capsule.model_task_prompt_ref);
|
|
56
|
+
return withNextSteps({
|
|
57
|
+
pack: { id: handle.manifest.pack_id, version: handle.manifest.version },
|
|
58
|
+
capsule_id: capsule.id,
|
|
59
|
+
prompt: promptText,
|
|
60
|
+
expected_output_schema: capsule.expected_output_schema ?? null,
|
|
61
|
+
safe_summary: capsule.safe_summary ?? null,
|
|
62
|
+
minimum_context_required: capsule.minimum_context_required ?? null,
|
|
63
|
+
host_instructions: "Gather the code spans indicated by minimum_context_required.symbols (or any deterministic match spans the matcher already flagged), attach them to the prompt above, run inference with your model, and return JSON matching expected_output_schema. The structured output flows back into the inferred lane.",
|
|
64
|
+
}, [
|
|
65
|
+
{
|
|
66
|
+
id: "host_runs_inference",
|
|
67
|
+
label: "Host LLM runs inference now (no further tool call)",
|
|
68
|
+
tool: "zivis_threat_get_inference_prompt",
|
|
69
|
+
why: "MCP cannot invoke your model. The host orchestrates the inference using this bundle.",
|
|
70
|
+
},
|
|
71
|
+
], `Prompt bundle ready for host-side inference of ${capsule.id}.`);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const THREAT_LIST_RELEVANT_CAPSULES_NAME = "zivis_threat_list_relevant_capsules";
|
|
3
|
+
export declare const THREAT_LIST_RELEVANT_CAPSULES_DESCRIPTION = "List threat-model patterns relevant to the user's current repo.\n\nUse this when the user asks any of:\n- \"what should I be worried about in this code\"\n- \"what threats apply to my app\"\n- \"are there known patterns that match my architecture\"\n- \"what's in my threat model\"\n- mid-conversation when the user describes a feature that touches deps the threat library covers\n\nReads the latest local repo graph artifact (produced by 'zivis inspect') from the user cache, runs every capsule's relevance_filter against it, and returns the subset whose filter passes \u2014 together with each capsule's safe_summary so you can frame the conversation in threat-model terms (component, flow, trust boundary, scenario).\n\nIf no graph artifact exists yet for this repo, the tool returns a next-step pointing to 'zivis inspect'. Always speak in threat-model vocabulary even when the user doesn't.";
|
|
4
|
+
export declare const THREAT_LIST_RELEVANT_CAPSULES_SCHEMA: {
|
|
5
|
+
artifact_path: z.ZodOptional<z.ZodString>;
|
|
6
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
7
|
+
};
|
|
8
|
+
export declare function createThreatListRelevantCapsulesHandler(): (params: {
|
|
9
|
+
artifact_path?: string;
|
|
10
|
+
cwd?: string;
|
|
11
|
+
}) => Promise<{
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
isError?: boolean;
|
|
17
|
+
}>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as fs from "node:fs/promises";
|
|
3
|
+
import * as fssync from "node:fs";
|
|
4
|
+
import * as os from "node:os";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { loadActivePack, findRelevantCapsules, } from "../pattern-pack/index.js";
|
|
7
|
+
import { withNextSteps, withNextStepsError } from "../lib/next-steps.js";
|
|
8
|
+
export const THREAT_LIST_RELEVANT_CAPSULES_NAME = "zivis_threat_list_relevant_capsules";
|
|
9
|
+
export const THREAT_LIST_RELEVANT_CAPSULES_DESCRIPTION = `List threat-model patterns relevant to the user's current repo.
|
|
10
|
+
|
|
11
|
+
Use this when the user asks any of:
|
|
12
|
+
- "what should I be worried about in this code"
|
|
13
|
+
- "what threats apply to my app"
|
|
14
|
+
- "are there known patterns that match my architecture"
|
|
15
|
+
- "what's in my threat model"
|
|
16
|
+
- mid-conversation when the user describes a feature that touches deps the threat library covers
|
|
17
|
+
|
|
18
|
+
Reads the latest local repo graph artifact (produced by 'zivis inspect') from the user cache, runs every capsule's relevance_filter against it, and returns the subset whose filter passes — together with each capsule's safe_summary so you can frame the conversation in threat-model terms (component, flow, trust boundary, scenario).
|
|
19
|
+
|
|
20
|
+
If no graph artifact exists yet for this repo, the tool returns a next-step pointing to 'zivis inspect'. Always speak in threat-model vocabulary even when the user doesn't.`;
|
|
21
|
+
export const THREAT_LIST_RELEVANT_CAPSULES_SCHEMA = {
|
|
22
|
+
artifact_path: z
|
|
23
|
+
.string()
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Optional path to a specific RepoGraphArtifactV1 JSON. If omitted, the tool finds the most recent artifact in ~/Library/Caches/zivis/repos/<repo-id>/inspect/runs/ for the repo at cwd."),
|
|
26
|
+
cwd: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Working directory whose repo cache to search (defaults to server cwd)."),
|
|
30
|
+
};
|
|
31
|
+
export function createThreatListRelevantCapsulesHandler() {
|
|
32
|
+
return async (params) => {
|
|
33
|
+
const cwd = params.cwd ?? process.cwd();
|
|
34
|
+
let artifact;
|
|
35
|
+
let artifactPath;
|
|
36
|
+
try {
|
|
37
|
+
const resolved = await resolveArtifactPath(params.artifact_path, cwd);
|
|
38
|
+
artifactPath = resolved;
|
|
39
|
+
const raw = await fs.readFile(resolved, "utf8");
|
|
40
|
+
artifact = JSON.parse(raw);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
return withNextStepsError(`No repo graph artifact found. ${err.message}`, [
|
|
44
|
+
{
|
|
45
|
+
id: "run_zivis_inspect",
|
|
46
|
+
label: "Run `zivis inspect` to build the local repo graph",
|
|
47
|
+
tool: "zivis_inspect",
|
|
48
|
+
why: "The relevance evaluation reads from the latest inspect run in the user cache.",
|
|
49
|
+
},
|
|
50
|
+
], "Run `zivis inspect` first; this tool reads from its output.");
|
|
51
|
+
}
|
|
52
|
+
const handle = await loadActivePack();
|
|
53
|
+
const relevant = await findRelevantCapsules(handle, artifact);
|
|
54
|
+
const summaries = relevant.map((cap) => ({
|
|
55
|
+
id: cap.id,
|
|
56
|
+
title: cap.title,
|
|
57
|
+
category: cap.category,
|
|
58
|
+
safe_summary: cap.safe_summary,
|
|
59
|
+
applicable_languages: cap.applicable_languages,
|
|
60
|
+
matched_on: matchedTerms(cap, artifact),
|
|
61
|
+
}));
|
|
62
|
+
return withNextSteps({
|
|
63
|
+
artifact_path: artifactPath,
|
|
64
|
+
pack: { id: handle.manifest.pack_id, version: handle.manifest.version },
|
|
65
|
+
languages_in_scope: artifact.scope.languages ?? [],
|
|
66
|
+
relevant_count: summaries.length,
|
|
67
|
+
relevant_capsules: summaries,
|
|
68
|
+
}, summaries.length > 0
|
|
69
|
+
? [
|
|
70
|
+
{
|
|
71
|
+
id: "get_capsule_details",
|
|
72
|
+
label: "Pull the full capsule for any item the user wants to investigate",
|
|
73
|
+
tool: "zivis_threat_get_capsule",
|
|
74
|
+
why: "The full capsule has threats (with STRIDE), risk_hints, repair_contract, related_patterns.",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: "get_inference_prompt",
|
|
78
|
+
label: "Get the inference prompt for the host LLM to run a deeper check",
|
|
79
|
+
tool: "zivis_threat_get_inference_prompt",
|
|
80
|
+
why: "INFER strategies in each capsule reference a prompt template the user's IDE model executes.",
|
|
81
|
+
},
|
|
82
|
+
]
|
|
83
|
+
: [
|
|
84
|
+
{
|
|
85
|
+
id: "no_relevant_patterns",
|
|
86
|
+
label: "No public-pack patterns matched this repo",
|
|
87
|
+
tool: "zivis_threat_list_relevant_capsules",
|
|
88
|
+
why: "This is normal for repos without agentic / RAG / self-consistency / multi-tenant patterns. Proprietary patterns may still apply server-side.",
|
|
89
|
+
},
|
|
90
|
+
], summaries.length > 0
|
|
91
|
+
? `Found ${summaries.length} relevant capsule(s) in the threat library.`
|
|
92
|
+
: "No public-pack capsules matched this repo. Proprietary patterns evaluated server-side may still apply.");
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function userCacheRoot() {
|
|
96
|
+
const home = os.homedir();
|
|
97
|
+
if (process.platform === "darwin") {
|
|
98
|
+
return path.join(home, "Library", "Caches", "zivis");
|
|
99
|
+
}
|
|
100
|
+
if (process.platform === "win32") {
|
|
101
|
+
const localAppData = process.env.LOCALAPPDATA ?? path.join(home, "AppData", "Local");
|
|
102
|
+
return path.join(localAppData, "zivis", "Cache");
|
|
103
|
+
}
|
|
104
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
105
|
+
return path.join(xdg ?? path.join(home, ".cache"), "zivis");
|
|
106
|
+
}
|
|
107
|
+
async function resolveArtifactPath(explicit, cwd) {
|
|
108
|
+
if (explicit) {
|
|
109
|
+
if (!fssync.existsSync(explicit)) {
|
|
110
|
+
throw new Error(`Artifact path does not exist: ${explicit}`);
|
|
111
|
+
}
|
|
112
|
+
return explicit;
|
|
113
|
+
}
|
|
114
|
+
const reposRoot = path.join(userCacheRoot(), "repos");
|
|
115
|
+
if (!fssync.existsSync(reposRoot)) {
|
|
116
|
+
throw new Error(`No inspect cache found at ${reposRoot}. Run \`zivis inspect\` from the repo to populate it.`);
|
|
117
|
+
}
|
|
118
|
+
const candidates = [];
|
|
119
|
+
for (const repo of await fs.readdir(reposRoot, { withFileTypes: true })) {
|
|
120
|
+
if (!repo.isDirectory())
|
|
121
|
+
continue;
|
|
122
|
+
const runs = path.join(reposRoot, repo.name, "inspect", "runs");
|
|
123
|
+
if (!fssync.existsSync(runs))
|
|
124
|
+
continue;
|
|
125
|
+
for (const entry of await fs.readdir(runs)) {
|
|
126
|
+
if (!entry.endsWith(".json"))
|
|
127
|
+
continue;
|
|
128
|
+
const full = path.join(runs, entry);
|
|
129
|
+
const stat = await fs.stat(full);
|
|
130
|
+
candidates.push({ file: full, mtime: stat.mtimeMs });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (candidates.length === 0) {
|
|
134
|
+
throw new Error(`No inspect runs found under ${reposRoot}. Run \`zivis inspect\` from the repo to produce one.`);
|
|
135
|
+
}
|
|
136
|
+
candidates.sort((a, b) => b.mtime - a.mtime);
|
|
137
|
+
return candidates[0].file;
|
|
138
|
+
}
|
|
139
|
+
function matchedTerms(cap, artifact) {
|
|
140
|
+
const matched = [];
|
|
141
|
+
const pkgs = new Set();
|
|
142
|
+
for (const node of artifact.nodes) {
|
|
143
|
+
if (node.type === "external_dependency" && node.attributes?.package) {
|
|
144
|
+
pkgs.add(node.attributes.package);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const langs = new Set(artifact.scope.languages ?? []);
|
|
148
|
+
const f = cap.relevance_filter;
|
|
149
|
+
if (!f)
|
|
150
|
+
return ["always-applicable (no relevance_filter set)"];
|
|
151
|
+
for (const term of [...(f.any_of ?? []), ...(f.all_of ?? [])]) {
|
|
152
|
+
if (term.dependency && pkgs.has(term.dependency))
|
|
153
|
+
matched.push(`dep:${term.dependency}`);
|
|
154
|
+
if (term.language && langs.has(term.language))
|
|
155
|
+
matched.push(`language:${term.language}`);
|
|
156
|
+
}
|
|
157
|
+
return matched.length > 0 ? matched : ["language match only"];
|
|
158
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const THREAT_RUN_MATCHER_NAME = "zivis_threat_run_matcher";
|
|
3
|
+
export declare const THREAT_RUN_MATCHER_DESCRIPTION = "Run the local pattern matcher against the latest repo graph artifact and emit normalized threat findings.\n\nUse this when:\n- The user asks ZIVIS to actually evaluate (not just list) which patterns fire on their code\n- After 'zivis inspect' has produced an artifact and the user wants concrete findings\n- \"find security issues in my code\", \"check this against the threat library\", \"what's actually wrong here\"\n\nPhase 3 v1 evaluates AST strategies for real (via @ast-grep/napi for TS/JS, plus Python and Go via dynamic language packs). INFER strategies emit a candidate the host LLM is expected to pick up via zivis_threat_get_inference_prompt and run with its own model. GRAPH / META / DEP / CONFIG strategies are surfaced as fired_strategies with match_count: 0 \u2014 visible-but-not-evaluated for now.\n\nLane assignment per finding:\n- trusted: count of fired deterministic strategies meets the capsule's required_evidence_count\n- inferred: at least one strategy fired but the bar wasn't met (host should run inference to confirm)\n\nThe output is a normalized findings array with pattern_id, lane, confidence, evidence spans, and (for inferred-lane findings) an inference_candidate the host LLM uses to run deeper analysis.";
|
|
4
|
+
export declare const THREAT_RUN_MATCHER_SCHEMA: {
|
|
5
|
+
artifact_path: z.ZodOptional<z.ZodString>;
|
|
6
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
7
|
+
};
|
|
8
|
+
export declare function createThreatRunMatcherHandler(): (params: {
|
|
9
|
+
artifact_path?: string;
|
|
10
|
+
cwd?: string;
|
|
11
|
+
}) => Promise<{
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
isError?: boolean;
|
|
17
|
+
}>;
|