@praxis.guard/auditor-cli 0.0.45 → 0.0.47
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/README.md +11 -4
- package/dist/adapters/claude-code/adapter.d.ts +28 -0
- package/dist/adapters/claude-code/adapter.d.ts.map +1 -0
- package/dist/adapters/claude-code/adapter.js +141 -0
- package/dist/adapters/claude-code/adapter.js.map +1 -0
- package/dist/adapters/claude-code/config-detect.d.ts +4 -0
- package/dist/adapters/claude-code/config-detect.d.ts.map +1 -0
- package/dist/adapters/claude-code/config-detect.js +44 -0
- package/dist/adapters/claude-code/config-detect.js.map +1 -0
- package/dist/adapters/claude-code/config-io.d.ts +8 -0
- package/dist/adapters/claude-code/config-io.d.ts.map +1 -0
- package/dist/adapters/claude-code/config-io.js +41 -0
- package/dist/adapters/claude-code/config-io.js.map +1 -0
- package/dist/adapters/claude-code/index.d.ts +3 -0
- package/dist/adapters/claude-code/index.d.ts.map +1 -0
- package/dist/adapters/claude-code/index.js +3 -0
- package/dist/adapters/claude-code/index.js.map +1 -0
- package/dist/adapters/claude-code/paths.d.ts +17 -0
- package/dist/adapters/claude-code/paths.d.ts.map +1 -0
- package/dist/adapters/claude-code/paths.js +32 -0
- package/dist/adapters/claude-code/paths.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +1 -33
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +1 -246
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex.d.ts +11 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +52 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +2 -0
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/select-targets.js +3 -3
- package/dist/adapters/select-targets.js.map +1 -1
- package/dist/adapters/types.d.ts +9 -2
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/bridge/execution-ticket-consume.d.ts +12 -0
- package/dist/bridge/execution-ticket-consume.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-consume.js +105 -0
- package/dist/bridge/execution-ticket-consume.js.map +1 -0
- package/dist/bridge/execution-ticket-match.d.ts +4 -0
- package/dist/bridge/execution-ticket-match.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-match.js +40 -0
- package/dist/bridge/execution-ticket-match.js.map +1 -0
- package/dist/bridge/execution-ticket-record.d.ts +14 -0
- package/dist/bridge/execution-ticket-record.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-record.js +51 -0
- package/dist/bridge/execution-ticket-record.js.map +1 -0
- package/dist/bridge/execution-ticket.d.ts +2 -23
- package/dist/bridge/execution-ticket.d.ts.map +1 -1
- package/dist/bridge/execution-ticket.js +2 -179
- package/dist/bridge/execution-ticket.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +17 -13
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/help.js +4 -4
- package/dist/cli/setup-all.d.ts.map +1 -1
- package/dist/cli/setup-all.js +6 -2
- package/dist/cli/setup-all.js.map +1 -1
- package/dist/cli/setup-codex.d.ts.map +1 -1
- package/dist/cli/setup-codex.js +4 -3
- package/dist/cli/setup-codex.js.map +1 -1
- package/dist/cli/setup-doctor.d.ts.map +1 -1
- package/dist/cli/setup-doctor.js +22 -7
- package/dist/cli/setup-doctor.js.map +1 -1
- package/dist/cli/setup-mcp.d.ts +1 -0
- package/dist/cli/setup-mcp.d.ts.map +1 -1
- package/dist/cli/setup-mcp.js +15 -2
- package/dist/cli/setup-mcp.js.map +1 -1
- package/dist/codex/config.d.ts +1 -0
- package/dist/codex/config.d.ts.map +1 -1
- package/dist/codex/config.js +23 -1
- package/dist/codex/config.js.map +1 -1
- package/dist/codex/evaluate-tool-audit.d.ts +29 -0
- package/dist/codex/evaluate-tool-audit.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-audit.js +58 -0
- package/dist/codex/evaluate-tool-audit.js.map +1 -0
- package/dist/codex/evaluate-tool-bash.d.ts +3 -0
- package/dist/codex/evaluate-tool-bash.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-bash.js +50 -0
- package/dist/codex/evaluate-tool-bash.js.map +1 -0
- package/dist/codex/evaluate-tool-mcp.d.ts +3 -0
- package/dist/codex/evaluate-tool-mcp.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-mcp.js +55 -0
- package/dist/codex/evaluate-tool-mcp.js.map +1 -0
- package/dist/codex/evaluate-tool-types.d.ts +27 -0
- package/dist/codex/evaluate-tool-types.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-types.js +15 -0
- package/dist/codex/evaluate-tool-types.js.map +1 -0
- package/dist/codex/evaluate-tool.d.ts +3 -26
- package/dist/codex/evaluate-tool.d.ts.map +1 -1
- package/dist/codex/evaluate-tool.js +3 -167
- package/dist/codex/evaluate-tool.js.map +1 -1
- package/dist/policy/classify.d.ts +9 -0
- package/dist/policy/classify.d.ts.map +1 -0
- package/dist/policy/classify.js +97 -0
- package/dist/policy/classify.js.map +1 -0
- package/dist/policy/index.d.ts +5 -54
- package/dist/policy/index.d.ts.map +1 -1
- package/dist/policy/index.js +4 -213
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/load.d.ts +8 -0
- package/dist/policy/load.d.ts.map +1 -0
- package/dist/policy/load.js +52 -0
- package/dist/policy/load.js.map +1 -0
- package/dist/policy/paths.d.ts +9 -0
- package/dist/policy/paths.d.ts.map +1 -0
- package/dist/policy/paths.js +42 -0
- package/dist/policy/paths.js.map +1 -0
- package/dist/policy/schema.d.ts +35 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +30 -0
- package/dist/policy/schema.js.map +1 -0
- package/package.json +1 -1
|
@@ -1,171 +1,7 @@
|
|
|
1
|
-
import { appendAuditJsonl } from "../audit/jsonl.js";
|
|
2
|
-
import { toolInputSha256 } from "../approval/fingerprint.js";
|
|
3
1
|
import { resolveGuardStorageRoot } from "../bridge/guard-storage-root.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
import { loadPoliciesV1, readPoliciesV1Revision } from "../policy/index.js";
|
|
8
|
-
import { analyzeShellCommand } from "../shell/analyze-command.js";
|
|
9
|
-
import { commandMayContainGovernedTool } from "../shell/governed-tools.js";
|
|
10
|
-
import { evaluateMcpProposal } from "../shell/evaluate.js";
|
|
11
|
-
import { sendGuardEvent } from "../telemetry/guard-events.js";
|
|
12
|
-
import { recordCodexPermissionHandoff } from "./permission-handoff.js";
|
|
13
|
-
export function parseCodexMcpToolName(toolName) {
|
|
14
|
-
if (!toolName.startsWith("mcp__"))
|
|
15
|
-
return null;
|
|
16
|
-
const parts = toolName.slice("mcp__".length).split("__");
|
|
17
|
-
if (parts.length < 2)
|
|
18
|
-
return null;
|
|
19
|
-
return { server: parts.slice(0, -1).join("__") || "stdio", tool: parts.at(-1) || "_" };
|
|
20
|
-
}
|
|
21
|
-
export function isPraxisGuardTool(toolName) {
|
|
22
|
-
const identity = parseCodexMcpToolName(toolName);
|
|
23
|
-
if (!identity || (identity.tool !== "guard" && identity.tool !== "guard_wait"))
|
|
24
|
-
return false;
|
|
25
|
-
return /^praxis(?:-|_)guard$/i.test(identity.server);
|
|
26
|
-
}
|
|
27
|
-
function codexReason(input) {
|
|
28
|
-
const formatted = formatHookDenyMessages({
|
|
29
|
-
hook: input.kind === "shell" ? "beforeShellExecution" : "beforeMCPExecution",
|
|
30
|
-
tier: input.tier,
|
|
31
|
-
argv: input.argv,
|
|
32
|
-
reasons: input.reasons,
|
|
33
|
-
toolName: input.toolName,
|
|
34
|
-
inlineApproval: input.inlineApproval,
|
|
35
|
-
});
|
|
36
|
-
return formatted.agent_message;
|
|
37
|
-
}
|
|
38
|
-
async function auditAndSend(input) {
|
|
39
|
-
const event = {
|
|
40
|
-
ts: new Date().toISOString(),
|
|
41
|
-
hook: "codexPreToolUse",
|
|
42
|
-
agent: "codex-app",
|
|
43
|
-
tool_name: input.payload.tool_name,
|
|
44
|
-
tool_input: input.payload.tool_input,
|
|
45
|
-
argv: input.argv,
|
|
46
|
-
tier: input.tier,
|
|
47
|
-
decision: input.allowed ? "allow" : "block",
|
|
48
|
-
governed: input.governed,
|
|
49
|
-
ticketConsumed: input.ticketConsumed,
|
|
50
|
-
reasons: input.reasons,
|
|
51
|
-
latency_ms: input.latencyMs,
|
|
52
|
-
};
|
|
53
|
-
await appendAuditJsonl(event, input.storageRoot).catch((error) => {
|
|
54
|
-
process.stderr.write(`[auditor] audit log append failed: ${String(error)}\n`);
|
|
55
|
-
});
|
|
56
|
-
await sendGuardEvent({
|
|
57
|
-
...event,
|
|
58
|
-
status: input.allowed ? "passed" : "blocked",
|
|
59
|
-
tool: input.kind === "shell" ? "auditor-hook" : "auditor-hook-mcp",
|
|
60
|
-
command_path: input.argv[0] ?? null,
|
|
61
|
-
verb: input.argv[1] ?? null,
|
|
62
|
-
resource: input.argv.slice(2).join(" ") || null,
|
|
63
|
-
kind: input.kind,
|
|
64
|
-
...(input.policyRevision !== null ? { policy_revision: input.policyRevision } : {}),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function shellReasons(analysis) {
|
|
68
|
-
const reasons = [];
|
|
69
|
-
if (!analysis.primary.evaluation.classification.matched)
|
|
70
|
-
reasons.push("unknown_command(default_deny)");
|
|
71
|
-
if (analysis.primary.evaluation.flags.metacharacters || analysis.raw_metacharacters)
|
|
72
|
-
reasons.push("metacharacters");
|
|
73
|
-
if (analysis.primary.evaluation.flags.dangerous_flags)
|
|
74
|
-
reasons.push("dangerous_flags");
|
|
75
|
-
if (analysis.fail_closed)
|
|
76
|
-
reasons.push("unparseable(fail_closed)");
|
|
77
|
-
if (analysis.invocations.length > 1)
|
|
78
|
-
reasons.push(`multiple_governed_invocations(${analysis.invocations.length})`);
|
|
79
|
-
return reasons;
|
|
80
|
-
}
|
|
81
|
-
async function evaluateBash(payload, started) {
|
|
82
|
-
const command = payload.tool_input && typeof payload.tool_input === "object"
|
|
83
|
-
? payload.tool_input.command
|
|
84
|
-
: undefined;
|
|
85
|
-
const rawCommand = typeof command === "string" ? command : "";
|
|
86
|
-
const storageRoot = resolveGuardStorageRoot(payload.cwd);
|
|
87
|
-
if (!rawCommand || !commandMayContainGovernedTool(rawCommand)) {
|
|
88
|
-
return { governed: false, allowed: true, tier: "READ", argv: [], storageRoot };
|
|
89
|
-
}
|
|
90
|
-
const [policy, policyRevision] = await Promise.all([loadPoliciesV1(), readPoliciesV1Revision()]);
|
|
91
|
-
const analysis = analyzeShellCommand(rawCommand, policy);
|
|
92
|
-
if (analysis.skipped) {
|
|
93
|
-
return { governed: false, allowed: true, tier: "READ", argv: [], storageRoot };
|
|
94
|
-
}
|
|
95
|
-
const argv = analysis.primary.canonical_argv;
|
|
96
|
-
const tier = analysis.tier;
|
|
97
|
-
const reasons = shellReasons(analysis);
|
|
98
|
-
let allowed = tier === "READ";
|
|
99
|
-
let ticketConsumed = false;
|
|
100
|
-
let inlineApproval = null;
|
|
101
|
-
if (tier === "MUTATE") {
|
|
102
|
-
const mutate = await resolveShellMutateHookPermission({
|
|
103
|
-
tier,
|
|
104
|
-
argv,
|
|
105
|
-
analysis,
|
|
106
|
-
storageRoot,
|
|
107
|
-
rawDisplay: rawCommand,
|
|
108
|
-
policyRevision,
|
|
109
|
-
initialReasons: reasons,
|
|
110
|
-
});
|
|
111
|
-
allowed = mutate.permission === "allow";
|
|
112
|
-
ticketConsumed = mutate.ticketConsumed;
|
|
113
|
-
inlineApproval = mutate.inlineApproval;
|
|
114
|
-
reasons.splice(0, reasons.length, ...mutate.reasons);
|
|
115
|
-
}
|
|
116
|
-
if (ticketConsumed) {
|
|
117
|
-
await recordCodexPermissionHandoff({ storageRoot, argv, turnId: payload.turn_id });
|
|
118
|
-
}
|
|
119
|
-
const reason = allowed ? undefined : codexReason({ kind: "shell", tier, argv, reasons, inlineApproval });
|
|
120
|
-
await auditAndSend({ payload, kind: "shell", tier, argv, allowed, governed: true, ticketConsumed, reasons, policyRevision, storageRoot, latencyMs: performance.now() - started });
|
|
121
|
-
return { governed: true, allowed, tier, argv, reason, storageRoot };
|
|
122
|
-
}
|
|
123
|
-
async function evaluateMcp(payload, started) {
|
|
124
|
-
const toolName = payload.tool_name ?? "";
|
|
125
|
-
const identity = parseCodexMcpToolName(toolName);
|
|
126
|
-
const storageRoot = resolveGuardStorageRoot(payload.cwd);
|
|
127
|
-
if (!identity || isPraxisGuardTool(toolName)) {
|
|
128
|
-
return { governed: false, allowed: true, tier: "READ", argv: [], storageRoot };
|
|
129
|
-
}
|
|
130
|
-
const argv = ["mcp", identity.server, identity.tool];
|
|
131
|
-
const [policy, policyRevision] = await Promise.all([loadPoliciesV1(), readPoliciesV1Revision()]);
|
|
132
|
-
const { skipped, evaluation } = evaluateMcpProposal(policy, argv);
|
|
133
|
-
if (skipped)
|
|
134
|
-
return { governed: false, allowed: true, tier: "READ", argv, storageRoot };
|
|
135
|
-
const tier = evaluation.tier;
|
|
136
|
-
const reasons = evaluation.reasons.map((reason) => reason.message);
|
|
137
|
-
const toolInputHash = toolInputSha256(payload.tool_input);
|
|
138
|
-
let allowed = tier === "READ";
|
|
139
|
-
let ticketConsumed = false;
|
|
140
|
-
let inlineApproval = null;
|
|
141
|
-
if (tier === "MUTATE") {
|
|
142
|
-
const mutate = await resolveMutateHookPermission({
|
|
143
|
-
argv,
|
|
144
|
-
tier,
|
|
145
|
-
storageRoot,
|
|
146
|
-
toolInputHash,
|
|
147
|
-
rawToolName: toolName,
|
|
148
|
-
toolInputPreview: JSON.stringify(payload.tool_input ?? {}).slice(0, 200),
|
|
149
|
-
policyRevision,
|
|
150
|
-
initialReasons: reasons,
|
|
151
|
-
});
|
|
152
|
-
allowed = mutate.permission === "allow";
|
|
153
|
-
ticketConsumed = mutate.ticketConsumed;
|
|
154
|
-
inlineApproval = mutate.inlineApproval;
|
|
155
|
-
reasons.splice(0, reasons.length, ...mutate.reasons);
|
|
156
|
-
}
|
|
157
|
-
if (ticketConsumed) {
|
|
158
|
-
await recordCodexPermissionHandoff({
|
|
159
|
-
storageRoot,
|
|
160
|
-
argv,
|
|
161
|
-
toolInputHash,
|
|
162
|
-
turnId: payload.turn_id,
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
const reason = allowed ? undefined : codexReason({ kind: "mcp", tier, argv, reasons, toolName, inlineApproval });
|
|
166
|
-
await auditAndSend({ payload, kind: "mcp", tier, argv, allowed, governed: true, ticketConsumed, reasons, policyRevision, storageRoot, latencyMs: performance.now() - started });
|
|
167
|
-
return { governed: true, allowed, tier, argv, reason, storageRoot, toolInputHash };
|
|
168
|
-
}
|
|
2
|
+
import { evaluateBash } from "./evaluate-tool-bash.js";
|
|
3
|
+
import { evaluateMcp } from "./evaluate-tool-mcp.js";
|
|
4
|
+
export { isPraxisGuardTool, parseCodexMcpToolName } from "./evaluate-tool-types.js";
|
|
169
5
|
export async function evaluateCodexTool(payload) {
|
|
170
6
|
const started = performance.now();
|
|
171
7
|
if (payload.tool_name === "Bash")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evaluate-tool.js","sourceRoot":"","sources":["../../src/codex/evaluate-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"evaluate-tool.js","sourceRoot":"","sources":["../../src/codex/evaluate-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAIrD,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAyB;IAC/D,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;IAClC,IAAI,OAAO,CAAC,SAAS,KAAK,MAAM;QAAE,OAAO,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxE,IAAI,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACjF,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE;QACR,WAAW,EAAE,uBAAuB,CAAC,OAAO,CAAC,GAAG,CAAC;KAClD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Classification, PoliciesV1 } from "./schema.js";
|
|
2
|
+
export declare function classifyArgv(policy: PoliciesV1, argv: readonly string[]): {
|
|
3
|
+
classification: Classification;
|
|
4
|
+
flags: {
|
|
5
|
+
metacharacters: boolean;
|
|
6
|
+
dangerous_flags: boolean;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/policy/classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAQ,MAAM,aAAa,CAAC;AA0BpE,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB;IAAE,cAAc,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE;QAAE,cAAc,EAAE,OAAO,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAoFlG"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
function hasMetacharacters(argv) {
|
|
2
|
+
const bad = [";", "&&", "||", "|", "`", "$(", ">", "<"];
|
|
3
|
+
return argv.some((t) => bad.some((b) => t.includes(b)));
|
|
4
|
+
}
|
|
5
|
+
function hasDangerousFlags(argv, dangerousFlags) {
|
|
6
|
+
const s = new Set(dangerousFlags);
|
|
7
|
+
return argv.some((t) => s.has(t));
|
|
8
|
+
}
|
|
9
|
+
function tryMultiTokenVerb(verbsToTiers, rest, verbIndex, verb1) {
|
|
10
|
+
if (!verb1)
|
|
11
|
+
return verb1;
|
|
12
|
+
const verb2 = rest[verbIndex + 1];
|
|
13
|
+
if (!verb2)
|
|
14
|
+
return verb1;
|
|
15
|
+
const combined = `${verb1} ${verb2}`;
|
|
16
|
+
if (verbsToTiers[combined])
|
|
17
|
+
return combined;
|
|
18
|
+
return verb1;
|
|
19
|
+
}
|
|
20
|
+
export function classifyArgv(policy, argv) {
|
|
21
|
+
const tool = argv[0] ?? null;
|
|
22
|
+
const metacharacters = hasMetacharacters(argv);
|
|
23
|
+
const dangerous_flags = hasDangerousFlags(argv, policy.dangerous_flags);
|
|
24
|
+
if (!tool || !policy.policies[tool]) {
|
|
25
|
+
return {
|
|
26
|
+
classification: { tool, command_path: null, verb: null, tier: "MUTATE", matched: false },
|
|
27
|
+
flags: { metacharacters, dangerous_flags },
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const rest = argv.slice(1);
|
|
31
|
+
const toolTable = policy.policies[tool];
|
|
32
|
+
if (rest.length === 0) {
|
|
33
|
+
const root = toolTable["__root__"];
|
|
34
|
+
const tier = root?.["__default__"];
|
|
35
|
+
if (tier) {
|
|
36
|
+
return {
|
|
37
|
+
classification: { tool, command_path: "__root__", verb: null, tier, matched: true },
|
|
38
|
+
flags: { metacharacters, dangerous_flags },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (rest.length > 0 && toolTable["__root__"]) {
|
|
43
|
+
const root = toolTable["__root__"];
|
|
44
|
+
const verb = rest[0] ?? null;
|
|
45
|
+
let tier;
|
|
46
|
+
if (verb) {
|
|
47
|
+
tier = root[verb];
|
|
48
|
+
if (tier === undefined)
|
|
49
|
+
tier = root["*"];
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
tier = root["__default__"];
|
|
53
|
+
}
|
|
54
|
+
if (tier !== undefined) {
|
|
55
|
+
return {
|
|
56
|
+
classification: { tool, command_path: "__root__", verb, tier, matched: true },
|
|
57
|
+
flags: { metacharacters, dangerous_flags },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const pathKeys = Object.keys(toolTable).sort((a, b) => b.split(" ").length - a.split(" ").length);
|
|
62
|
+
for (const pathKey of pathKeys) {
|
|
63
|
+
const k = pathKey.split(" ");
|
|
64
|
+
const prefix = rest.slice(0, k.length);
|
|
65
|
+
const matches = k.length > 0 && prefix.length === k.length && prefix.every((t, i) => t === k[i]);
|
|
66
|
+
if (!matches)
|
|
67
|
+
continue;
|
|
68
|
+
const verbIndex = k.length;
|
|
69
|
+
const verb1 = rest[verbIndex] ?? null;
|
|
70
|
+
const verbsToTiers = toolTable[pathKey] ?? {};
|
|
71
|
+
const verb = tryMultiTokenVerb(verbsToTiers, rest, verbIndex, verb1);
|
|
72
|
+
let tier;
|
|
73
|
+
if (verb) {
|
|
74
|
+
tier = verbsToTiers[verb];
|
|
75
|
+
if (tier === undefined)
|
|
76
|
+
tier = verbsToTiers["*"];
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
tier = verbsToTiers["__default__"];
|
|
80
|
+
}
|
|
81
|
+
if (tier === undefined) {
|
|
82
|
+
return {
|
|
83
|
+
classification: { tool, command_path: pathKey, verb, tier: "MUTATE", matched: false },
|
|
84
|
+
flags: { metacharacters, dangerous_flags },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
classification: { tool, command_path: pathKey, verb, tier, matched: true },
|
|
89
|
+
flags: { metacharacters, dangerous_flags },
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
classification: { tool, command_path: rest[0] ?? null, verb: rest[1] ?? null, tier: "MUTATE", matched: false },
|
|
94
|
+
flags: { metacharacters, dangerous_flags },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=classify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/policy/classify.ts"],"names":[],"mappings":"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"}
|
package/dist/policy/index.d.ts
CHANGED
|
@@ -1,55 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}>;
|
|
7
|
-
export type Tier = z.infer<typeof TierSchema>;
|
|
8
|
-
export declare const PoliciesV1Schema: z.ZodObject<{
|
|
9
|
-
tiers: z.ZodArray<z.ZodEnum<{
|
|
10
|
-
READ: "READ";
|
|
11
|
-
MUTATE: "MUTATE";
|
|
12
|
-
DESTRUCTIVE: "DESTRUCTIVE";
|
|
13
|
-
}>>;
|
|
14
|
-
dangerous_flags: z.ZodArray<z.ZodString>;
|
|
15
|
-
policies: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
16
|
-
READ: "READ";
|
|
17
|
-
MUTATE: "MUTATE";
|
|
18
|
-
DESTRUCTIVE: "DESTRUCTIVE";
|
|
19
|
-
}>>>>;
|
|
20
|
-
shell: z.ZodOptional<z.ZodObject<{
|
|
21
|
-
prelude_verbs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
22
|
-
privilege_verbs: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
23
|
-
}, z.core.$strip>>;
|
|
24
|
-
}, z.core.$strip>;
|
|
25
|
-
export type PoliciesV1 = z.infer<typeof PoliciesV1Schema>;
|
|
26
|
-
export type Classification = {
|
|
27
|
-
tool: string | null;
|
|
28
|
-
command_path: string | null;
|
|
29
|
-
verb: string | null;
|
|
30
|
-
tier: Tier;
|
|
31
|
-
matched: boolean;
|
|
32
|
-
};
|
|
33
|
-
export declare function ensureTiersComplete(tiers: readonly Tier[]): void;
|
|
34
|
-
export declare function parsePoliciesV1Json(raw: unknown): PoliciesV1;
|
|
35
|
-
export declare function defaultPoliciesV1Path(): string;
|
|
36
|
-
/** Effective path when `opts.policyPath` is omitted (env override matches `auditor doctor` / help). */
|
|
37
|
-
export declare function resolvedPoliciesV1Path(opts?: {
|
|
38
|
-
policyPath?: string;
|
|
39
|
-
}): string;
|
|
40
|
-
export declare function policiesV1MetaPathFor(policyFilePath: string): string;
|
|
41
|
-
export declare function defaultPoliciesMetaPath(): string;
|
|
42
|
-
export declare function readPoliciesV1Revision(opts?: {
|
|
43
|
-
policyPath?: string;
|
|
44
|
-
}): Promise<number | null>;
|
|
45
|
-
export declare function loadPoliciesV1(opts?: {
|
|
46
|
-
policyPath?: string;
|
|
47
|
-
}): Promise<PoliciesV1>;
|
|
48
|
-
export declare function classifyArgv(policy: PoliciesV1, argv: readonly string[]): {
|
|
49
|
-
classification: Classification;
|
|
50
|
-
flags: {
|
|
51
|
-
metacharacters: boolean;
|
|
52
|
-
dangerous_flags: boolean;
|
|
53
|
-
};
|
|
54
|
-
};
|
|
1
|
+
export type { Classification, PoliciesV1, Tier } from "./schema.js";
|
|
2
|
+
export { parsePoliciesV1Json } from "./schema.js";
|
|
3
|
+
export { defaultPoliciesMetaPath, defaultPoliciesV1Path, policiesV1MetaPathFor, resolvedPoliciesV1Path, } from "./paths.js";
|
|
4
|
+
export { loadPoliciesV1, readPoliciesV1Revision } from "./load.js";
|
|
5
|
+
export { classifyArgv } from "./classify.js";
|
|
55
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/policy/index.js
CHANGED
|
@@ -1,214 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
export const TierSchema = z.enum(["READ", "MUTATE", "DESTRUCTIVE"]);
|
|
8
|
-
export const PoliciesV1Schema = z.object({
|
|
9
|
-
tiers: z.array(TierSchema).nonempty(),
|
|
10
|
-
dangerous_flags: z.array(z.string()),
|
|
11
|
-
policies: z.record(z.string(), z.record(z.string(), z.record(z.string(), TierSchema))),
|
|
12
|
-
shell: z
|
|
13
|
-
.object({
|
|
14
|
-
prelude_verbs: z.array(z.string()).optional(),
|
|
15
|
-
privilege_verbs: z.array(z.string()).optional(),
|
|
16
|
-
})
|
|
17
|
-
.optional(),
|
|
18
|
-
});
|
|
19
|
-
export function ensureTiersComplete(tiers) {
|
|
20
|
-
const s = new Set(tiers);
|
|
21
|
-
for (const required of ["READ", "MUTATE", "DESTRUCTIVE"]) {
|
|
22
|
-
if (!s.has(required)) {
|
|
23
|
-
throw new Error(`policies.v1.json tiers missing: ${required}`);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
export function parsePoliciesV1Json(raw) {
|
|
28
|
-
const parsed = PoliciesV1Schema.safeParse(raw);
|
|
29
|
-
if (!parsed.success) {
|
|
30
|
-
throw new Error(`Invalid policies: ${parsed.error.message}`);
|
|
31
|
-
}
|
|
32
|
-
ensureTiersComplete(parsed.data.tiers);
|
|
33
|
-
return parsed.data;
|
|
34
|
-
}
|
|
35
|
-
function bundledPoliciesCandidates() {
|
|
36
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
37
|
-
return [
|
|
38
|
-
path.resolve(here, "../policies.v1.json"),
|
|
39
|
-
path.resolve(here, "../../../auditor/policies.v1.json"),
|
|
40
|
-
];
|
|
41
|
-
}
|
|
42
|
-
function resolveBundledPoliciesPath() {
|
|
43
|
-
for (const candidate of bundledPoliciesCandidates()) {
|
|
44
|
-
if (existsSync(candidate))
|
|
45
|
-
return candidate;
|
|
46
|
-
}
|
|
47
|
-
throw new Error(`No bundled policies.v1.json found. Tried:\n${bundledPoliciesCandidates().map((p) => ` - ${p}`).join("\n")}`);
|
|
48
|
-
}
|
|
49
|
-
function defaultPraxisDir() {
|
|
50
|
-
return path.join(os.homedir(), ".praxis");
|
|
51
|
-
}
|
|
52
|
-
export function defaultPoliciesV1Path() {
|
|
53
|
-
return path.join(defaultPraxisDir(), "policies.v1.json");
|
|
54
|
-
}
|
|
55
|
-
/** Effective path when `opts.policyPath` is omitted (env override matches `auditor doctor` / help). */
|
|
56
|
-
export function resolvedPoliciesV1Path(opts) {
|
|
57
|
-
if (opts?.policyPath?.trim())
|
|
58
|
-
return opts.policyPath.trim();
|
|
59
|
-
const fromEnv = process.env.PRAXIS_POLICIES_V1_PATH?.trim();
|
|
60
|
-
if (fromEnv)
|
|
61
|
-
return fromEnv;
|
|
62
|
-
return defaultPoliciesV1Path();
|
|
63
|
-
}
|
|
64
|
-
export function policiesV1MetaPathFor(policyFilePath) {
|
|
65
|
-
const dir = path.dirname(policyFilePath);
|
|
66
|
-
const base = path.basename(policyFilePath, ".json");
|
|
67
|
-
return path.join(dir, `${base}.meta.json`);
|
|
68
|
-
}
|
|
69
|
-
export function defaultPoliciesMetaPath() {
|
|
70
|
-
return policiesV1MetaPathFor(defaultPoliciesV1Path());
|
|
71
|
-
}
|
|
72
|
-
export async function readPoliciesV1Revision(opts) {
|
|
73
|
-
const policyPath = resolvedPoliciesV1Path(opts);
|
|
74
|
-
const metaPath = policiesV1MetaPathFor(policyPath);
|
|
75
|
-
try {
|
|
76
|
-
const raw = await readFile(metaPath, "utf8");
|
|
77
|
-
const parsed = JSON.parse(raw);
|
|
78
|
-
const r = Number(parsed.revision);
|
|
79
|
-
return Number.isFinite(r) ? r : null;
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
async function bootstrapPoliciesIfMissing(policyPath) {
|
|
86
|
-
if (existsSync(policyPath))
|
|
87
|
-
return;
|
|
88
|
-
const bundledPath = resolveBundledPoliciesPath();
|
|
89
|
-
const dir = path.dirname(policyPath);
|
|
90
|
-
await mkdir(dir, { recursive: true });
|
|
91
|
-
const tmpPolicy = `${policyPath}.tmp.${process.pid}`;
|
|
92
|
-
await copyFile(bundledPath, tmpPolicy);
|
|
93
|
-
await rename(tmpPolicy, policyPath);
|
|
94
|
-
const metaPath = policiesV1MetaPathFor(policyPath);
|
|
95
|
-
if (!existsSync(metaPath)) {
|
|
96
|
-
const bootstrapMeta = {
|
|
97
|
-
revision: 0,
|
|
98
|
-
syncedAt: new Date().toISOString(),
|
|
99
|
-
source: "bundled-bootstrap",
|
|
100
|
-
};
|
|
101
|
-
const tmpMeta = `${metaPath}.tmp.${process.pid}`;
|
|
102
|
-
await writeFile(tmpMeta, `${JSON.stringify(bootstrapMeta, null, 2)}\n`, "utf8");
|
|
103
|
-
await rename(tmpMeta, metaPath);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export async function loadPoliciesV1(opts) {
|
|
107
|
-
const policyPath = resolvedPoliciesV1Path(opts);
|
|
108
|
-
await bootstrapPoliciesIfMissing(policyPath);
|
|
109
|
-
const raw = await readFile(policyPath, "utf8");
|
|
110
|
-
try {
|
|
111
|
-
return parsePoliciesV1Json(JSON.parse(raw));
|
|
112
|
-
}
|
|
113
|
-
catch (e) {
|
|
114
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
115
|
-
throw new Error(`Invalid policies file at ${policyPath}: ${msg}`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function hasMetacharacters(argv) {
|
|
119
|
-
const bad = [";", "&&", "||", "|", "`", "$(", ">", "<"];
|
|
120
|
-
return argv.some((t) => bad.some((b) => t.includes(b)));
|
|
121
|
-
}
|
|
122
|
-
function hasDangerousFlags(argv, dangerousFlags) {
|
|
123
|
-
const s = new Set(dangerousFlags);
|
|
124
|
-
return argv.some((t) => s.has(t));
|
|
125
|
-
}
|
|
126
|
-
function tryMultiTokenVerb(verbsToTiers, rest, verbIndex, verb1) {
|
|
127
|
-
if (!verb1)
|
|
128
|
-
return verb1;
|
|
129
|
-
const verb2 = rest[verbIndex + 1];
|
|
130
|
-
if (!verb2)
|
|
131
|
-
return verb1;
|
|
132
|
-
const combined = `${verb1} ${verb2}`;
|
|
133
|
-
if (verbsToTiers[combined])
|
|
134
|
-
return combined;
|
|
135
|
-
return verb1;
|
|
136
|
-
}
|
|
137
|
-
export function classifyArgv(policy, argv) {
|
|
138
|
-
const tool = argv[0] ?? null;
|
|
139
|
-
const metacharacters = hasMetacharacters(argv);
|
|
140
|
-
const dangerous_flags = hasDangerousFlags(argv, policy.dangerous_flags);
|
|
141
|
-
if (!tool || !policy.policies[tool]) {
|
|
142
|
-
return {
|
|
143
|
-
classification: { tool, command_path: null, verb: null, tier: "MUTATE", matched: false },
|
|
144
|
-
flags: { metacharacters, dangerous_flags },
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
const rest = argv.slice(1);
|
|
148
|
-
const toolTable = policy.policies[tool];
|
|
149
|
-
if (rest.length === 0) {
|
|
150
|
-
const root = toolTable["__root__"];
|
|
151
|
-
const tier = root?.["__default__"];
|
|
152
|
-
if (tier) {
|
|
153
|
-
return {
|
|
154
|
-
classification: { tool, command_path: "__root__", verb: null, tier, matched: true },
|
|
155
|
-
flags: { metacharacters, dangerous_flags },
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (rest.length > 0 && toolTable["__root__"]) {
|
|
160
|
-
const root = toolTable["__root__"];
|
|
161
|
-
const verb = rest[0] ?? null;
|
|
162
|
-
let tier;
|
|
163
|
-
if (verb) {
|
|
164
|
-
tier = root[verb];
|
|
165
|
-
if (tier === undefined)
|
|
166
|
-
tier = root["*"];
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
tier = root["__default__"];
|
|
170
|
-
}
|
|
171
|
-
if (tier !== undefined) {
|
|
172
|
-
return {
|
|
173
|
-
classification: { tool, command_path: "__root__", verb, tier, matched: true },
|
|
174
|
-
flags: { metacharacters, dangerous_flags },
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
const pathKeys = Object.keys(toolTable).sort((a, b) => b.split(" ").length - a.split(" ").length);
|
|
179
|
-
for (const pathKey of pathKeys) {
|
|
180
|
-
const k = pathKey.split(" ");
|
|
181
|
-
const prefix = rest.slice(0, k.length);
|
|
182
|
-
const matches = k.length > 0 && prefix.length === k.length && prefix.every((t, i) => t === k[i]);
|
|
183
|
-
if (!matches)
|
|
184
|
-
continue;
|
|
185
|
-
const verbIndex = k.length;
|
|
186
|
-
const verb1 = rest[verbIndex] ?? null;
|
|
187
|
-
const verbsToTiers = toolTable[pathKey] ?? {};
|
|
188
|
-
const verb = tryMultiTokenVerb(verbsToTiers, rest, verbIndex, verb1);
|
|
189
|
-
let tier;
|
|
190
|
-
if (verb) {
|
|
191
|
-
tier = verbsToTiers[verb];
|
|
192
|
-
if (tier === undefined)
|
|
193
|
-
tier = verbsToTiers["*"];
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
tier = verbsToTiers["__default__"];
|
|
197
|
-
}
|
|
198
|
-
if (tier === undefined) {
|
|
199
|
-
return {
|
|
200
|
-
classification: { tool, command_path: pathKey, verb, tier: "MUTATE", matched: false },
|
|
201
|
-
flags: { metacharacters, dangerous_flags },
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
return {
|
|
205
|
-
classification: { tool, command_path: pathKey, verb, tier, matched: true },
|
|
206
|
-
flags: { metacharacters, dangerous_flags },
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
return {
|
|
210
|
-
classification: { tool, command_path: rest[0] ?? null, verb: rest[1] ?? null, tier: "MUTATE", matched: false },
|
|
211
|
-
flags: { metacharacters, dangerous_flags },
|
|
212
|
-
};
|
|
213
|
-
}
|
|
1
|
+
export { parsePoliciesV1Json } from "./schema.js";
|
|
2
|
+
export { defaultPoliciesMetaPath, defaultPoliciesV1Path, policiesV1MetaPathFor, resolvedPoliciesV1Path, } from "./paths.js";
|
|
3
|
+
export { loadPoliciesV1, readPoliciesV1Revision } from "./load.js";
|
|
4
|
+
export { classifyArgv } from "./classify.js";
|
|
214
5
|
//# sourceMappingURL=index.js.map
|
package/dist/policy/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/policy/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type PoliciesV1 } from "./schema.js";
|
|
2
|
+
export declare function readPoliciesV1Revision(opts?: {
|
|
3
|
+
policyPath?: string;
|
|
4
|
+
}): Promise<number | null>;
|
|
5
|
+
export declare function loadPoliciesV1(opts?: {
|
|
6
|
+
policyPath?: string;
|
|
7
|
+
}): Promise<PoliciesV1>;
|
|
8
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/policy/load.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAGnE,wBAAsB,sBAAsB,CAAC,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWnG;AA0BD,wBAAsB,cAAc,CAAC,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAUxF"}
|