@zivis/mcp 0.1.0-alpha.21 → 0.1.0-alpha.22
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-pack/index.d.ts +133 -0
- package/dist/pattern-pack/index.js +212 -0
- package/dist/pattern-pack/index.js.map +1 -0
- package/dist/pattern-packs/zivis-public-0.1.0/capsules/agents/privilege-separation.yaml +228 -0
- package/dist/pattern-packs/zivis-public-0.1.0/capsules/prompting/self-consistency-no-isolation.yaml +240 -0
- package/dist/pattern-packs/zivis-public-0.1.0/capsules/security/late-org-filter.yaml +270 -0
- package/dist/pattern-packs/zivis-public-0.1.0/manifest.json +68 -0
- package/dist/pattern-packs/zivis-public-0.1.0/prompts/agents/privilege-separation/identify.md +54 -0
- package/dist/pattern-packs/zivis-public-0.1.0/prompts/prompting/self-consistency-no-isolation/identify.md +60 -0
- package/dist/pattern-packs/zivis-public-0.1.0/prompts/security/late-org-filter/identify.md +78 -0
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.js +1 -7
- package/dist/prompts/index.js.map +1 -1
- package/dist/server.js +26 -166
- package/dist/server.js.map +1 -1
- package/dist/tools/enterprise/get-threat-model-artifact.d.ts +30 -0
- package/dist/tools/enterprise/get-threat-model-artifact.js +80 -0
- package/dist/tools/enterprise/get-threat-model-artifact.js.map +1 -0
- package/dist/tools/enterprise/get-threat-model.d.ts +1 -1
- package/dist/tools/enterprise/get-threat-model.js +59 -11
- package/dist/tools/enterprise/get-threat-model.js.map +1 -1
- package/dist/tools/enterprise/list-threat-model-artifacts.d.ts +67 -0
- package/dist/tools/enterprise/list-threat-model-artifacts.js +121 -0
- package/dist/tools/enterprise/list-threat-model-artifacts.js.map +1 -0
- package/dist/tools/enterprise/manage-data-asset.d.ts +1 -1
- package/dist/tools/enterprise/manage-data-flow.d.ts +1 -1
- package/dist/tools/enterprise/manage-test-case.d.ts +1 -1
- package/dist/tools/inspect.d.ts +31 -0
- package/dist/tools/inspect.js +100 -0
- package/dist/tools/inspect.js.map +1 -0
- package/dist/tools/manage-application.d.ts +1 -1
- package/dist/tools/security-review.js +67 -50
- package/dist/tools/security-review.js.map +1 -1
- package/dist/tools/threat-get-capsule.d.ts +25 -0
- package/dist/tools/threat-get-capsule.js +64 -0
- package/dist/tools/threat-get-capsule.js.map +1 -0
- package/dist/tools/threat-get-inference-prompt.d.ts +32 -0
- package/dist/tools/threat-get-inference-prompt.js +91 -0
- package/dist/tools/threat-get-inference-prompt.js.map +1 -0
- package/dist/tools/threat-list-relevant-capsules.d.ts +30 -0
- package/dist/tools/threat-list-relevant-capsules.js +176 -0
- package/dist/tools/threat-list-relevant-capsules.js.map +1 -0
- package/package.json +10 -3
- package/dist/prompts/prep-for-launch.d.ts +0 -9
- package/dist/prompts/prep-for-launch.js +0 -62
- package/dist/prompts/prep-for-launch.js.map +0 -1
- package/dist/prompts/secure-my-app.d.ts +0 -9
- package/dist/prompts/secure-my-app.js +0 -70
- package/dist/prompts/secure-my-app.js.map +0 -1
- package/dist/prompts/weekly-check.d.ts +0 -9
- package/dist/prompts/weekly-check.js +0 -48
- package/dist/prompts/weekly-check.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-campaign.d.ts +0 -27
- package/dist/tools/enterprise/get-campaign.js +0 -31
- package/dist/tools/enterprise/get-campaign.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/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-campaigns.d.ts +0 -37
- package/dist/tools/enterprise/list-campaigns.js +0 -60
- package/dist/tools/enterprise/list-campaigns.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/manage-campaign-agent-instance.d.ts +0 -42
- package/dist/tools/enterprise/manage-campaign-agent-instance.js +0 -68
- package/dist/tools/enterprise/manage-campaign-agent-instance.js.map +0 -1
- package/dist/tools/enterprise/manage-campaign-target.d.ts +0 -44
- package/dist/tools/enterprise/manage-campaign-target.js +0 -70
- package/dist/tools/enterprise/manage-campaign-target.js.map +0 -1
- package/dist/tools/enterprise/manage-campaign.d.ts +0 -62
- package/dist/tools/enterprise/manage-campaign.js +0 -114
- package/dist/tools/enterprise/manage-campaign.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/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/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-auth-config.d.ts +0 -27
- package/dist/tools/get-application-auth-config.js +0 -44
- package/dist/tools/get-application-auth-config.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-finding-details.d.ts +0 -22
- package/dist/tools/get-finding-details.js +0 -61
- package/dist/tools/get-finding-details.js.map +0 -1
- package/dist/tools/get-findings.d.ts +0 -51
- package/dist/tools/get-findings.js +0 -124
- package/dist/tools/get-findings.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/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-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 -38
- package/dist/tools/list-scans.js +0 -125
- 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 -25
- package/dist/tools/list-test-scenarios.js +0 -94
- 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/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/setup-red-team-target.d.ts +0 -73
- package/dist/tools/setup-red-team-target.js +0 -461
- package/dist/tools/setup-red-team-target.js.map +0 -1
- package/dist/tools/triage-finding.d.ts +0 -41
- package/dist/tools/triage-finding.js +0 -125
- package/dist/tools/triage-finding.js.map +0 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local pattern pack reader.
|
|
3
|
+
*
|
|
4
|
+
* The pack ships bundled inside the @zivis/mcp npm package at
|
|
5
|
+
* `dist/pattern-packs/<pack-id>-<version>/`. On first use we copy it to
|
|
6
|
+
* `~/Library/Caches/zivis/pattern-packs/<pack-id>-<version>/` so future
|
|
7
|
+
* runs read from the user cache directly.
|
|
8
|
+
*
|
|
9
|
+
* Both the CLI's matcher (Phase 3) and the MCP tools that surface
|
|
10
|
+
* relevant capsules mid-IDE-conversation read through this module.
|
|
11
|
+
*
|
|
12
|
+
* Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 2A)
|
|
13
|
+
* Schemas:
|
|
14
|
+
* - schemas/pattern-pack-manifest.schema.json (manifest.json)
|
|
15
|
+
* - schemas/pattern-detection-card.schema.json (capsule yaml)
|
|
16
|
+
*/
|
|
17
|
+
export interface PackManifest {
|
|
18
|
+
schema_version: "1.0.0";
|
|
19
|
+
pack_id: string;
|
|
20
|
+
pack_name: string;
|
|
21
|
+
version: string;
|
|
22
|
+
built_at: string;
|
|
23
|
+
tier: "public_teaser" | "public" | "customer_safe";
|
|
24
|
+
description?: string;
|
|
25
|
+
capsules: ManifestCapsuleEntry[];
|
|
26
|
+
prompts: ManifestPromptEntry[];
|
|
27
|
+
}
|
|
28
|
+
export interface ManifestCapsuleEntry {
|
|
29
|
+
id: string;
|
|
30
|
+
version: string;
|
|
31
|
+
path: string;
|
|
32
|
+
sha256: string;
|
|
33
|
+
category?: string;
|
|
34
|
+
lifecycle?: string;
|
|
35
|
+
applicable_languages?: string[];
|
|
36
|
+
}
|
|
37
|
+
export interface ManifestPromptEntry {
|
|
38
|
+
path: string;
|
|
39
|
+
sha256: string;
|
|
40
|
+
capsule_id?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface RelevanceTerm {
|
|
43
|
+
dependency?: string;
|
|
44
|
+
direct_only?: boolean;
|
|
45
|
+
language?: string;
|
|
46
|
+
framework?: string;
|
|
47
|
+
evidence?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface RelevanceFilter {
|
|
50
|
+
any_of?: RelevanceTerm[];
|
|
51
|
+
all_of?: RelevanceTerm[];
|
|
52
|
+
none_of?: RelevanceTerm[];
|
|
53
|
+
}
|
|
54
|
+
export interface Capsule {
|
|
55
|
+
id: string;
|
|
56
|
+
slug: string;
|
|
57
|
+
version: string;
|
|
58
|
+
category: string;
|
|
59
|
+
title?: string;
|
|
60
|
+
headline?: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
detection_tier: "public" | "proprietary";
|
|
63
|
+
scoring_tier: "public" | "proprietary";
|
|
64
|
+
applicable_languages: string[];
|
|
65
|
+
relevance_filter?: RelevanceFilter;
|
|
66
|
+
strategies: unknown[];
|
|
67
|
+
required_evidence_count: number;
|
|
68
|
+
threats?: unknown[];
|
|
69
|
+
lifecycle: "draft" | "active" | "deprecated";
|
|
70
|
+
sensitivity_level?: "public_teaser" | "customer_safe" | "zivis_confidential";
|
|
71
|
+
safe_summary?: string;
|
|
72
|
+
detect_when?: string;
|
|
73
|
+
risk_hints?: string[];
|
|
74
|
+
architectural_signals?: string[];
|
|
75
|
+
model_task_prompt_ref?: string;
|
|
76
|
+
expected_output_schema?: unknown;
|
|
77
|
+
minimum_context_required?: {
|
|
78
|
+
lines?: number;
|
|
79
|
+
symbols?: string[];
|
|
80
|
+
};
|
|
81
|
+
related_patterns?: string[];
|
|
82
|
+
repair_contract?: {
|
|
83
|
+
allowed?: string[];
|
|
84
|
+
forbidden?: string[];
|
|
85
|
+
};
|
|
86
|
+
validation_contract?: {
|
|
87
|
+
requires_tests_pass?: boolean;
|
|
88
|
+
requires_static_rules?: string[];
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export interface PackHandle {
|
|
92
|
+
manifest: PackManifest;
|
|
93
|
+
rootDir: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Minimal structural interface of a RepoGraphArtifactV1 that the reader
|
|
97
|
+
* actually needs. Lets this module avoid a hard dep on the full graph-types
|
|
98
|
+
* package while preserving compatibility with `RepoGraphArtifactV1`.
|
|
99
|
+
*/
|
|
100
|
+
export interface GraphArtifactView {
|
|
101
|
+
scope: {
|
|
102
|
+
languages?: string[];
|
|
103
|
+
};
|
|
104
|
+
nodes: Array<{
|
|
105
|
+
type: string;
|
|
106
|
+
evidence: Array<{
|
|
107
|
+
kind: string;
|
|
108
|
+
}>;
|
|
109
|
+
attributes?: {
|
|
110
|
+
package?: string;
|
|
111
|
+
};
|
|
112
|
+
}>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Locate the active pack and ensure it's available in the user cache.
|
|
116
|
+
*
|
|
117
|
+
* Resolution order:
|
|
118
|
+
* 1. ZIVIS_PACK_DIR env var (override for tests / enterprise air-gap imports)
|
|
119
|
+
* 2. User cache, if present
|
|
120
|
+
* 3. Bundled pack inside @zivis/mcp (copied to user cache on first use)
|
|
121
|
+
*/
|
|
122
|
+
export declare function loadActivePack(packId?: string): Promise<PackHandle>;
|
|
123
|
+
export declare function getCapsule(handle: PackHandle, capsuleId: string): Promise<Capsule>;
|
|
124
|
+
export declare function getInferencePrompt(handle: PackHandle, ref: string): Promise<string>;
|
|
125
|
+
export declare function listCapsuleIds(handle: PackHandle): Promise<string[]>;
|
|
126
|
+
export declare function findRelevantCapsules(handle: PackHandle, artifact: GraphArtifactView): Promise<Capsule[]>;
|
|
127
|
+
interface EvalContext {
|
|
128
|
+
packageNames: Set<string>;
|
|
129
|
+
languages: Set<string>;
|
|
130
|
+
evidenceKinds: Set<string>;
|
|
131
|
+
}
|
|
132
|
+
export declare function matchesRelevance(cap: Capsule, ctx: EvalContext): boolean;
|
|
133
|
+
export {};
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local pattern pack reader.
|
|
3
|
+
*
|
|
4
|
+
* The pack ships bundled inside the @zivis/mcp npm package at
|
|
5
|
+
* `dist/pattern-packs/<pack-id>-<version>/`. On first use we copy it to
|
|
6
|
+
* `~/Library/Caches/zivis/pattern-packs/<pack-id>-<version>/` so future
|
|
7
|
+
* runs read from the user cache directly.
|
|
8
|
+
*
|
|
9
|
+
* Both the CLI's matcher (Phase 3) and the MCP tools that surface
|
|
10
|
+
* relevant capsules mid-IDE-conversation read through this module.
|
|
11
|
+
*
|
|
12
|
+
* Plan: docs/plans/LOCAL-REPO-GRAPH-IMPLEMENTATION.md (Phase 2A)
|
|
13
|
+
* Schemas:
|
|
14
|
+
* - schemas/pattern-pack-manifest.schema.json (manifest.json)
|
|
15
|
+
* - schemas/pattern-detection-card.schema.json (capsule yaml)
|
|
16
|
+
*/
|
|
17
|
+
import * as fs from "node:fs/promises";
|
|
18
|
+
import * as fssync from "node:fs";
|
|
19
|
+
import * as os from "node:os";
|
|
20
|
+
import * as path from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import * as crypto from "node:crypto";
|
|
23
|
+
import * as yaml from "js-yaml";
|
|
24
|
+
// ── Cache layout ──
|
|
25
|
+
function userCacheRoot() {
|
|
26
|
+
const home = os.homedir();
|
|
27
|
+
if (process.platform === "darwin") {
|
|
28
|
+
return path.join(home, "Library", "Caches", "zivis");
|
|
29
|
+
}
|
|
30
|
+
if (process.platform === "win32") {
|
|
31
|
+
const localAppData = process.env.LOCALAPPDATA ?? path.join(home, "AppData", "Local");
|
|
32
|
+
return path.join(localAppData, "zivis", "Cache");
|
|
33
|
+
}
|
|
34
|
+
const xdg = process.env.XDG_CACHE_HOME;
|
|
35
|
+
return path.join(xdg ?? path.join(home, ".cache"), "zivis");
|
|
36
|
+
}
|
|
37
|
+
function userPackRoot() {
|
|
38
|
+
return path.join(userCacheRoot(), "pattern-packs");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Locate the pack bundled inside the @zivis/mcp npm install. We resolve
|
|
42
|
+
* from this module's own URL so it works whether the MCP is installed
|
|
43
|
+
* globally, locally, or run via pnpm workspace symlink.
|
|
44
|
+
*/
|
|
45
|
+
function bundledPackRoot() {
|
|
46
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
47
|
+
// dist layout: dist/pattern-pack/index.js → dist/pattern-packs
|
|
48
|
+
return path.resolve(here, "../pattern-packs");
|
|
49
|
+
}
|
|
50
|
+
const DEFAULT_PACK_ID = "zivis-public";
|
|
51
|
+
// ── Loader ──
|
|
52
|
+
/**
|
|
53
|
+
* Locate the active pack and ensure it's available in the user cache.
|
|
54
|
+
*
|
|
55
|
+
* Resolution order:
|
|
56
|
+
* 1. ZIVIS_PACK_DIR env var (override for tests / enterprise air-gap imports)
|
|
57
|
+
* 2. User cache, if present
|
|
58
|
+
* 3. Bundled pack inside @zivis/mcp (copied to user cache on first use)
|
|
59
|
+
*/
|
|
60
|
+
export async function loadActivePack(packId = DEFAULT_PACK_ID) {
|
|
61
|
+
if (process.env.ZIVIS_PACK_DIR) {
|
|
62
|
+
return readManifest(process.env.ZIVIS_PACK_DIR);
|
|
63
|
+
}
|
|
64
|
+
const cached = await findCachedPack(packId);
|
|
65
|
+
if (cached) {
|
|
66
|
+
return readManifest(cached);
|
|
67
|
+
}
|
|
68
|
+
const bundledDir = await findBundledPack(packId);
|
|
69
|
+
if (!bundledDir) {
|
|
70
|
+
throw new Error(`No pattern pack found. Looked in user cache (${userPackRoot()}) and bundled location (${bundledPackRoot()}). ` +
|
|
71
|
+
`Set ZIVIS_PACK_DIR to override.`);
|
|
72
|
+
}
|
|
73
|
+
const handle = await readManifest(bundledDir);
|
|
74
|
+
const cacheDir = path.join(userPackRoot(), `${handle.manifest.pack_id}-${handle.manifest.version}`);
|
|
75
|
+
await copyDir(bundledDir, cacheDir);
|
|
76
|
+
return { manifest: handle.manifest, rootDir: cacheDir };
|
|
77
|
+
}
|
|
78
|
+
async function findCachedPack(packId) {
|
|
79
|
+
const root = userPackRoot();
|
|
80
|
+
if (!fssync.existsSync(root))
|
|
81
|
+
return undefined;
|
|
82
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
83
|
+
const candidates = entries
|
|
84
|
+
.filter((e) => e.isDirectory() && e.name.startsWith(`${packId}-`))
|
|
85
|
+
.map((e) => e.name)
|
|
86
|
+
.sort()
|
|
87
|
+
.reverse();
|
|
88
|
+
for (const name of candidates) {
|
|
89
|
+
const dir = path.join(root, name);
|
|
90
|
+
if (fssync.existsSync(path.join(dir, "manifest.json"))) {
|
|
91
|
+
return dir;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
async function findBundledPack(packId) {
|
|
97
|
+
const root = bundledPackRoot();
|
|
98
|
+
if (!fssync.existsSync(root))
|
|
99
|
+
return undefined;
|
|
100
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
101
|
+
const matches = entries
|
|
102
|
+
.filter((e) => e.isDirectory() && e.name.startsWith(`${packId}-`))
|
|
103
|
+
.map((e) => path.join(root, e.name))
|
|
104
|
+
.sort()
|
|
105
|
+
.reverse();
|
|
106
|
+
return matches[0];
|
|
107
|
+
}
|
|
108
|
+
async function readManifest(rootDir) {
|
|
109
|
+
const manifestPath = path.join(rootDir, "manifest.json");
|
|
110
|
+
const raw = await fs.readFile(manifestPath, "utf8");
|
|
111
|
+
const manifest = JSON.parse(raw);
|
|
112
|
+
return { manifest, rootDir };
|
|
113
|
+
}
|
|
114
|
+
async function copyDir(src, dst) {
|
|
115
|
+
await fs.mkdir(dst, { recursive: true });
|
|
116
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
117
|
+
await Promise.all(entries.map(async (entry) => {
|
|
118
|
+
const s = path.join(src, entry.name);
|
|
119
|
+
const d = path.join(dst, entry.name);
|
|
120
|
+
if (entry.isDirectory())
|
|
121
|
+
await copyDir(s, d);
|
|
122
|
+
else if (entry.isFile())
|
|
123
|
+
await fs.copyFile(s, d);
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
// ── Reader API ──
|
|
127
|
+
export async function getCapsule(handle, capsuleId) {
|
|
128
|
+
const entry = handle.manifest.capsules.find((c) => c.id === capsuleId);
|
|
129
|
+
if (!entry)
|
|
130
|
+
throw new Error(`Capsule not found in pack: ${capsuleId}`);
|
|
131
|
+
const fullPath = path.join(handle.rootDir, entry.path);
|
|
132
|
+
const raw = await fs.readFile(fullPath, "utf8");
|
|
133
|
+
await verifySha256(raw, entry.sha256, entry.path);
|
|
134
|
+
return yaml.load(raw);
|
|
135
|
+
}
|
|
136
|
+
export async function getInferencePrompt(handle, ref) {
|
|
137
|
+
const entry = handle.manifest.prompts.find((p) => p.path === ref);
|
|
138
|
+
if (!entry)
|
|
139
|
+
throw new Error(`Prompt not found in pack: ${ref}`);
|
|
140
|
+
const fullPath = path.join(handle.rootDir, ref);
|
|
141
|
+
const raw = await fs.readFile(fullPath, "utf8");
|
|
142
|
+
await verifySha256(raw, entry.sha256, ref);
|
|
143
|
+
return raw;
|
|
144
|
+
}
|
|
145
|
+
async function verifySha256(content, expected, label) {
|
|
146
|
+
const actual = crypto.createHash("sha256").update(content).digest("hex");
|
|
147
|
+
if (actual !== expected) {
|
|
148
|
+
throw new Error(`Pack integrity check failed for ${label}: expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
export async function listCapsuleIds(handle) {
|
|
152
|
+
return handle.manifest.capsules.map((c) => c.id);
|
|
153
|
+
}
|
|
154
|
+
// ── Relevance evaluation ──
|
|
155
|
+
export async function findRelevantCapsules(handle, artifact) {
|
|
156
|
+
const out = [];
|
|
157
|
+
const ctx = buildEvalContext(artifact);
|
|
158
|
+
for (const entry of handle.manifest.capsules) {
|
|
159
|
+
const cap = await getCapsule(handle, entry.id);
|
|
160
|
+
if (matchesRelevance(cap, ctx))
|
|
161
|
+
out.push(cap);
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
function buildEvalContext(artifact) {
|
|
166
|
+
const packageNames = new Set();
|
|
167
|
+
for (const node of artifact.nodes) {
|
|
168
|
+
if (node.type === "external_dependency" && node.attributes?.package) {
|
|
169
|
+
packageNames.add(node.attributes.package);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const languages = new Set(artifact.scope.languages ?? []);
|
|
173
|
+
const evidenceKinds = new Set();
|
|
174
|
+
for (const node of artifact.nodes) {
|
|
175
|
+
for (const ev of node.evidence)
|
|
176
|
+
evidenceKinds.add(ev.kind);
|
|
177
|
+
}
|
|
178
|
+
return { packageNames, languages, evidenceKinds };
|
|
179
|
+
}
|
|
180
|
+
export function matchesRelevance(cap, ctx) {
|
|
181
|
+
if (cap.applicable_languages.length > 0) {
|
|
182
|
+
const hit = cap.applicable_languages.some((l) => l === "cross" || ctx.languages.has(l));
|
|
183
|
+
if (!hit)
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
const f = cap.relevance_filter;
|
|
187
|
+
if (!f)
|
|
188
|
+
return true;
|
|
189
|
+
if (f.any_of && f.any_of.length > 0) {
|
|
190
|
+
if (!f.any_of.some((t) => evalTerm(t, ctx)))
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
if (f.all_of && f.all_of.length > 0) {
|
|
194
|
+
if (!f.all_of.every((t) => evalTerm(t, ctx)))
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
if (f.none_of && f.none_of.length > 0) {
|
|
198
|
+
if (f.none_of.some((t) => evalTerm(t, ctx)))
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
function evalTerm(term, ctx) {
|
|
204
|
+
if (term.dependency !== undefined)
|
|
205
|
+
return ctx.packageNames.has(term.dependency);
|
|
206
|
+
if (term.language !== undefined)
|
|
207
|
+
return ctx.languages.has(term.language);
|
|
208
|
+
if (term.evidence !== undefined)
|
|
209
|
+
return ctx.evidenceKinds.has(term.evidence);
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pattern-pack/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Detection Card: Privilege Separation (absent)
|
|
2
|
+
# Spec: docs/specs/PATTERN-MATCHING-LIBRARY-V1.md
|
|
3
|
+
# Schema: schemas/pattern-detection-card.schema.json
|
|
4
|
+
|
|
5
|
+
id: agents.privilege-separation
|
|
6
|
+
slug: privilege-separation
|
|
7
|
+
version: 0.1.0
|
|
8
|
+
category: agents
|
|
9
|
+
title: Privilege Separation
|
|
10
|
+
headline: Per-Subtask Capability Scoping
|
|
11
|
+
description: >
|
|
12
|
+
Detects agentic codebases where multiple agents share a single tool/capability
|
|
13
|
+
set without per-agent scoping. Absence of privilege separation means one
|
|
14
|
+
compromised agent inherits the full capability surface of the system.
|
|
15
|
+
detection_tier: public
|
|
16
|
+
scoring_tier: proprietary
|
|
17
|
+
|
|
18
|
+
applicable_languages:
|
|
19
|
+
- typescript
|
|
20
|
+
- javascript
|
|
21
|
+
- python
|
|
22
|
+
|
|
23
|
+
# Don't run this pattern unless an agent framework is actually present.
|
|
24
|
+
# Mirrors nuclei-style relevance gating to keep the noise floor low.
|
|
25
|
+
relevance_filter:
|
|
26
|
+
any_of:
|
|
27
|
+
- dependency: "langgraph"
|
|
28
|
+
direct_only: true
|
|
29
|
+
- dependency: "langchain"
|
|
30
|
+
direct_only: true
|
|
31
|
+
- dependency: "@langchain/langgraph"
|
|
32
|
+
direct_only: true
|
|
33
|
+
- dependency: "crewai"
|
|
34
|
+
direct_only: true
|
|
35
|
+
- dependency: "llama-index"
|
|
36
|
+
direct_only: true
|
|
37
|
+
- dependency: "openai-agents"
|
|
38
|
+
direct_only: true
|
|
39
|
+
- dependency: "autogen-agentchat"
|
|
40
|
+
direct_only: true
|
|
41
|
+
|
|
42
|
+
strategies:
|
|
43
|
+
# 1. AST: Find tool list assignments (Python — LangChain/LangGraph idiom).
|
|
44
|
+
- code: AST
|
|
45
|
+
language: python
|
|
46
|
+
expression: |
|
|
47
|
+
rule:
|
|
48
|
+
kind: assignment
|
|
49
|
+
pattern: $TOOLS = [$$$]
|
|
50
|
+
has:
|
|
51
|
+
stopBy: end
|
|
52
|
+
any:
|
|
53
|
+
- pattern: create_react_agent
|
|
54
|
+
- pattern: bind_tools
|
|
55
|
+
- pattern: AgentExecutor
|
|
56
|
+
evidence_fields: [file_path, line_span, symbol]
|
|
57
|
+
confidence_weight: 0.25
|
|
58
|
+
|
|
59
|
+
# 2. AST: TypeScript/JavaScript equivalent.
|
|
60
|
+
- code: AST
|
|
61
|
+
language: typescript
|
|
62
|
+
expression: |
|
|
63
|
+
rule:
|
|
64
|
+
any:
|
|
65
|
+
- pattern: const $TOOLS = [$$$]
|
|
66
|
+
- pattern: bindTools($$$)
|
|
67
|
+
- pattern: createReactAgent($$$)
|
|
68
|
+
evidence_fields: [file_path, line_span, symbol]
|
|
69
|
+
confidence_weight: 0.25
|
|
70
|
+
|
|
71
|
+
# 3. GRAPH: Two or more agent declarations share the same tool set.
|
|
72
|
+
# Predicate evaluated against extractor output (components/edges).
|
|
73
|
+
- code: GRAPH
|
|
74
|
+
expression: |
|
|
75
|
+
count(distinct agent_declaration) >= 2
|
|
76
|
+
AND any_pair(agents, lambda a, b: a.tool_set == b.tool_set)
|
|
77
|
+
evidence_fields: [graph_path, file_spans, node_ids]
|
|
78
|
+
confidence_weight: 0.35
|
|
79
|
+
|
|
80
|
+
# 4. META: Absence of per-agent capability scope OR explicit authz layer.
|
|
81
|
+
- code: META
|
|
82
|
+
expression: |
|
|
83
|
+
NOT exists_any_of(
|
|
84
|
+
per_agent_tool_filter,
|
|
85
|
+
capability_token_check,
|
|
86
|
+
authorization_layer_around_tool_dispatch,
|
|
87
|
+
langgraph_state_machine_with_per_node_tools
|
|
88
|
+
)
|
|
89
|
+
evidence_fields: [missing_controls]
|
|
90
|
+
confidence_weight: 0.30
|
|
91
|
+
|
|
92
|
+
# 5. INFER: Last-resort semantic check; never alone proves a finding.
|
|
93
|
+
- code: INFER
|
|
94
|
+
expression: "prompt_id:agents.privilege-separation.identify"
|
|
95
|
+
evidence_fields: [llm_rationale]
|
|
96
|
+
confidence_weight: 0.15
|
|
97
|
+
trusted: false
|
|
98
|
+
|
|
99
|
+
required_evidence_count: 3
|
|
100
|
+
|
|
101
|
+
# Presence of any of these controls downgrades or eliminates the finding.
|
|
102
|
+
control_negations:
|
|
103
|
+
- "presence_of(per_agent_tool_filter)"
|
|
104
|
+
- "presence_of(capability_token_check)"
|
|
105
|
+
- "presence_of(langgraph_state_machine_with_per_node_tools)"
|
|
106
|
+
|
|
107
|
+
threats:
|
|
108
|
+
- title: Compromised planner inherits executor capabilities
|
|
109
|
+
stride: [tampering, elevation_of_privilege]
|
|
110
|
+
description: >
|
|
111
|
+
A prompt-injection compromise of any agent escalates to the full set of
|
|
112
|
+
tools available to all agents in the system, including high-impact tools
|
|
113
|
+
like code execution, email, or file write.
|
|
114
|
+
remediation: >
|
|
115
|
+
Bind only the minimum tools required to each agent. In LangGraph, define
|
|
116
|
+
tools per node rather than globally. Add a capability token or
|
|
117
|
+
authorization layer that validates tool dispatch against agent identity.
|
|
118
|
+
- title: Lateral compromise via shared tool registry
|
|
119
|
+
stride: [elevation_of_privilege, information_disclosure]
|
|
120
|
+
description: >
|
|
121
|
+
Any tool callable from one agent is callable from every agent. There is
|
|
122
|
+
no blast-radius reduction even if one agent is otherwise constrained.
|
|
123
|
+
|
|
124
|
+
fixtures:
|
|
125
|
+
positive:
|
|
126
|
+
- "fixtures/positive/privilege-separation/langgraph_shared_tools_python"
|
|
127
|
+
- "fixtures/positive/privilege-separation/langchain_shared_tools_typescript"
|
|
128
|
+
negative:
|
|
129
|
+
- "fixtures/negative/privilege-separation/langgraph_per_node_tools"
|
|
130
|
+
- "fixtures/negative/privilege-separation/non_agentic_repo"
|
|
131
|
+
|
|
132
|
+
lifecycle: draft
|
|
133
|
+
owner: platform-threat-modeling
|
|
134
|
+
tags:
|
|
135
|
+
- agentic-ai
|
|
136
|
+
- least-privilege
|
|
137
|
+
- blast-radius
|
|
138
|
+
|
|
139
|
+
# Capsule fields — added in Phase 2A so the pack builder can ship this card
|
|
140
|
+
# as a runnable customer-safe capsule (deterministic strategies + inference prompt).
|
|
141
|
+
sensitivity_level: customer_safe
|
|
142
|
+
allowed_execution_modes:
|
|
143
|
+
- local_only
|
|
144
|
+
- local_model
|
|
145
|
+
- hybrid_cloud_eval
|
|
146
|
+
|
|
147
|
+
safe_summary: >
|
|
148
|
+
Multi-agent systems often share a single tool registry across agents. When that
|
|
149
|
+
happens, a prompt-injection compromise of any one agent inherits the full
|
|
150
|
+
capability surface of the system — including high-impact tools like code
|
|
151
|
+
execution, email, or filesystem write. Privilege separation means each agent
|
|
152
|
+
is bound only to the minimum tools required for its role.
|
|
153
|
+
|
|
154
|
+
detect_when: >
|
|
155
|
+
Two or more agent declarations are wired to the same tool list, or a single
|
|
156
|
+
shared tool array is referenced by every agent factory call, with no per-agent
|
|
157
|
+
capability scoping or authorization layer between agent and tool dispatch.
|
|
158
|
+
|
|
159
|
+
risk_hints:
|
|
160
|
+
- Any tool callable from one agent becomes callable from every agent
|
|
161
|
+
- Compromise of the weakest-prompted agent escalates to the most-privileged tool
|
|
162
|
+
- LangGraph's per-node tool binding is the idiomatic fix; AgentExecutor with a flat tool list is the anti-pattern
|
|
163
|
+
|
|
164
|
+
architectural_signals:
|
|
165
|
+
- Shared TOOLS array reused across multiple agent constructors
|
|
166
|
+
- No capability_token / authorization_layer between planner and tool dispatch
|
|
167
|
+
- LangGraph used without per-node tool binding
|
|
168
|
+
|
|
169
|
+
model_task_prompt_ref: prompts/agents/privilege-separation/identify.md
|
|
170
|
+
|
|
171
|
+
expected_output_schema:
|
|
172
|
+
type: object
|
|
173
|
+
required: [verdict, rationale, evidence_spans]
|
|
174
|
+
properties:
|
|
175
|
+
verdict:
|
|
176
|
+
type: string
|
|
177
|
+
enum: [present, absent, unclear]
|
|
178
|
+
description: present = privilege separation IS implemented; absent = the anti-pattern fires; unclear = needs human review
|
|
179
|
+
confidence:
|
|
180
|
+
type: number
|
|
181
|
+
minimum: 0
|
|
182
|
+
maximum: 1
|
|
183
|
+
rationale:
|
|
184
|
+
type: string
|
|
185
|
+
description: One paragraph, cites specific code constructs.
|
|
186
|
+
evidence_spans:
|
|
187
|
+
type: array
|
|
188
|
+
items:
|
|
189
|
+
type: object
|
|
190
|
+
required: [file]
|
|
191
|
+
properties:
|
|
192
|
+
file: { type: string }
|
|
193
|
+
start_line: { type: integer }
|
|
194
|
+
end_line: { type: integer }
|
|
195
|
+
note: { type: string }
|
|
196
|
+
|
|
197
|
+
minimum_context_required:
|
|
198
|
+
lines: 120
|
|
199
|
+
symbols:
|
|
200
|
+
- bind_tools
|
|
201
|
+
- bindTools
|
|
202
|
+
- create_react_agent
|
|
203
|
+
- createReactAgent
|
|
204
|
+
- AgentExecutor
|
|
205
|
+
|
|
206
|
+
related_patterns:
|
|
207
|
+
- agents.goal-decomposition-attack-surface
|
|
208
|
+
- agents.tool-call-without-authorization
|
|
209
|
+
|
|
210
|
+
repair_contract:
|
|
211
|
+
allowed:
|
|
212
|
+
- Bind a per-agent tool subset at construction time
|
|
213
|
+
- Introduce a capability-token or authorization layer between agent and tool dispatch
|
|
214
|
+
- Migrate to LangGraph state machines with per-node tools
|
|
215
|
+
forbidden:
|
|
216
|
+
- Removing tools entirely without functional replacement
|
|
217
|
+
- Centralizing tools further (the opposite direction)
|
|
218
|
+
- Disabling agent execution to "fix" the finding
|
|
219
|
+
|
|
220
|
+
validation_contract:
|
|
221
|
+
requires_tests_pass: false
|
|
222
|
+
requires_static_rules:
|
|
223
|
+
- no_shared_tool_registry_after_patch
|
|
224
|
+
|
|
225
|
+
unsafe_to_expose_fields:
|
|
226
|
+
- internal_rubric
|
|
227
|
+
- golden_transcripts
|
|
228
|
+
- exploit_templates
|