@inhuman.tools/policy 0.0.0-stage → 0.1.0
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/authorize.scm +4 -0
- package/dist/acknowledge.d.ts +70 -0
- package/dist/acknowledge.d.ts.map +1 -0
- package/dist/acknowledge.js +162 -0
- package/dist/acknowledge.js.map +1 -0
- package/dist/authorize.d.ts +8 -0
- package/dist/authorize.d.ts.map +1 -0
- package/dist/authorize.js +39 -0
- package/dist/authorize.js.map +1 -0
- package/dist/bind.d.ts +6 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +45 -0
- package/dist/bind.js.map +1 -0
- package/dist/check.d.ts +30 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +389 -0
- package/dist/check.js.map +1 -0
- package/dist/classes.d.ts +23 -0
- package/dist/classes.d.ts.map +1 -0
- package/dist/classes.js +139 -0
- package/dist/classes.js.map +1 -0
- package/dist/compile.d.ts +40 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +311 -0
- package/dist/compile.js.map +1 -0
- package/dist/deadline.d.ts +5 -0
- package/dist/deadline.d.ts.map +1 -0
- package/dist/deadline.js +17 -0
- package/dist/deadline.js.map +1 -0
- package/dist/decide.d.ts +64 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +482 -0
- package/dist/decide.js.map +1 -0
- package/dist/error-with-invariant.d.ts +9 -0
- package/dist/error-with-invariant.d.ts.map +1 -0
- package/dist/error-with-invariant.js +12 -0
- package/dist/error-with-invariant.js.map +1 -0
- package/dist/floor.d.ts +9 -0
- package/dist/floor.d.ts.map +1 -0
- package/dist/floor.js +9 -0
- package/dist/floor.js.map +1 -0
- package/dist/glob-expand.d.ts +10 -0
- package/dist/glob-expand.d.ts.map +1 -0
- package/dist/glob-expand.js +132 -0
- package/dist/glob-expand.js.map +1 -0
- package/dist/guards.d.ts +26 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +419 -0
- package/dist/guards.js.map +1 -0
- package/dist/identity.d.ts +11 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +23 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/license-law.d.ts +43 -0
- package/dist/license-law.d.ts.map +1 -0
- package/dist/license-law.js +129 -0
- package/dist/license-law.js.map +1 -0
- package/dist/license.d.ts +3 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +2 -0
- package/dist/license.js.map +1 -0
- package/dist/lift.d.ts +4 -0
- package/dist/lift.d.ts.map +1 -0
- package/dist/lift.js +14 -0
- package/dist/lift.js.map +1 -0
- package/dist/path-policy.d.ts +53 -0
- package/dist/path-policy.d.ts.map +1 -0
- package/dist/path-policy.js +248 -0
- package/dist/path-policy.js.map +1 -0
- package/dist/peel-cwd.d.ts +8 -0
- package/dist/peel-cwd.d.ts.map +1 -0
- package/dist/peel-cwd.js +120 -0
- package/dist/peel-cwd.js.map +1 -0
- package/dist/prep.d.ts +58 -0
- package/dist/prep.d.ts.map +1 -0
- package/dist/prep.js +690 -0
- package/dist/prep.js.map +1 -0
- package/dist/processor.d.ts +71 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +132 -0
- package/dist/processor.js.map +1 -0
- package/dist/reasonable-defaults.d.ts +1448 -0
- package/dist/reasonable-defaults.d.ts.map +1 -0
- package/dist/reasonable-defaults.js +6 -0
- package/dist/reasonable-defaults.js.map +1 -0
- package/dist/reasonable-defaults.json +1662 -0
- package/dist/run-authorization.d.ts +8 -0
- package/dist/run-authorization.d.ts.map +1 -0
- package/dist/run-authorization.js +16 -0
- package/dist/run-authorization.js.map +1 -0
- package/dist/schemas/tirith.d.ts +58 -0
- package/dist/schemas/tirith.d.ts.map +1 -0
- package/dist/schemas/tirith.js +23 -0
- package/dist/schemas/tirith.js.map +1 -0
- package/dist/tirith-units.d.ts +2 -0
- package/dist/tirith-units.d.ts.map +1 -0
- package/dist/tirith-units.js +227 -0
- package/dist/tirith-units.js.map +1 -0
- package/dist/tirith.d.ts +24 -0
- package/dist/tirith.d.ts.map +1 -0
- package/dist/tirith.js +311 -0
- package/dist/tirith.js.map +1 -0
- package/dist/tool-path.d.ts +8 -0
- package/dist/tool-path.d.ts.map +1 -0
- package/dist/tool-path.js +38 -0
- package/dist/tool-path.js.map +1 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +15 -0
- package/dist/verdict.d.ts.map +1 -0
- package/dist/verdict.js +55 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +62 -3
- package/src/acknowledge.ts +206 -0
- package/src/authorize.ts +38 -0
- package/src/bind.ts +58 -0
- package/src/check.ts +552 -0
- package/src/classes.ts +156 -0
- package/src/compile.ts +370 -0
- package/src/deadline.ts +15 -0
- package/src/floor.ts +16 -0
- package/src/glob-expand.ts +137 -0
- package/src/guards.ts +428 -0
- package/src/identity.ts +26 -0
- package/src/index.ts +24 -0
- package/src/lift.ts +15 -0
- package/src/path-policy.ts +280 -0
- package/src/processor.ts +187 -0
- package/src/reasonable-defaults.json +1662 -0
- package/src/reasonable-defaults.ts +8 -0
- package/src/run-authorization.ts +23 -0
- package/src/tool-path.ts +43 -0
- package/src/types.ts +102 -0
- package/src/verdict.ts +63 -0
- package/README.md +0 -3
package/authorize.scm
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ClassId } from "./classes.js";
|
|
2
|
+
import { type FloorVerdict } from "./types.js";
|
|
3
|
+
export type AckMatch = {
|
|
4
|
+
readonly class: ClassId;
|
|
5
|
+
} | {
|
|
6
|
+
readonly mcp: string;
|
|
7
|
+
readonly account?: string;
|
|
8
|
+
readonly tool?: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly tool: string;
|
|
11
|
+
} | {
|
|
12
|
+
readonly command: readonly string[];
|
|
13
|
+
};
|
|
14
|
+
export type AckFlag = {
|
|
15
|
+
readonly match: AckMatch;
|
|
16
|
+
readonly why?: string;
|
|
17
|
+
readonly modes?: readonly ("manual" | "auto" | "yolo")[];
|
|
18
|
+
};
|
|
19
|
+
/** Throws a readable error for an invalid block; `undefined` is no flags. */
|
|
20
|
+
export declare function parseAcknowledge(value: unknown): readonly AckFlag[];
|
|
21
|
+
/** A config file's text: a JSON array of flags, or an object with an `acknowledge` array. Empty text is none. */
|
|
22
|
+
export declare function parseAcknowledgeText(text: string | undefined): readonly AckFlag[];
|
|
23
|
+
/** Layer rule: the union. Project can add; nothing in it removes a user flag. */
|
|
24
|
+
export declare function mergeAcknowledge(...layers: readonly (readonly AckFlag[] | undefined)[]): readonly AckFlag[];
|
|
25
|
+
/** `mcp__server__tool` is the common MCP tool-name shape; hosts that spell it differently pass `mcp` themselves. */
|
|
26
|
+
export declare function mcpOf(toolName: string): {
|
|
27
|
+
readonly server: string;
|
|
28
|
+
readonly tool: string;
|
|
29
|
+
} | undefined;
|
|
30
|
+
export type AckSubject = {
|
|
31
|
+
readonly tool?: string;
|
|
32
|
+
readonly mcp?: {
|
|
33
|
+
readonly server: string;
|
|
34
|
+
readonly account?: string;
|
|
35
|
+
readonly tool?: string;
|
|
36
|
+
};
|
|
37
|
+
readonly verdict?: FloorVerdict;
|
|
38
|
+
};
|
|
39
|
+
export type AckRequirement = {
|
|
40
|
+
readonly labels: readonly string[];
|
|
41
|
+
readonly why: readonly string[];
|
|
42
|
+
};
|
|
43
|
+
export declare function labelOf(match: AckMatch): string;
|
|
44
|
+
/** Null when no flag matches. */
|
|
45
|
+
export declare function acknowledgeRequirement(flags: readonly AckFlag[], subject: AckSubject): AckRequirement | null;
|
|
46
|
+
/** Strictest floor verdict for a call, with the host path preparation the adapters use. */
|
|
47
|
+
export declare function floorVerdictOf(call: {
|
|
48
|
+
readonly kind: "bash";
|
|
49
|
+
readonly command: string;
|
|
50
|
+
readonly cwd?: string;
|
|
51
|
+
} | {
|
|
52
|
+
readonly kind: "read" | "write";
|
|
53
|
+
readonly path: string;
|
|
54
|
+
readonly cwd?: string;
|
|
55
|
+
}): FloorVerdict;
|
|
56
|
+
export declare function blockReason(requirement: AckRequirement): string;
|
|
57
|
+
export type AckRequest = {
|
|
58
|
+
readonly summary: string;
|
|
59
|
+
readonly detail: string;
|
|
60
|
+
readonly why?: string;
|
|
61
|
+
};
|
|
62
|
+
export type Acknowledger = (request: AckRequest) => Promise<boolean>;
|
|
63
|
+
/** `text` is what the agent wrote (a command, a path, arguments). It is JSON-encoded and truncated. */
|
|
64
|
+
export declare function acknowledgeRequest(requirement: AckRequirement, tool: string, text: string): AckRequest;
|
|
65
|
+
/**
|
|
66
|
+
* Ask the host. Undefined means acknowledged and the call may run; a string is the denial reason.
|
|
67
|
+
* No `acknowledger` is the degraded path: the reason is `needs acknowledgement: <label>`.
|
|
68
|
+
*/
|
|
69
|
+
export declare function requestAcknowledgement(requirement: AckRequirement, tool: string, text: string, acknowledger: Acknowledger | undefined): Promise<string | undefined>;
|
|
70
|
+
//# sourceMappingURL=acknowledge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acknowledge.d.ts","sourceRoot":"","sources":["../src/acknowledge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `needsAcknowledgement` for the adapters. One place for the flag schema, the matcher and the texts;
|
|
3
|
+
* an adapter only asks "does this call need an acknowledgement" and translates the answer into its
|
|
4
|
+
* host's confirmation mechanism.
|
|
5
|
+
*
|
|
6
|
+
* A flag forces a request for a call that would otherwise run (floor approve, judge allow, any
|
|
7
|
+
* resolution to allow). It never turns a block or a denial into anything. Flags only tighten:
|
|
8
|
+
* the effective set is the union of the user and project layers, so a project file can add and
|
|
9
|
+
* can never remove a user flag. The dist ships none.
|
|
10
|
+
*
|
|
11
|
+
* Adapters have no `modes` of their own, so `modes` is accepted (the schema is the daemon's) and
|
|
12
|
+
* ignored: a flag applies in every adapter.
|
|
13
|
+
*
|
|
14
|
+
* `class` matches the classes of the floor votes (`classesOf`). An approve has no classes, so a
|
|
15
|
+
* class flag only matches a call whose floor tier is ask or deny. `command` matches a prefix of
|
|
16
|
+
* `[argv0, ...spine, ...familyArgs]` of any shell unit in `verdict.seen`, so approved calls match.
|
|
17
|
+
*/
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { defaultPolicy } from "./bind.js";
|
|
20
|
+
import { CLASS_IDS } from "./classes.js";
|
|
21
|
+
import { lattice } from "./lift.js";
|
|
22
|
+
import { normalizeToolPath } from "./tool-path.js";
|
|
23
|
+
import { classesOf } from "./types.js";
|
|
24
|
+
import { join } from "./verdict.js";
|
|
25
|
+
const classIdSchema = z.enum(CLASS_IDS);
|
|
26
|
+
const matchSchema = z.union([
|
|
27
|
+
z.strictObject({ class: classIdSchema }),
|
|
28
|
+
z.strictObject({ mcp: z.string().min(1), account: z.string().min(1).optional(), tool: z.string().min(1).optional() }),
|
|
29
|
+
z.strictObject({ tool: z.string().min(1) }),
|
|
30
|
+
z.strictObject({ command: z.array(z.string().min(1)).min(1) }),
|
|
31
|
+
]);
|
|
32
|
+
const flagSchema = z.strictObject({
|
|
33
|
+
match: matchSchema,
|
|
34
|
+
why: z.string().max(200).optional(),
|
|
35
|
+
modes: z.array(z.enum(["manual", "auto", "yolo"])).optional(),
|
|
36
|
+
});
|
|
37
|
+
/** Throws a readable error for an invalid block; `undefined` is no flags. */
|
|
38
|
+
export function parseAcknowledge(value) {
|
|
39
|
+
if (value === undefined)
|
|
40
|
+
return [];
|
|
41
|
+
const parsed = z.array(flagSchema).safeParse(value);
|
|
42
|
+
if (!parsed.success) {
|
|
43
|
+
const issue = parsed.error.issues[0];
|
|
44
|
+
throw new Error(`invalid acknowledge config: ${issue === undefined ? "bad shape" : `${issue.path.join(".") || "(root)"}: ${issue.message}`}`);
|
|
45
|
+
}
|
|
46
|
+
return parsed.data;
|
|
47
|
+
}
|
|
48
|
+
/** A config file's text: a JSON array of flags, or an object with an `acknowledge` array. Empty text is none. */
|
|
49
|
+
export function parseAcknowledgeText(text) {
|
|
50
|
+
if (text === undefined || text.trim() === "")
|
|
51
|
+
return [];
|
|
52
|
+
let raw;
|
|
53
|
+
try {
|
|
54
|
+
raw = JSON.parse(text);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
throw new Error("invalid acknowledge config: not json");
|
|
58
|
+
}
|
|
59
|
+
if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) {
|
|
60
|
+
return parseAcknowledge(raw.acknowledge);
|
|
61
|
+
}
|
|
62
|
+
return parseAcknowledge(raw);
|
|
63
|
+
}
|
|
64
|
+
/** Layer rule: the union. Project can add; nothing in it removes a user flag. */
|
|
65
|
+
export function mergeAcknowledge(...layers) {
|
|
66
|
+
const out = new Map();
|
|
67
|
+
for (const layer of layers)
|
|
68
|
+
for (const flag of layer ?? [])
|
|
69
|
+
out.set(JSON.stringify([flag.match, flag.why]), flag);
|
|
70
|
+
return [...out.values()];
|
|
71
|
+
}
|
|
72
|
+
/** `mcp__server__tool` is the common MCP tool-name shape; hosts that spell it differently pass `mcp` themselves. */
|
|
73
|
+
export function mcpOf(toolName) {
|
|
74
|
+
const found = /^mcp__(.+?)__(.+)$/.exec(toolName);
|
|
75
|
+
return found?.[1] === undefined || found[2] === undefined ? undefined : { server: found[1], tool: found[2] };
|
|
76
|
+
}
|
|
77
|
+
export function labelOf(match) {
|
|
78
|
+
if ("class" in match)
|
|
79
|
+
return `class ${match.class}`;
|
|
80
|
+
if ("command" in match)
|
|
81
|
+
return `command ${match.command.join(" ")}`;
|
|
82
|
+
if ("mcp" in match) {
|
|
83
|
+
return `mcp ${[match.mcp, match.tool].filter((part) => part !== undefined).join("/")}`;
|
|
84
|
+
}
|
|
85
|
+
return `tool ${match.tool}`;
|
|
86
|
+
}
|
|
87
|
+
function matches(match, subject) {
|
|
88
|
+
if ("class" in match)
|
|
89
|
+
return subject.verdict !== undefined && classesOf(subject.verdict).includes(match.class);
|
|
90
|
+
if ("command" in match) {
|
|
91
|
+
const units = subject.verdict?.seen ?? [];
|
|
92
|
+
return units.some((unit) => {
|
|
93
|
+
const identity = [unit.argv0, ...unit.spine, ...unit.familyArgs];
|
|
94
|
+
return match.command.length <= identity.length && match.command.every((word, i) => identity[i] === word);
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const mcp = subject.mcp ?? (subject.tool === undefined ? undefined : mcpOf(subject.tool));
|
|
98
|
+
if ("mcp" in match) {
|
|
99
|
+
return (mcp !== undefined &&
|
|
100
|
+
mcp.server === match.mcp &&
|
|
101
|
+
(match.tool === undefined || mcp.tool === match.tool) &&
|
|
102
|
+
(match.account === undefined || ("account" in mcp && mcp.account === match.account)));
|
|
103
|
+
}
|
|
104
|
+
return subject.tool === match.tool || (mcp !== undefined && mcp.tool === match.tool);
|
|
105
|
+
}
|
|
106
|
+
/** Null when no flag matches. */
|
|
107
|
+
export function acknowledgeRequirement(flags, subject) {
|
|
108
|
+
const labels = [];
|
|
109
|
+
const why = [];
|
|
110
|
+
for (const flag of flags) {
|
|
111
|
+
if (!matches(flag.match, subject))
|
|
112
|
+
continue;
|
|
113
|
+
const label = labelOf(flag.match);
|
|
114
|
+
if (!labels.includes(label))
|
|
115
|
+
labels.push(label);
|
|
116
|
+
if (flag.why !== undefined && !why.includes(flag.why))
|
|
117
|
+
why.push(flag.why);
|
|
118
|
+
}
|
|
119
|
+
return labels.length === 0 ? null : { labels, why };
|
|
120
|
+
}
|
|
121
|
+
/** Strictest floor verdict for a call, with the host path preparation the adapters use. */
|
|
122
|
+
export function floorVerdictOf(call) {
|
|
123
|
+
if (call.kind === "bash")
|
|
124
|
+
return defaultPolicy.explainBash(call.command, undefined);
|
|
125
|
+
const prepared = normalizeToolPath(call.path, call.cwd);
|
|
126
|
+
const explain = call.kind === "read" ? defaultPolicy.explainRead : defaultPolicy.explainWrite;
|
|
127
|
+
const first = explain(prepared);
|
|
128
|
+
const second = explain(prepared.toLowerCase());
|
|
129
|
+
const top = lattice([first.disposition, second.disposition]);
|
|
130
|
+
return join([first, second].filter((verdict) => verdict.disposition === top));
|
|
131
|
+
}
|
|
132
|
+
export function blockReason(requirement) {
|
|
133
|
+
return `needs acknowledgement: ${requirement.labels.join(", ")}`;
|
|
134
|
+
}
|
|
135
|
+
const DETAIL_LIMIT = 500;
|
|
136
|
+
/** `text` is what the agent wrote (a command, a path, arguments). It is JSON-encoded and truncated. */
|
|
137
|
+
export function acknowledgeRequest(requirement, tool, text) {
|
|
138
|
+
const encoded = JSON.stringify(text);
|
|
139
|
+
const detail = encoded.length > DETAIL_LIMIT ? `${encoded.slice(0, DETAIL_LIMIT)}...` : encoded;
|
|
140
|
+
const why = requirement.why.length === 0 ? undefined : requirement.why.join("; ");
|
|
141
|
+
return {
|
|
142
|
+
summary: `Acknowledge ${tool}: ${requirement.labels.join(", ")}`,
|
|
143
|
+
detail,
|
|
144
|
+
...(why === undefined ? {} : { why }),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Ask the host. Undefined means acknowledged and the call may run; a string is the denial reason.
|
|
149
|
+
* No `acknowledger` is the degraded path: the reason is `needs acknowledgement: <label>`.
|
|
150
|
+
*/
|
|
151
|
+
export async function requestAcknowledgement(requirement, tool, text, acknowledger) {
|
|
152
|
+
if (acknowledger === undefined)
|
|
153
|
+
return blockReason(requirement);
|
|
154
|
+
try {
|
|
155
|
+
const accepted = await acknowledger(acknowledgeRequest(requirement, tool, text));
|
|
156
|
+
return accepted ? undefined : `acknowledgement declined: ${requirement.labels.join(", ")}`;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return `acknowledgement failed: ${requirement.labels.join(", ")}`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=acknowledge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acknowledge.js","sourceRoot":"","sources":["../src/acknowledge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ErrorWithInvariant } from "@inhuman.tools/error-with-invariant";
|
|
2
|
+
export declare class DecideError extends ErrorWithInvariant {
|
|
3
|
+
readonly name = "DecideError";
|
|
4
|
+
}
|
|
5
|
+
export declare function authorizationProgram(): string;
|
|
6
|
+
/** A set `POLICY_AUTHORIZE` that cannot be read is an error, not the dist script. */
|
|
7
|
+
export declare function authorizationSource(override?: string, env?: NodeJS.ProcessEnv): string;
|
|
8
|
+
//# sourceMappingURL=authorize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,qBAAa,WAAY,SAAQ,kBAAkB;IACjD,SAAkB,IAAI,iBAAiB;CACxC;AAMD,wBAAgB,oBAAoB,IAAI,MAAM,CAI7C;AAED,qFAAqF;AACrF,wBAAgB,mBAAmB,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAgBtF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { ErrorWithInvariant } from "@inhuman.tools/error-with-invariant";
|
|
5
|
+
export class DecideError extends ErrorWithInvariant {
|
|
6
|
+
name = "DecideError";
|
|
7
|
+
}
|
|
8
|
+
const programPath = path.join(path.dirname(fileURLToPath(import.meta.url)), "../authorize.scm");
|
|
9
|
+
let cached;
|
|
10
|
+
export function authorizationProgram() {
|
|
11
|
+
if (cached !== undefined)
|
|
12
|
+
return cached;
|
|
13
|
+
cached = readFileSync(programPath, "utf8");
|
|
14
|
+
return cached;
|
|
15
|
+
}
|
|
16
|
+
/** A set `POLICY_AUTHORIZE` that cannot be read is an error, not the dist script. */
|
|
17
|
+
export function authorizationSource(override, env) {
|
|
18
|
+
const inline = override?.trim();
|
|
19
|
+
if (inline)
|
|
20
|
+
return inline;
|
|
21
|
+
const file = env?.POLICY_AUTHORIZE?.trim();
|
|
22
|
+
if (file === undefined || file === "")
|
|
23
|
+
return authorizationProgram();
|
|
24
|
+
let text;
|
|
25
|
+
try {
|
|
26
|
+
text = readFileSync(file, "utf8");
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : undefined;
|
|
30
|
+
if (code === "ENOENT")
|
|
31
|
+
throw new DecideError(`authorization program not found: ${file}`);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
const source = text.trim();
|
|
35
|
+
if (source === "")
|
|
36
|
+
throw new DecideError("authorization program is empty");
|
|
37
|
+
return text;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=authorize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../src/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAEzE,MAAM,OAAO,WAAY,SAAQ,kBAAkB;IAC/B,IAAI,GAAG,aAAa,CAAC;CACxC;AAED,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;AAEhG,IAAI,MAA0B,CAAC;AAE/B,MAAM,UAAU,oBAAoB;IAClC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC3C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,mBAAmB,CAAC,QAAiB,EAAE,GAAuB;IAC5E,MAAM,MAAM,GAAG,QAAQ,EAAE,IAAI,EAAE,CAAC;IAChC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAG,GAAG,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,oBAAoB,EAAE,CAAC;IACrE,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACrG,IAAI,IAAI,KAAK,QAAQ;YAAE,MAAM,IAAI,WAAW,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC;QACzF,MAAM,KAAK,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,MAAM,KAAK,EAAE;QAAE,MAAM,IAAI,WAAW,CAAC,gCAAgC,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/bind.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Which } from "./identity.js";
|
|
2
|
+
import { type Policy } from "./types.js";
|
|
3
|
+
export declare function bindPolicy(document: unknown, which?: Which): Policy;
|
|
4
|
+
/** Dist floor. A path-form argv0 stays a path: this binding has no `which`. */
|
|
5
|
+
export declare const defaultPolicy: Policy;
|
|
6
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,EAAgC,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AAKvE,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,GAAE,KAAkB,GAAG,MAAM,CA4C/E;AAED,+EAA+E;AAC/E,eAAO,MAAM,aAAa,EAAE,MAAuC,CAAC"}
|
package/dist/bind.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { explainBash } from "./check.js";
|
|
2
|
+
import { compilePolicy, PolicyAssumeError } from "./compile.js";
|
|
3
|
+
import { explainPath, writeRemainderKind } from "./path-policy.js";
|
|
4
|
+
import { reasonableDefaults } from "./reasonable-defaults.js";
|
|
5
|
+
import { classesOf } from "./types.js";
|
|
6
|
+
import { cast } from "./verdict.js";
|
|
7
|
+
const unresolved = () => undefined;
|
|
8
|
+
export function bindPolicy(document, which = unresolved) {
|
|
9
|
+
const compiled = compilePolicy(document);
|
|
10
|
+
const clusters = { read: compiled.read, write: compiled.write };
|
|
11
|
+
const bash = (command, cwd) => compiled.bash === undefined
|
|
12
|
+
? cast("ask", "unmodelled", "bash:no-policy")
|
|
13
|
+
: explainBash(compiled.bash, command, clusters, which, cwd);
|
|
14
|
+
for (const smoke of compiled.assume) {
|
|
15
|
+
const verdict = bash(smoke.command);
|
|
16
|
+
const actual = verdict.disposition;
|
|
17
|
+
PolicyAssumeError.invariant(actual === smoke.expect, `assume: expected ${smoke.expect}, got ${actual}: ${smoke.command}`, {
|
|
18
|
+
expected: smoke.expect,
|
|
19
|
+
actual,
|
|
20
|
+
command: smoke.command,
|
|
21
|
+
});
|
|
22
|
+
if (smoke.expectClass !== undefined) {
|
|
23
|
+
const classes = classesOf(verdict);
|
|
24
|
+
PolicyAssumeError.invariant(classes.includes(smoke.expectClass), `assume: expected class ${smoke.expectClass}, got ${classes.join(",") || "none"}: ${smoke.command}`, { expected: smoke.expect, actual, command: smoke.command });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const path = (cluster) => {
|
|
28
|
+
const term = cluster === "read" ? compiled.read : compiled.write;
|
|
29
|
+
return (raw) => term === undefined ? cast("ask", "unmodelled", `${cluster}:no-policy`) : explainPath(term, raw);
|
|
30
|
+
};
|
|
31
|
+
const explainRead = path("read");
|
|
32
|
+
const explainWrite = path("write");
|
|
33
|
+
return {
|
|
34
|
+
bash: (command, cwd) => bash(command, cwd).disposition,
|
|
35
|
+
explainBash: bash,
|
|
36
|
+
read: (raw) => explainRead(raw).disposition,
|
|
37
|
+
explainRead,
|
|
38
|
+
write: (raw) => explainWrite(raw).disposition,
|
|
39
|
+
explainWrite,
|
|
40
|
+
writeKind: (raw) => (compiled.write === undefined ? null : writeRemainderKind(compiled.write, raw)),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Dist floor. A path-form argv0 stays a path: this binding has no `which`. */
|
|
44
|
+
export const defaultPolicy = bindPolicy(reasonableDefaults);
|
|
45
|
+
//# sourceMappingURL=bind.js.map
|
package/dist/bind.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.js","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"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"}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String processors over a compiled YAML term. Prep, unparsed→ask, empty I→ask,
|
|
3
|
+
* and the pipeline lattice live here — not on the host.
|
|
4
|
+
*
|
|
5
|
+
* Shape (policy / matcher / subcommands) is one vote. File effects from
|
|
6
|
+
* arg_types / arg_rest_type join on their own lattice — they cannot lift ask.
|
|
7
|
+
* `"--"` present: suffix is re-parsed with that body's flag vocabulary
|
|
8
|
+
* (undeclared dash tokens stay positionals). `"--"` absent: cutoff, consume
|
|
9
|
+
* the delimiter, leftovers are positionals.
|
|
10
|
+
*
|
|
11
|
+
* Every vote carries the class of the rule that cast it (see classes.ts). The verdict of a call
|
|
12
|
+
* is the strictest disposition plus the votes at exactly that disposition (verdict.ts `join`).
|
|
13
|
+
*/
|
|
14
|
+
import { type Which } from "./identity.js";
|
|
15
|
+
import { type PathTerm } from "./path-policy.js";
|
|
16
|
+
import type { CommandNode, Disposition, FloorVerdict } from "./types.js";
|
|
17
|
+
type PathClusters = {
|
|
18
|
+
readonly read?: PathTerm;
|
|
19
|
+
readonly write?: PathTerm;
|
|
20
|
+
/** Workspace-relative (or extra-root absolute) directory the shell runs in. Relative path tokens re-base on it. */
|
|
21
|
+
readonly cwd?: string;
|
|
22
|
+
/** The shell would expand this question's words (an argument is not literal). */
|
|
23
|
+
readonly expand?: boolean;
|
|
24
|
+
/** `dotglob` is mentioned in the command: `*` may match a leading dot. */
|
|
25
|
+
readonly dotglob?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export declare function checkBash(term: CommandNode, command: string, clusters?: PathClusters, which?: Which, cwd?: string): Disposition;
|
|
28
|
+
export declare function explainBash(term: CommandNode, command: string, clusters?: PathClusters, which?: Which, cwd?: string): FloorVerdict;
|
|
29
|
+
export { explainPath } from "./path-policy.js";
|
|
30
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAQH,OAAO,EAAgB,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAEV,WAAW,EACX,WAAW,EAEX,YAAY,EAIb,MAAM,YAAY,CAAC;AAGpB,KAAK,YAAY,GAAG;IAClB,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,mHAAmH;IACnH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AA+CF,wBAAgB,SAAS,CACvB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,YAAiB,EAC3B,KAAK,CAAC,EAAE,KAAK,EACb,GAAG,CAAC,EAAE,MAAM,GACX,WAAW,CAEb;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,YAAiB,EAC3B,KAAK,CAAC,EAAE,KAAK,EACb,GAAG,CAAC,EAAE,MAAM,GACX,YAAY,CAmDd;AA0YD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|