@zivis/mcp 0.1.19 → 0.2.5
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/dist/lib/harness-bootstrap.d.ts +9 -0
- package/dist/lib/harness-bootstrap.js +78 -0
- package/dist/matcher/index.js +1 -1
- package/dist/matcher/inference-candidates.js +1 -1
- package/dist/pattern-packs/zivis-public-0.2.0/manifest.json +1 -1
- package/dist/prompts/getting-started.js +26 -2
- package/dist/server.js +24 -143
- package/dist/tools/application.d.ts +53 -0
- package/dist/tools/application.js +232 -0
- package/dist/tools/artifacts.d.ts +21 -57
- package/dist/tools/artifacts.js +116 -150
- package/dist/tools/devx-run.d.ts +15 -37
- package/dist/tools/devx-run.js +66 -77
- package/dist/tools/diagram.d.ts +55 -0
- package/dist/tools/diagram.js +209 -0
- package/dist/tools/document.d.ts +48 -0
- package/dist/tools/document.js +137 -0
- package/dist/tools/finding.d.ts +133 -0
- package/dist/tools/finding.js +211 -0
- package/dist/tools/get-started.d.ts +1 -1
- package/dist/tools/get-started.js +93 -33
- package/dist/tools/security-memory.d.ts +21 -55
- package/dist/tools/security-memory.js +93 -138
- package/dist/tools/signal.d.ts +50 -0
- package/dist/tools/signal.js +139 -0
- package/dist/tools/threat-library.d.ts +27 -0
- package/dist/tools/threat-library.js +266 -0
- package/package.json +1 -1
- package/dist/tools/create-diagram.d.ts +0 -39
- package/dist/tools/create-diagram.js +0 -74
- package/dist/tools/create-document.d.ts +0 -23
- package/dist/tools/create-document.js +0 -47
- package/dist/tools/create-finding.d.ts +0 -85
- package/dist/tools/create-finding.js +0 -136
- package/dist/tools/delete-finding.d.ts +0 -19
- package/dist/tools/delete-finding.js +0 -36
- package/dist/tools/discover-local-infra.d.ts +0 -14
- package/dist/tools/discover-local-infra.js +0 -686
- package/dist/tools/explain-signal-for-diff.d.ts +0 -34
- package/dist/tools/explain-signal-for-diff.js +0 -75
- package/dist/tools/get-application-overview.d.ts +0 -22
- package/dist/tools/get-application-overview.js +0 -137
- package/dist/tools/get-application.d.ts +0 -22
- package/dist/tools/get-application.js +0 -77
- package/dist/tools/get-diagram.d.ts +0 -22
- package/dist/tools/get-diagram.js +0 -49
- package/dist/tools/get-document.d.ts +0 -17
- package/dist/tools/get-document.js +0 -37
- package/dist/tools/get-signal.d.ts +0 -24
- package/dist/tools/get-signal.js +0 -75
- package/dist/tools/import-openapi-endpoints.d.ts +0 -28
- package/dist/tools/import-openapi-endpoints.js +0 -87
- package/dist/tools/inspect.d.ts +0 -21
- package/dist/tools/inspect.js +0 -222
- package/dist/tools/list-applications.d.ts +0 -29
- package/dist/tools/list-applications.js +0 -68
- package/dist/tools/list-diagrams.d.ts +0 -37
- package/dist/tools/list-diagrams.js +0 -74
- package/dist/tools/list-documents.d.ts +0 -19
- package/dist/tools/list-documents.js +0 -44
- package/dist/tools/list-endpoints.d.ts +0 -42
- package/dist/tools/list-endpoints.js +0 -92
- package/dist/tools/list-signals.d.ts +0 -37
- package/dist/tools/list-signals.js +0 -83
- package/dist/tools/manage-application.d.ts +0 -64
- package/dist/tools/manage-application.js +0 -129
- package/dist/tools/manage-diagram.d.ts +0 -41
- package/dist/tools/manage-diagram.js +0 -91
- package/dist/tools/manage-endpoint-lifecycle.d.ts +0 -80
- package/dist/tools/manage-endpoint-lifecycle.js +0 -180
- package/dist/tools/security-review.d.ts +0 -40
- package/dist/tools/security-review.js +0 -199
- package/dist/tools/threat-get-capsule.d.ts +0 -15
- package/dist/tools/threat-get-capsule.js +0 -53
- package/dist/tools/threat-get-inference-prompt.d.ts +0 -15
- package/dist/tools/threat-get-inference-prompt.js +0 -73
- package/dist/tools/threat-list-relevant-capsules.d.ts +0 -17
- package/dist/tools/threat-list-relevant-capsules.js +0 -158
- package/dist/tools/threat-run-matcher.d.ts +0 -17
- package/dist/tools/threat-run-matcher.js +0 -145
- package/dist/tools/update-document.d.ts +0 -23
- package/dist/tools/update-document.js +0 -57
- package/dist/tools/update-endpoint.d.ts +0 -60
- package/dist/tools/update-endpoint.js +0 -138
- package/dist/tools/update-finding.d.ts +0 -61
- package/dist/tools/update-finding.js +0 -80
- package/dist/tools/update-mermaid-source.d.ts +0 -21
- package/dist/tools/update-mermaid-source.js +0 -60
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { requireApplicationId } from "../resolve-application-id.js";
|
|
3
|
-
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
-
export const MANAGE_ENDPOINT_LIFECYCLE_NAME = "zivis_manage_endpoint_lifecycle";
|
|
5
|
-
export const MANAGE_ENDPOINT_LIFECYCLE_DESCRIPTION = `Manage endpoint lifecycle for an application.
|
|
6
|
-
|
|
7
|
-
Actions:
|
|
8
|
-
- create: create a single endpoint
|
|
9
|
-
- update: patch an endpoint
|
|
10
|
-
- delete: delete a single endpoint
|
|
11
|
-
- bulk_delete: delete endpoints by source (e.g., openapi)
|
|
12
|
-
- import_openapi: import endpoints from an OpenAPI spec`;
|
|
13
|
-
export const MANAGE_ENDPOINT_LIFECYCLE_SCHEMA = {
|
|
14
|
-
application_id: z
|
|
15
|
-
.string()
|
|
16
|
-
.optional()
|
|
17
|
-
.describe("Application UUID. If omitted, uses applicationId from .zivis/project.json when set."),
|
|
18
|
-
action: z
|
|
19
|
-
.enum(["create", "update", "delete", "bulk_delete", "import_openapi"])
|
|
20
|
-
.describe("Endpoint lifecycle action"),
|
|
21
|
-
endpoint_id: z.string().optional().describe("Required for update/delete actions"),
|
|
22
|
-
path: z.string().optional().describe("Endpoint path, e.g. /api/chat"),
|
|
23
|
-
method: z
|
|
24
|
-
.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"])
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("HTTP method"),
|
|
27
|
-
summary: z.string().optional().describe("Endpoint summary"),
|
|
28
|
-
description: z.string().optional().describe("Endpoint description"),
|
|
29
|
-
tags: z.array(z.string()).optional().describe("Endpoint tags"),
|
|
30
|
-
auth_required: z.boolean().optional().describe("Whether auth is required"),
|
|
31
|
-
deprecated: z.boolean().optional().describe("Whether endpoint is deprecated"),
|
|
32
|
-
endpoint_type: z
|
|
33
|
-
.enum(["api", "chat", "sse", "validation", "web"])
|
|
34
|
-
.optional()
|
|
35
|
-
.describe("Endpoint type"),
|
|
36
|
-
request_template: z
|
|
37
|
-
.string()
|
|
38
|
-
.optional()
|
|
39
|
-
.describe("AI request template, usually includes {{message}}"),
|
|
40
|
-
response_path: z
|
|
41
|
-
.string()
|
|
42
|
-
.optional()
|
|
43
|
-
.describe("JSON path to pull response text"),
|
|
44
|
-
streaming_enabled: z.boolean().optional().describe("Whether streaming is enabled"),
|
|
45
|
-
source: z
|
|
46
|
-
.enum(["openapi", "manual", "discovery"])
|
|
47
|
-
.optional()
|
|
48
|
-
.describe("Source filter for bulk_delete"),
|
|
49
|
-
spec_url: z.string().optional().describe("OpenAPI spec URL for import_openapi"),
|
|
50
|
-
spec_content: z.string().optional().describe("Raw OpenAPI spec content"),
|
|
51
|
-
replace_existing: z
|
|
52
|
-
.boolean()
|
|
53
|
-
.optional()
|
|
54
|
-
.describe("When import_openapi, remove previous openapi endpoints first"),
|
|
55
|
-
};
|
|
56
|
-
export function createManageEndpointLifecycleHandler(apiClient) {
|
|
57
|
-
return async (params) => {
|
|
58
|
-
const req = requireApplicationId(params.application_id);
|
|
59
|
-
if (!req.ok) {
|
|
60
|
-
return {
|
|
61
|
-
content: [{ type: "text", text: `Error: ${req.message}` }],
|
|
62
|
-
isError: true,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
const applicationId = req.id;
|
|
66
|
-
const action = params.action;
|
|
67
|
-
try {
|
|
68
|
-
let data;
|
|
69
|
-
if (action === "create") {
|
|
70
|
-
if (!params.path || !params.method) {
|
|
71
|
-
return {
|
|
72
|
-
content: [
|
|
73
|
-
{
|
|
74
|
-
type: "text",
|
|
75
|
-
text: "Error: create requires path and method",
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
isError: true,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
data = await apiClient.post(`/api/rt/applications/${applicationId}/endpoints`, {
|
|
82
|
-
path: params.path,
|
|
83
|
-
method: params.method,
|
|
84
|
-
summary: params.summary,
|
|
85
|
-
description: params.description,
|
|
86
|
-
tags: params.tags,
|
|
87
|
-
authRequired: params.auth_required,
|
|
88
|
-
deprecated: params.deprecated,
|
|
89
|
-
endpointType: params.endpoint_type,
|
|
90
|
-
requestTemplate: params.request_template,
|
|
91
|
-
responsePath: params.response_path,
|
|
92
|
-
streamingEnabled: params.streaming_enabled,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else if (action === "update") {
|
|
96
|
-
if (!params.endpoint_id) {
|
|
97
|
-
return {
|
|
98
|
-
content: [
|
|
99
|
-
{ type: "text", text: "Error: endpoint_id is required for update" },
|
|
100
|
-
],
|
|
101
|
-
isError: true,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
const body = {};
|
|
105
|
-
if (params.path !== undefined)
|
|
106
|
-
body.path = params.path;
|
|
107
|
-
if (params.method !== undefined)
|
|
108
|
-
body.method = params.method;
|
|
109
|
-
if (params.summary !== undefined)
|
|
110
|
-
body.summary = params.summary;
|
|
111
|
-
if (params.description !== undefined)
|
|
112
|
-
body.description = params.description;
|
|
113
|
-
if (params.tags !== undefined)
|
|
114
|
-
body.tags = params.tags;
|
|
115
|
-
if (params.auth_required !== undefined)
|
|
116
|
-
body.authRequired = params.auth_required;
|
|
117
|
-
if (params.deprecated !== undefined)
|
|
118
|
-
body.deprecated = params.deprecated;
|
|
119
|
-
if (params.endpoint_type !== undefined)
|
|
120
|
-
body.endpointType = params.endpoint_type;
|
|
121
|
-
if (params.request_template !== undefined)
|
|
122
|
-
body.requestTemplate = params.request_template;
|
|
123
|
-
if (params.response_path !== undefined)
|
|
124
|
-
body.responsePath = params.response_path;
|
|
125
|
-
if (params.streaming_enabled !== undefined) {
|
|
126
|
-
body.streamingEnabled = params.streaming_enabled;
|
|
127
|
-
}
|
|
128
|
-
data = await apiClient.patch(`/api/rt/applications/${applicationId}/endpoints/${params.endpoint_id}`, body);
|
|
129
|
-
}
|
|
130
|
-
else if (action === "delete") {
|
|
131
|
-
if (!params.endpoint_id) {
|
|
132
|
-
return {
|
|
133
|
-
content: [
|
|
134
|
-
{ type: "text", text: "Error: endpoint_id is required for delete" },
|
|
135
|
-
],
|
|
136
|
-
isError: true,
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
data = await apiClient.del(`/api/rt/applications/${applicationId}/endpoints/${params.endpoint_id}`);
|
|
140
|
-
}
|
|
141
|
-
else if (action === "bulk_delete") {
|
|
142
|
-
if (!params.source) {
|
|
143
|
-
return {
|
|
144
|
-
content: [
|
|
145
|
-
{
|
|
146
|
-
type: "text",
|
|
147
|
-
text: "Error: source is required for bulk_delete (openapi/manual/discovery)",
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
isError: true,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
data = await apiClient.del(`/api/rt/applications/${applicationId}/endpoints?source=${encodeURIComponent(params.source)}`);
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
data = await apiClient.post(`/api/rt/applications/${applicationId}/endpoints/import-openapi`, {
|
|
157
|
-
specUrl: params.spec_url,
|
|
158
|
-
specContent: params.spec_content,
|
|
159
|
-
replaceExisting: params.replace_existing ?? false,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
const sanitized = sanitizeResponse({
|
|
163
|
-
action,
|
|
164
|
-
application_id: applicationId,
|
|
165
|
-
endpoint_id: params.endpoint_id,
|
|
166
|
-
result: data,
|
|
167
|
-
});
|
|
168
|
-
return {
|
|
169
|
-
content: [{ type: "text", text: JSON.stringify(sanitized, null, 2) }],
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
catch (err) {
|
|
173
|
-
const message = err instanceof Error ? err.message : "Failed to manage endpoint lifecycle";
|
|
174
|
-
return {
|
|
175
|
-
content: [{ type: "text", text: `Error: ${message}` }],
|
|
176
|
-
isError: true,
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { ApiClient } from "../api-client.js";
|
|
3
|
-
import type { ZivisConfig } from "../types.js";
|
|
4
|
-
export declare const SECURITY_REVIEW_NAME = "zivis_security_review";
|
|
5
|
-
export declare const SECURITY_REVIEW_DESCRIPTION = "Gather ZIVIS security intelligence for an AI-powered code review.\n\nPulls historical findings and open vulnerabilities to give you comprehensive security context. Use this BEFORE reviewing code to understand:\n\n1. **Regression risks** \u2014 Previously fixed vulnerabilities that could be reintroduced\n2. **Known vulnerabilities** \u2014 Open findings that may be relevant to the code being reviewed\n\nReturns structured security context that you should reference during code review. Focus on:\n- Code that touches areas where historical findings were fixed (regression check)\n\nFor dependency risk, use `zivis test dependencies` instead \u2014 this tool no longer checks dependencies.\n\nProvide at least one of: repo or application_id.";
|
|
6
|
-
export declare const SECURITY_REVIEW_SCHEMA: {
|
|
7
|
-
repo: z.ZodOptional<z.ZodString>;
|
|
8
|
-
application_id: z.ZodOptional<z.ZodString>;
|
|
9
|
-
focus_areas: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
10
|
-
regression: "regression";
|
|
11
|
-
all: "all";
|
|
12
|
-
}>>>;
|
|
13
|
-
severity_threshold: z.ZodOptional<z.ZodEnum<{
|
|
14
|
-
critical: "critical";
|
|
15
|
-
high: "high";
|
|
16
|
-
medium: "medium";
|
|
17
|
-
low: "low";
|
|
18
|
-
info: "info";
|
|
19
|
-
}>>;
|
|
20
|
-
include_resolved: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
-
};
|
|
22
|
-
export declare function createSecurityReviewHandler(apiClient: ApiClient, _config: ZivisConfig): (params: {
|
|
23
|
-
repo?: string;
|
|
24
|
-
application_id?: string;
|
|
25
|
-
focus_areas?: string[];
|
|
26
|
-
severity_threshold?: string;
|
|
27
|
-
include_resolved?: boolean;
|
|
28
|
-
}) => Promise<{
|
|
29
|
-
content: {
|
|
30
|
-
type: "text";
|
|
31
|
-
text: string;
|
|
32
|
-
}[];
|
|
33
|
-
isError: boolean;
|
|
34
|
-
} | {
|
|
35
|
-
content: {
|
|
36
|
-
type: "text";
|
|
37
|
-
text: string;
|
|
38
|
-
}[];
|
|
39
|
-
isError?: undefined;
|
|
40
|
-
}>;
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { resolveApplicationId } from "../resolve-application-id.js";
|
|
3
|
-
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
-
export const SECURITY_REVIEW_NAME = "zivis_security_review";
|
|
5
|
-
export const SECURITY_REVIEW_DESCRIPTION = `Gather ZIVIS security intelligence for an AI-powered code review.
|
|
6
|
-
|
|
7
|
-
Pulls historical findings and open vulnerabilities to give you comprehensive security context. Use this BEFORE reviewing code to understand:
|
|
8
|
-
|
|
9
|
-
1. **Regression risks** — Previously fixed vulnerabilities that could be reintroduced
|
|
10
|
-
2. **Known vulnerabilities** — Open findings that may be relevant to the code being reviewed
|
|
11
|
-
|
|
12
|
-
Returns structured security context that you should reference during code review. Focus on:
|
|
13
|
-
- Code that touches areas where historical findings were fixed (regression check)
|
|
14
|
-
|
|
15
|
-
For dependency risk, use \`zivis test dependencies\` instead — this tool no longer checks dependencies.
|
|
16
|
-
|
|
17
|
-
Provide at least one of: repo or application_id.`;
|
|
18
|
-
export const SECURITY_REVIEW_SCHEMA = {
|
|
19
|
-
repo: z.string().optional().describe("Repository name (owner/repo) — pulls findings scoped to this repo"),
|
|
20
|
-
application_id: z
|
|
21
|
-
.string()
|
|
22
|
-
.optional()
|
|
23
|
-
.describe("Application UUID — pulls findings scoped to this app. If omitted, uses applicationId from .zivis/project.json when set."),
|
|
24
|
-
focus_areas: z
|
|
25
|
-
.array(z.enum(["regression", "all"]))
|
|
26
|
-
.optional()
|
|
27
|
-
.describe("Which intelligence to gather (default: all)"),
|
|
28
|
-
severity_threshold: z
|
|
29
|
-
.enum(["critical", "high", "medium", "low", "info"])
|
|
30
|
-
.optional()
|
|
31
|
-
.describe("Minimum severity to include (default: low)"),
|
|
32
|
-
include_resolved: z
|
|
33
|
-
.boolean()
|
|
34
|
-
.default(true)
|
|
35
|
-
.describe("Include resolved findings for regression checking (default: true)"),
|
|
36
|
-
};
|
|
37
|
-
const SEVERITY_ORDER = {
|
|
38
|
-
critical: 5,
|
|
39
|
-
high: 4,
|
|
40
|
-
medium: 3,
|
|
41
|
-
low: 2,
|
|
42
|
-
info: 1,
|
|
43
|
-
};
|
|
44
|
-
export function createSecurityReviewHandler(apiClient, _config) {
|
|
45
|
-
return async (params) => {
|
|
46
|
-
const { repo, application_id: application_idParam, focus_areas = ["all"], severity_threshold = "low", include_resolved = true, } = params;
|
|
47
|
-
const application_id = resolveApplicationId(application_idParam);
|
|
48
|
-
if (!repo && !application_id) {
|
|
49
|
-
return {
|
|
50
|
-
content: [{
|
|
51
|
-
type: "text",
|
|
52
|
-
text: "Error: Provide at least one of: repo or application_id — " +
|
|
53
|
-
"or run `zivis init` to connect this repository to a ZIVIS Application " +
|
|
54
|
-
"so application_id resolves automatically.",
|
|
55
|
-
}],
|
|
56
|
-
isError: true,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const shouldInclude = (area) => focus_areas.includes("all") || focus_areas.includes(area);
|
|
60
|
-
const context = {
|
|
61
|
-
_description: "ZIVIS Security Review Context — use this intelligence during code review",
|
|
62
|
-
generatedAt: new Date().toISOString(),
|
|
63
|
-
parameters: { repo, application_id },
|
|
64
|
-
};
|
|
65
|
-
const errors = [];
|
|
66
|
-
if (shouldInclude("regression") && (repo || application_id)) {
|
|
67
|
-
try {
|
|
68
|
-
const resolvedFindings = await fetchFindings(apiClient, {
|
|
69
|
-
repo,
|
|
70
|
-
status: "resolved",
|
|
71
|
-
limit: 50,
|
|
72
|
-
});
|
|
73
|
-
const dismissedFindings = await fetchFindings(apiClient, {
|
|
74
|
-
repo,
|
|
75
|
-
status: "false_positive",
|
|
76
|
-
limit: 20,
|
|
77
|
-
});
|
|
78
|
-
const regressionPatterns = buildRegressionPatterns(resolvedFindings);
|
|
79
|
-
context.regressionCheck = {
|
|
80
|
-
_instruction: "Check code changes against these previously fixed vulnerabilities. Flag if similar patterns appear.",
|
|
81
|
-
resolvedCount: resolvedFindings.length,
|
|
82
|
-
patterns: regressionPatterns,
|
|
83
|
-
recentlyFixed: resolvedFindings.slice(0, 10).map(summarizeFinding),
|
|
84
|
-
falsePositives: dismissedFindings.slice(0, 5).map(summarizeFinding),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
catch (err) {
|
|
88
|
-
errors.push(`Regression data: ${err instanceof Error ? err.message : "failed"}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
if (shouldInclude("regression") && (repo || application_id)) {
|
|
92
|
-
try {
|
|
93
|
-
const minSeverity = SEVERITY_ORDER[severity_threshold] || 2;
|
|
94
|
-
const openFindings = await fetchFindings(apiClient, {
|
|
95
|
-
repo,
|
|
96
|
-
status: "open",
|
|
97
|
-
limit: 50,
|
|
98
|
-
});
|
|
99
|
-
const filtered = openFindings.filter((f) => (SEVERITY_ORDER[f.severity] || 1) >= minSeverity);
|
|
100
|
-
context.openVulnerabilities = {
|
|
101
|
-
_instruction: "These are KNOWN open vulnerabilities. Check if code changes interact with or worsen these issues.",
|
|
102
|
-
count: filtered.length,
|
|
103
|
-
bySeverity: countBySeverity(filtered),
|
|
104
|
-
findings: filtered.slice(0, 20).map(summarizeFinding),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
catch (err) {
|
|
108
|
-
errors.push(`Open findings: ${err instanceof Error ? err.message : "failed"}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
context.reviewGuidance = buildReviewGuidance(context);
|
|
112
|
-
if (errors.length > 0) {
|
|
113
|
-
context.warnings = errors;
|
|
114
|
-
}
|
|
115
|
-
return {
|
|
116
|
-
content: [{
|
|
117
|
-
type: "text",
|
|
118
|
-
text: JSON.stringify(sanitizeResponse(context), null, 2),
|
|
119
|
-
}],
|
|
120
|
-
};
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
async function fetchFindings(apiClient, params) {
|
|
124
|
-
const query = new URLSearchParams();
|
|
125
|
-
if (params.repo)
|
|
126
|
-
query.set("resourceName", params.repo);
|
|
127
|
-
if (params.status)
|
|
128
|
-
query.set("status", params.status);
|
|
129
|
-
if (params.limit)
|
|
130
|
-
query.set("limit", String(params.limit));
|
|
131
|
-
const path = `/api/findings/unified?${query.toString()}`;
|
|
132
|
-
const data = await apiClient.get(path);
|
|
133
|
-
return data.findings || [];
|
|
134
|
-
}
|
|
135
|
-
function summarizeFinding(f) {
|
|
136
|
-
return {
|
|
137
|
-
title: f.title,
|
|
138
|
-
severity: f.severity,
|
|
139
|
-
category: f.category,
|
|
140
|
-
cweId: f.cweId,
|
|
141
|
-
status: f.status,
|
|
142
|
-
targetUrl: f.targetUrl,
|
|
143
|
-
description: f.description?.substring(0, 300),
|
|
144
|
-
remediation: f.recommendation?.substring(0, 300) || f.remediation?.substring(0, 300),
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
function countBySeverity(findings) {
|
|
148
|
-
const counts = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
149
|
-
for (const f of findings) {
|
|
150
|
-
const sev = f.severity || "info";
|
|
151
|
-
counts[sev] = (counts[sev] || 0) + 1;
|
|
152
|
-
}
|
|
153
|
-
return counts;
|
|
154
|
-
}
|
|
155
|
-
function buildRegressionPatterns(resolvedFindings) {
|
|
156
|
-
const patternMap = new Map();
|
|
157
|
-
for (const f of resolvedFindings) {
|
|
158
|
-
const key = `${f.category || "uncategorized"}::${f.cweId || "no-cwe"}`;
|
|
159
|
-
const existing = patternMap.get(key);
|
|
160
|
-
if (existing) {
|
|
161
|
-
existing.count++;
|
|
162
|
-
if (existing.titles.length < 3)
|
|
163
|
-
existing.titles.push(f.title);
|
|
164
|
-
}
|
|
165
|
-
else {
|
|
166
|
-
patternMap.set(key, {
|
|
167
|
-
count: 1,
|
|
168
|
-
titles: [f.title],
|
|
169
|
-
cweId: f.cweId,
|
|
170
|
-
category: f.category,
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
return Array.from(patternMap.values())
|
|
175
|
-
.sort((a, b) => b.count - a.count)
|
|
176
|
-
.slice(0, 15)
|
|
177
|
-
.map((p) => ({
|
|
178
|
-
category: p.category,
|
|
179
|
-
cweId: p.cweId,
|
|
180
|
-
occurrences: p.count,
|
|
181
|
-
examples: p.titles,
|
|
182
|
-
_check: `Previously fixed ${p.count}x — verify this pattern is not reintroduced`,
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
185
|
-
function buildReviewGuidance(context) {
|
|
186
|
-
const guidance = [];
|
|
187
|
-
const regression = context.regressionCheck;
|
|
188
|
-
if (regression?.resolvedCount > 0) {
|
|
189
|
-
guidance.push(`REGRESSION: ${regression.resolvedCount} previously fixed vulnerabilities. Check ${regression.patterns?.length || 0} recurring patterns.`);
|
|
190
|
-
}
|
|
191
|
-
const open = context.openVulnerabilities;
|
|
192
|
-
if (open?.count > 0) {
|
|
193
|
-
guidance.push(`OPEN VULNS: ${open.count} known vulnerabilities (${open.bySeverity?.critical || 0} critical, ${open.bySeverity?.high || 0} high). Verify changes don't worsen these.`);
|
|
194
|
-
}
|
|
195
|
-
if (guidance.length === 0) {
|
|
196
|
-
guidance.push("No significant security context found. Perform standard code review best practices.");
|
|
197
|
-
}
|
|
198
|
-
return guidance;
|
|
199
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}>;
|
|
@@ -1,53 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}>;
|
|
@@ -1,73 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
}>;
|