@zivis/mcp 0.1.0-alpha.26 → 0.1.0-alpha.28
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/pattern-packs/zivis-public-0.2.0/manifest.json +1 -1
- package/dist/server.js +20 -0
- package/dist/tools/get-signal.d.ts +24 -0
- package/dist/tools/get-signal.js +75 -0
- package/dist/tools/list-changes-since.d.ts +24 -0
- package/dist/tools/list-changes-since.js +65 -0
- package/dist/tools/list-signals.d.ts +37 -0
- package/dist/tools/list-signals.js +83 -0
- package/dist/tools/threat-overview.d.ts +24 -0
- package/dist/tools/threat-overview.js +81 -0
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"pack_id": "zivis-public",
|
|
4
4
|
"pack_name": "ZIVIS Public Pattern Pack",
|
|
5
5
|
"version": "0.2.0",
|
|
6
|
-
"built_at": "2026-05-
|
|
6
|
+
"built_at": "2026-05-17T13:05:28.291Z",
|
|
7
7
|
"tier": "customer_safe",
|
|
8
8
|
"description": "ZIVIS-curated public pattern pack — capsules + inference prompts evaluated locally on the user's machine.",
|
|
9
9
|
"capsules": [
|
package/dist/server.js
CHANGED
|
@@ -64,6 +64,10 @@ import { INSPECT_ZAT_NAME, INSPECT_ZAT_DESCRIPTION, INSPECT_ZAT_SCHEMA, createIn
|
|
|
64
64
|
import { LIST_APPLICATIONS_NAME, LIST_APPLICATIONS_DESCRIPTION, LIST_APPLICATIONS_SCHEMA, createListApplicationsHandler, } from "./tools/list-applications.js";
|
|
65
65
|
import { GET_APPLICATION_NAME, GET_APPLICATION_DESCRIPTION, GET_APPLICATION_SCHEMA, createGetApplicationHandler, } from "./tools/get-application.js";
|
|
66
66
|
import { GET_APPLICATION_OVERVIEW_NAME, GET_APPLICATION_OVERVIEW_DESCRIPTION, GET_APPLICATION_OVERVIEW_SCHEMA, createGetApplicationOverviewHandler, } from "./tools/get-application-overview.js";
|
|
67
|
+
import { THREAT_OVERVIEW_NAME, THREAT_OVERVIEW_DESCRIPTION, THREAT_OVERVIEW_SCHEMA, createThreatOverviewHandler, } from "./tools/threat-overview.js";
|
|
68
|
+
import { LIST_SIGNALS_NAME, LIST_SIGNALS_DESCRIPTION, LIST_SIGNALS_SCHEMA, createListSignalsHandler, } from "./tools/list-signals.js";
|
|
69
|
+
import { GET_SIGNAL_NAME, GET_SIGNAL_DESCRIPTION, GET_SIGNAL_SCHEMA, createGetSignalHandler, } from "./tools/get-signal.js";
|
|
70
|
+
import { LIST_CHANGES_SINCE_NAME, LIST_CHANGES_SINCE_DESCRIPTION, LIST_CHANGES_SINCE_SCHEMA, createListChangesSinceHandler, } from "./tools/list-changes-since.js";
|
|
67
71
|
import { LIST_ENDPOINTS_NAME, LIST_ENDPOINTS_DESCRIPTION, LIST_ENDPOINTS_SCHEMA, createListEndpointsHandler, } from "./tools/list-endpoints.js";
|
|
68
72
|
import { IMPORT_OPENAPI_ENDPOINTS_NAME, IMPORT_OPENAPI_ENDPOINTS_DESCRIPTION, IMPORT_OPENAPI_ENDPOINTS_SCHEMA, createImportOpenApiEndpointsHandler, } from "./tools/import-openapi-endpoints.js";
|
|
69
73
|
import { UPDATE_ENDPOINT_NAME, UPDATE_ENDPOINT_DESCRIPTION, UPDATE_ENDPOINT_SCHEMA, createUpdateEndpointHandler, } from "./tools/update-endpoint.js";
|
|
@@ -187,6 +191,22 @@ export async function startServer(incoming = DEFAULT_CONFIG) {
|
|
|
187
191
|
description: GET_APPLICATION_OVERVIEW_DESCRIPTION,
|
|
188
192
|
inputSchema: GET_APPLICATION_OVERVIEW_SCHEMA,
|
|
189
193
|
}, createGetApplicationOverviewHandler(apiClient));
|
|
194
|
+
server.registerTool(THREAT_OVERVIEW_NAME, {
|
|
195
|
+
description: THREAT_OVERVIEW_DESCRIPTION,
|
|
196
|
+
inputSchema: THREAT_OVERVIEW_SCHEMA,
|
|
197
|
+
}, createThreatOverviewHandler(apiClient));
|
|
198
|
+
server.registerTool(LIST_SIGNALS_NAME, {
|
|
199
|
+
description: LIST_SIGNALS_DESCRIPTION,
|
|
200
|
+
inputSchema: LIST_SIGNALS_SCHEMA,
|
|
201
|
+
}, createListSignalsHandler(apiClient));
|
|
202
|
+
server.registerTool(GET_SIGNAL_NAME, {
|
|
203
|
+
description: GET_SIGNAL_DESCRIPTION,
|
|
204
|
+
inputSchema: GET_SIGNAL_SCHEMA,
|
|
205
|
+
}, createGetSignalHandler(apiClient));
|
|
206
|
+
server.registerTool(LIST_CHANGES_SINCE_NAME, {
|
|
207
|
+
description: LIST_CHANGES_SINCE_DESCRIPTION,
|
|
208
|
+
inputSchema: LIST_CHANGES_SINCE_SCHEMA,
|
|
209
|
+
}, createListChangesSinceHandler(apiClient));
|
|
190
210
|
server.registerTool(LIST_ENDPOINTS_NAME, {
|
|
191
211
|
description: LIST_ENDPOINTS_DESCRIPTION,
|
|
192
212
|
inputSchema: LIST_ENDPOINTS_SCHEMA,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ApiClient } from "../api-client.js";
|
|
3
|
+
export declare const GET_SIGNAL_NAME = "zivis_get_signal";
|
|
4
|
+
export declare const GET_SIGNAL_DESCRIPTION = "Get full detail on a single Signal by its id.\n\nReturns the qualified narrative \u2014 description, mitigation, attack-chain context, taxonomy (STRIDE / ATPS layer / MITRE / OWASP / compliance mappings), detected safeguards and what breaks them, and the polymorphic source-artifact reference for drilling into the native subsystem.\n\nPass `signal_id` from a `zivis_list_signals` response.\n\nSECURITY: Display-shaped output only. No raw graph data.";
|
|
5
|
+
export declare const GET_SIGNAL_SCHEMA: {
|
|
6
|
+
application_id: z.ZodOptional<z.ZodString>;
|
|
7
|
+
signal_id: z.ZodString;
|
|
8
|
+
};
|
|
9
|
+
export declare function createGetSignalHandler(apiClient: ApiClient): (params: {
|
|
10
|
+
application_id?: string;
|
|
11
|
+
signal_id: string;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
content: {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
isError: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
content: {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
isError?: undefined;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireApplicationId } from "../resolve-application-id.js";
|
|
3
|
+
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
+
export const GET_SIGNAL_NAME = "zivis_get_signal";
|
|
5
|
+
export const GET_SIGNAL_DESCRIPTION = `Get full detail on a single Signal by its id.
|
|
6
|
+
|
|
7
|
+
Returns the qualified narrative — description, mitigation, attack-chain context, taxonomy (STRIDE / ATPS layer / MITRE / OWASP / compliance mappings), detected safeguards and what breaks them, and the polymorphic source-artifact reference for drilling into the native subsystem.
|
|
8
|
+
|
|
9
|
+
Pass \`signal_id\` from a \`zivis_list_signals\` response.
|
|
10
|
+
|
|
11
|
+
SECURITY: Display-shaped output only. No raw graph data.`;
|
|
12
|
+
export const GET_SIGNAL_SCHEMA = {
|
|
13
|
+
application_id: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("Application UUID. If omitted, uses applicationId from .zivis/project.json."),
|
|
17
|
+
signal_id: z
|
|
18
|
+
.string()
|
|
19
|
+
.describe("Opaque signal id (from zivis_list_signals)."),
|
|
20
|
+
};
|
|
21
|
+
export function createGetSignalHandler(apiClient) {
|
|
22
|
+
return async (params) => {
|
|
23
|
+
const req = requireApplicationId(params.application_id);
|
|
24
|
+
if (!req.ok) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: `Error: ${req.message}` }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (!params.signal_id) {
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text: "Error: signal_id is required" }],
|
|
33
|
+
isError: true,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const path = `/api/apps/${req.id}/signals/${encodeURIComponent(params.signal_id)}`;
|
|
37
|
+
try {
|
|
38
|
+
const s = await apiClient.get(path);
|
|
39
|
+
const result = {
|
|
40
|
+
id: s.id,
|
|
41
|
+
source: s.source,
|
|
42
|
+
severity: s.severity,
|
|
43
|
+
status: s.status,
|
|
44
|
+
confidence: s.confidence,
|
|
45
|
+
title: s.title,
|
|
46
|
+
description: s.description,
|
|
47
|
+
category: s.category,
|
|
48
|
+
attack_chain: s.attackChain
|
|
49
|
+
? {
|
|
50
|
+
name: s.attackChain.chainName,
|
|
51
|
+
step: `${s.attackChain.stepIndex}/${s.attackChain.totalSteps}`,
|
|
52
|
+
}
|
|
53
|
+
: null,
|
|
54
|
+
taxonomy: s.taxonomy ?? null,
|
|
55
|
+
components: s.components?.map((c) => c.name) ?? [],
|
|
56
|
+
refs: s.refs,
|
|
57
|
+
recommended_action: s.recommendedAction,
|
|
58
|
+
safeguards: s.safeguards ?? null,
|
|
59
|
+
fingerprint: s.fingerprint,
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
content: [
|
|
63
|
+
{ type: "text", text: JSON.stringify(sanitizeResponse(result), null, 2) },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
const message = err instanceof Error ? err.message : "Failed to load signal";
|
|
69
|
+
return {
|
|
70
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
71
|
+
isError: true,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ApiClient } from "../api-client.js";
|
|
3
|
+
export declare const LIST_CHANGES_SINCE_NAME = "zivis_list_changes_since";
|
|
4
|
+
export declare const LIST_CHANGES_SINCE_DESCRIPTION = "What changed in this app's threat model since the given version. Returns human-readable change cards (added / removed / edited components, scenarios, signals) \u2014 no raw graph deltas.\n\nUse this when the user asks:\n- \"what's new since I last looked\"\n- \"what changed since the last review\"\n- \"what's new since version X\"\n\nGet a `since_version_id` from `zivis_list_threat_model_versions` or from a prior overview call. Returns an empty list when nothing changed.";
|
|
5
|
+
export declare const LIST_CHANGES_SINCE_SCHEMA: {
|
|
6
|
+
application_id: z.ZodOptional<z.ZodString>;
|
|
7
|
+
since_version_id: z.ZodString;
|
|
8
|
+
};
|
|
9
|
+
export declare function createListChangesSinceHandler(apiClient: ApiClient): (params: {
|
|
10
|
+
application_id?: string;
|
|
11
|
+
since_version_id: string;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
content: {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
isError: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
content: {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
isError?: undefined;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireApplicationId } from "../resolve-application-id.js";
|
|
3
|
+
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
+
export const LIST_CHANGES_SINCE_NAME = "zivis_list_changes_since";
|
|
5
|
+
export const LIST_CHANGES_SINCE_DESCRIPTION = `What changed in this app's threat model since the given version. Returns human-readable change cards (added / removed / edited components, scenarios, signals) — no raw graph deltas.
|
|
6
|
+
|
|
7
|
+
Use this when the user asks:
|
|
8
|
+
- "what's new since I last looked"
|
|
9
|
+
- "what changed since the last review"
|
|
10
|
+
- "what's new since version X"
|
|
11
|
+
|
|
12
|
+
Get a \`since_version_id\` from \`zivis_list_threat_model_versions\` or from a prior overview call. Returns an empty list when nothing changed.`;
|
|
13
|
+
export const LIST_CHANGES_SINCE_SCHEMA = {
|
|
14
|
+
application_id: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("Application UUID. If omitted, uses applicationId from .zivis/project.json."),
|
|
18
|
+
since_version_id: z
|
|
19
|
+
.string()
|
|
20
|
+
.describe("Opaque version token (from zivis_threat_overview or zivis_list_threat_model_versions)."),
|
|
21
|
+
};
|
|
22
|
+
export function createListChangesSinceHandler(apiClient) {
|
|
23
|
+
return async (params) => {
|
|
24
|
+
const req = requireApplicationId(params.application_id);
|
|
25
|
+
if (!req.ok) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: `Error: ${req.message}` }],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (!params.since_version_id) {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{ type: "text", text: "Error: since_version_id is required" },
|
|
35
|
+
],
|
|
36
|
+
isError: true,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const path = `/api/apps/${req.id}/change-digest?since=${encodeURIComponent(params.since_version_id)}`;
|
|
40
|
+
try {
|
|
41
|
+
const data = await apiClient.get(path);
|
|
42
|
+
const result = {
|
|
43
|
+
total: data.length,
|
|
44
|
+
items: data.map((c) => ({
|
|
45
|
+
kind: c.kind,
|
|
46
|
+
title: c.title,
|
|
47
|
+
narrative: c.narrative,
|
|
48
|
+
component: c.componentName,
|
|
49
|
+
})),
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{ type: "text", text: JSON.stringify(sanitizeResponse(result), null, 2) },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const message = err instanceof Error ? err.message : "Failed to load change digest";
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ApiClient } from "../api-client.js";
|
|
3
|
+
export declare const LIST_SIGNALS_NAME = "zivis_list_signals";
|
|
4
|
+
export declare const LIST_SIGNALS_DESCRIPTION = "List the application's current Signals \u2014 the unified \"needs attention\" stream.\n\nA Signal is ZIVIS's promoted artifact that crosses source families (threat-model Observations, red-team / pen-test Findings, behavior-monitoring Behaviors / Patterns). Each Signal carries severity, status, the chain reference when applicable, and the source family discriminator.\n\nUse this when the user asks:\n- \"what are the open security issues\" / \"what threats does ZIVIS show\"\n- \"what's high or critical\" (filter by severity)\n- \"what's still open\" (filter by status)\n\nReturns display-shaped DTOs. `id` is an opaque token \u2014 pass to `zivis_get_signal` for detail.\n\nSECURITY: This is a low-cost read. Caller must be authorized for the application; cross-org reads return empty.";
|
|
5
|
+
export declare const LIST_SIGNALS_SCHEMA: {
|
|
6
|
+
application_id: z.ZodOptional<z.ZodString>;
|
|
7
|
+
severity: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
critical: "critical";
|
|
9
|
+
high: "high";
|
|
10
|
+
medium: "medium";
|
|
11
|
+
low: "low";
|
|
12
|
+
info: "info";
|
|
13
|
+
}>>;
|
|
14
|
+
status: z.ZodOptional<z.ZodEnum<{
|
|
15
|
+
open: "open";
|
|
16
|
+
in_progress: "in_progress";
|
|
17
|
+
resolved: "resolved";
|
|
18
|
+
dismissed: "dismissed";
|
|
19
|
+
}>>;
|
|
20
|
+
};
|
|
21
|
+
export declare function createListSignalsHandler(apiClient: ApiClient): (params: {
|
|
22
|
+
application_id?: string;
|
|
23
|
+
severity?: string;
|
|
24
|
+
status?: string;
|
|
25
|
+
}) => Promise<{
|
|
26
|
+
content: {
|
|
27
|
+
type: "text";
|
|
28
|
+
text: string;
|
|
29
|
+
}[];
|
|
30
|
+
isError: boolean;
|
|
31
|
+
} | {
|
|
32
|
+
content: {
|
|
33
|
+
type: "text";
|
|
34
|
+
text: string;
|
|
35
|
+
}[];
|
|
36
|
+
isError?: undefined;
|
|
37
|
+
}>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireApplicationId } from "../resolve-application-id.js";
|
|
3
|
+
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
+
export const LIST_SIGNALS_NAME = "zivis_list_signals";
|
|
5
|
+
export const LIST_SIGNALS_DESCRIPTION = `List the application's current Signals — the unified "needs attention" stream.
|
|
6
|
+
|
|
7
|
+
A Signal is ZIVIS's promoted artifact that crosses source families (threat-model Observations, red-team / pen-test Findings, behavior-monitoring Behaviors / Patterns). Each Signal carries severity, status, the chain reference when applicable, and the source family discriminator.
|
|
8
|
+
|
|
9
|
+
Use this when the user asks:
|
|
10
|
+
- "what are the open security issues" / "what threats does ZIVIS show"
|
|
11
|
+
- "what's high or critical" (filter by severity)
|
|
12
|
+
- "what's still open" (filter by status)
|
|
13
|
+
|
|
14
|
+
Returns display-shaped DTOs. \`id\` is an opaque token — pass to \`zivis_get_signal\` for detail.
|
|
15
|
+
|
|
16
|
+
SECURITY: This is a low-cost read. Caller must be authorized for the application; cross-org reads return empty.`;
|
|
17
|
+
export const LIST_SIGNALS_SCHEMA = {
|
|
18
|
+
application_id: z
|
|
19
|
+
.string()
|
|
20
|
+
.optional()
|
|
21
|
+
.describe("Application UUID (from zivis_list_applications). If omitted, uses applicationId from .zivis/project.json when set."),
|
|
22
|
+
severity: z
|
|
23
|
+
.enum(["critical", "high", "medium", "low", "info"])
|
|
24
|
+
.optional()
|
|
25
|
+
.describe("Filter by severity. Omit to return all."),
|
|
26
|
+
status: z
|
|
27
|
+
.enum(["open", "in_progress", "resolved", "dismissed"])
|
|
28
|
+
.optional()
|
|
29
|
+
.describe("Filter by wire status. Omit to return all."),
|
|
30
|
+
};
|
|
31
|
+
export function createListSignalsHandler(apiClient) {
|
|
32
|
+
return async (params) => {
|
|
33
|
+
const req = requireApplicationId(params.application_id);
|
|
34
|
+
if (!req.ok) {
|
|
35
|
+
return {
|
|
36
|
+
content: [{ type: "text", text: `Error: ${req.message}` }],
|
|
37
|
+
isError: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const application_id = req.id;
|
|
41
|
+
const qs = new URLSearchParams();
|
|
42
|
+
if (params.severity)
|
|
43
|
+
qs.set("severity", params.severity);
|
|
44
|
+
if (params.status)
|
|
45
|
+
qs.set("status", params.status);
|
|
46
|
+
const path = `/api/apps/${application_id}/signals${qs.toString() ? `?${qs}` : ""}`;
|
|
47
|
+
try {
|
|
48
|
+
const data = await apiClient.get(path);
|
|
49
|
+
const result = {
|
|
50
|
+
total: data.length,
|
|
51
|
+
items: data.map((s) => ({
|
|
52
|
+
id: s.id,
|
|
53
|
+
source: s.source,
|
|
54
|
+
severity: s.severity,
|
|
55
|
+
status: s.status,
|
|
56
|
+
confidence: s.confidence,
|
|
57
|
+
title: s.title,
|
|
58
|
+
category: s.category,
|
|
59
|
+
attack_chain: s.attackChain
|
|
60
|
+
? {
|
|
61
|
+
name: s.attackChain.chainName,
|
|
62
|
+
step: `${s.attackChain.stepIndex}/${s.attackChain.totalSteps}`,
|
|
63
|
+
}
|
|
64
|
+
: null,
|
|
65
|
+
components: s.components?.map((c) => c.name) ?? [],
|
|
66
|
+
recommended_action: s.recommendedAction,
|
|
67
|
+
})),
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{ type: "text", text: JSON.stringify(sanitizeResponse(result), null, 2) },
|
|
72
|
+
],
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const message = err instanceof Error ? err.message : "Failed to list signals";
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ApiClient } from "../api-client.js";
|
|
3
|
+
export declare const THREAT_OVERVIEW_NAME = "zivis_threat_overview";
|
|
4
|
+
export declare const THREAT_OVERVIEW_DESCRIPTION = "Get the application's current threat-model overview \u2014 severity counts, node counts by type (components / actors / attack scenarios / controls), and the most recent analysis-run metadata.\n\nThis is the \"ZIVIS, what did you find?\" entry point. Use it:\n- right after `zivis_check_repo` to confirm SIGNAL data landed\n- when the user asks \"what threats does ZIVIS know about?\" or \"what's the security state?\"\n- as the first call after a server-side analysis run completes\n\nReturns display-shaped data \u2014 no graph IDs, no enum strings. Versions are opaque tokens; pass them to `zivis_list_changes_since` to diff.\n\nSECURITY: This is a low-cost read. Safe to call repeatedly. The graph itself never leaves the platform; only the display projection does.";
|
|
5
|
+
export declare const THREAT_OVERVIEW_SCHEMA: {
|
|
6
|
+
application_id: z.ZodOptional<z.ZodString>;
|
|
7
|
+
version_id: z.ZodOptional<z.ZodString>;
|
|
8
|
+
};
|
|
9
|
+
export declare function createThreatOverviewHandler(apiClient: ApiClient): (params: {
|
|
10
|
+
application_id?: string;
|
|
11
|
+
version_id?: string;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
content: {
|
|
14
|
+
type: "text";
|
|
15
|
+
text: string;
|
|
16
|
+
}[];
|
|
17
|
+
isError: boolean;
|
|
18
|
+
} | {
|
|
19
|
+
content: {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}[];
|
|
23
|
+
isError?: undefined;
|
|
24
|
+
}>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { requireApplicationId } from "../resolve-application-id.js";
|
|
3
|
+
import { sanitizeResponse } from "../sanitize.js";
|
|
4
|
+
export const THREAT_OVERVIEW_NAME = "zivis_threat_overview";
|
|
5
|
+
export const THREAT_OVERVIEW_DESCRIPTION = `Get the application's current threat-model overview — severity counts, node counts by type (components / actors / attack scenarios / controls), and the most recent analysis-run metadata.
|
|
6
|
+
|
|
7
|
+
This is the "ZIVIS, what did you find?" entry point. Use it:
|
|
8
|
+
- right after \`zivis_check_repo\` to confirm SIGNAL data landed
|
|
9
|
+
- when the user asks "what threats does ZIVIS know about?" or "what's the security state?"
|
|
10
|
+
- as the first call after a server-side analysis run completes
|
|
11
|
+
|
|
12
|
+
Returns display-shaped data — no graph IDs, no enum strings. Versions are opaque tokens; pass them to \`zivis_list_changes_since\` to diff.
|
|
13
|
+
|
|
14
|
+
SECURITY: This is a low-cost read. Safe to call repeatedly. The graph itself never leaves the platform; only the display projection does.`;
|
|
15
|
+
export const THREAT_OVERVIEW_SCHEMA = {
|
|
16
|
+
application_id: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Application UUID (from zivis_list_applications). If omitted, uses applicationId from .zivis/project.json when set."),
|
|
20
|
+
version_id: z
|
|
21
|
+
.string()
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("Optional opaque version token. When set, returns the overview as-of that captured GraphVersion. When omitted, returns current state."),
|
|
24
|
+
};
|
|
25
|
+
export function createThreatOverviewHandler(apiClient) {
|
|
26
|
+
return async (params) => {
|
|
27
|
+
const req = requireApplicationId(params.application_id);
|
|
28
|
+
if (!req.ok) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text: `Error: ${req.message}` }],
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const application_id = req.id;
|
|
35
|
+
const qs = params.version_id
|
|
36
|
+
? `?versionId=${encodeURIComponent(params.version_id)}`
|
|
37
|
+
: "";
|
|
38
|
+
const path = `/api/apps/${application_id}/threat-model/overview${qs}`;
|
|
39
|
+
try {
|
|
40
|
+
const data = await apiClient.get(path);
|
|
41
|
+
const result = {
|
|
42
|
+
application_id: data.appId,
|
|
43
|
+
threat_model_id: data.threatModelId,
|
|
44
|
+
version: data.versionId
|
|
45
|
+
? {
|
|
46
|
+
id: data.versionId,
|
|
47
|
+
label: data.versionLabel,
|
|
48
|
+
captured_at: data.capturedAt,
|
|
49
|
+
analysis_status: data.analysisStatus,
|
|
50
|
+
analyzed_at: data.analyzedAt,
|
|
51
|
+
}
|
|
52
|
+
: null,
|
|
53
|
+
node_counts: {
|
|
54
|
+
components: data.componentCount,
|
|
55
|
+
actors: data.actorCount,
|
|
56
|
+
attack_scenarios: data.attackScenarioCount,
|
|
57
|
+
controls: data.controlCount,
|
|
58
|
+
},
|
|
59
|
+
threat_counts: {
|
|
60
|
+
total: data.totalThreats,
|
|
61
|
+
critical: data.criticalCount,
|
|
62
|
+
high: data.highCount,
|
|
63
|
+
medium: data.mediumCount,
|
|
64
|
+
low: data.lowCount,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
content: [
|
|
69
|
+
{ type: "text", text: JSON.stringify(sanitizeResponse(result), null, 2) },
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
const message = err instanceof Error ? err.message : "Failed to load threat overview";
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
package/package.json
CHANGED