pi-daddy 0.17.0 → 0.18.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/CHANGELOG.md +154 -80
- package/README.md +54 -25
- package/dist/approval-prompt.d.ts +3 -1
- package/dist/approval-prompt.d.ts.map +1 -1
- package/dist/approval-prompt.js +1 -1
- package/dist/approval-prompt.js.map +1 -1
- package/dist/approval-store.d.ts.map +1 -1
- package/dist/approval-store.js +4 -1
- package/dist/approval-store.js.map +1 -1
- package/dist/approval.d.ts +20 -2
- package/dist/approval.d.ts.map +1 -1
- package/dist/approval.js +26 -6
- package/dist/approval.js.map +1 -1
- package/dist/chain.d.ts +6 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/chain.js +1 -1
- package/dist/chain.js.map +1 -1
- package/dist/check-runner.d.ts +61 -0
- package/dist/check-runner.d.ts.map +1 -0
- package/dist/check-runner.js +237 -0
- package/dist/check-runner.js.map +1 -0
- package/dist/correlation.d.ts +90 -0
- package/dist/correlation.d.ts.map +1 -0
- package/dist/correlation.js +183 -0
- package/dist/correlation.js.map +1 -0
- package/dist/delegate-types.d.ts +140 -0
- package/dist/delegate-types.d.ts.map +1 -0
- package/dist/delegate-types.js +8 -0
- package/dist/delegate-types.js.map +1 -0
- package/dist/delegate.d.ts +4 -128
- package/dist/delegate.d.ts.map +1 -1
- package/dist/delegate.js +68 -72
- package/dist/delegate.js.map +1 -1
- package/dist/delegation-approval.d.ts +36 -0
- package/dist/delegation-approval.d.ts.map +1 -0
- package/dist/delegation-approval.js +67 -0
- package/dist/delegation-approval.js.map +1 -0
- package/dist/git-identity.d.ts +13 -0
- package/dist/git-identity.d.ts.map +1 -0
- package/dist/git-identity.js +44 -0
- package/dist/git-identity.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lease-record.d.ts +78 -0
- package/dist/lease-record.d.ts.map +1 -0
- package/dist/lease-record.js +52 -0
- package/dist/lease-record.js.map +1 -0
- package/dist/ledger-events.d.ts +87 -0
- package/dist/ledger-events.d.ts.map +1 -0
- package/dist/ledger-events.js +45 -0
- package/dist/ledger-events.js.map +1 -0
- package/dist/ledger-report.d.ts +19 -12
- package/dist/ledger-report.d.ts.map +1 -1
- package/dist/ledger-report.js +81 -1
- package/dist/ledger-report.js.map +1 -1
- package/dist/ledger.d.ts +44 -1
- package/dist/ledger.d.ts.map +1 -1
- package/dist/ledger.js +20 -2
- package/dist/ledger.js.map +1 -1
- package/dist/refusals.d.ts +16 -0
- package/dist/refusals.d.ts.map +1 -0
- package/dist/refusals.js +51 -0
- package/dist/refusals.js.map +1 -0
- package/dist/run-child.d.ts +4 -0
- package/dist/run-child.d.ts.map +1 -1
- package/dist/run-child.js +21 -1
- package/dist/run-child.js.map +1 -1
- package/dist/run-herdr.d.ts +7 -0
- package/dist/run-herdr.d.ts.map +1 -1
- package/dist/run-herdr.js +41 -12
- package/dist/run-herdr.js.map +1 -1
- package/dist/workspace-lease.d.ts +28 -0
- package/dist/workspace-lease.d.ts.map +1 -0
- package/dist/workspace-lease.js +276 -0
- package/dist/workspace-lease.js.map +1 -0
- package/dist/workspace.d.ts +32 -0
- package/dist/workspace.d.ts.map +1 -0
- package/dist/workspace.js +79 -0
- package/dist/workspace.js.map +1 -0
- package/extensions/approval-banking.ts +66 -0
- package/extensions/approvals.ts +95 -7
- package/extensions/chain-approval-facts.ts +51 -0
- package/extensions/chain-ledger.ts +48 -0
- package/extensions/delegate-chain.ts +115 -81
- package/extensions/delegation.ts +81 -23
- package/extensions/execute-child.ts +289 -0
- package/extensions/fanout-outcome.ts +97 -0
- package/extensions/run-delegation.ts +130 -120
- package/extensions/session.ts +4 -0
- package/extensions/workspace-runtime.ts +165 -0
- package/package.json +17 -1
- package/src/approval-prompt.ts +4 -2
- package/src/approval-store.ts +4 -1
- package/src/approval.ts +47 -14
- package/src/chain.ts +3 -1
- package/src/check-runner.ts +341 -0
- package/src/correlation.ts +260 -0
- package/src/delegate-types.ts +144 -0
- package/src/delegate.ts +80 -179
- package/src/delegation-approval.ts +99 -0
- package/src/git-identity.ts +52 -0
- package/src/index.ts +50 -0
- package/src/lease-record.ts +119 -0
- package/src/ledger-events.ts +138 -0
- package/src/ledger-report.ts +90 -2
- package/src/ledger.ts +68 -3
- package/src/refusals.ts +66 -0
- package/src/run-child.ts +23 -1
- package/src/run-herdr.ts +41 -11
- package/src/workspace-lease.ts +303 -0
- package/src/workspace.ts +135 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-lease.js","sourceRoot":"","sources":["../src/workspace-lease.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export declare const ENV_WORKSPACE_REGISTRY = "PI_GRANTS_WORKSPACE_REGISTRY";
|
|
2
|
+
export type WorkspaceAccess = "read" | "write";
|
|
3
|
+
export interface WorkspaceRegistryFile {
|
|
4
|
+
version: 1;
|
|
5
|
+
workspaces: Record<string, {
|
|
6
|
+
path: string;
|
|
7
|
+
}>;
|
|
8
|
+
}
|
|
9
|
+
export interface ValidatedWorkspace {
|
|
10
|
+
workspaceId: string;
|
|
11
|
+
/** Canonical Git worktree root and the child's validated initial CWD. Not a sandbox. */
|
|
12
|
+
root: string;
|
|
13
|
+
gitCommonDir: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function loadWorkspaceRegistry(path: string): Promise<WorkspaceRegistryFile>;
|
|
16
|
+
export declare function resolveWorkspace(registry: WorkspaceRegistryFile, workspaceId: string): Promise<ValidatedWorkspace>;
|
|
17
|
+
/**
|
|
18
|
+
* Canonicalize and validate the initial workspace against Git's registered worktree list.
|
|
19
|
+
* This prevents accidental misrouting. It does not constrain any path a child accesses after spawn.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateRegisteredWorkspace(input: {
|
|
22
|
+
workspaceId: string;
|
|
23
|
+
registeredRoot: string;
|
|
24
|
+
suppliedRoot?: string;
|
|
25
|
+
}): Promise<ValidatedWorkspace>;
|
|
26
|
+
/**
|
|
27
|
+
* The governed-writer lease lives in `./workspace-lease.ts` and is re-exported here so that
|
|
28
|
+
* "the workspace module" remains one import for callers. Split only to stay under the 400-line
|
|
29
|
+
* module ceiling this project enforces mechanically.
|
|
30
|
+
*/
|
|
31
|
+
export { ENV_WORKSPACE_LEASE_DIR, acquireWorkspaceLease, defaultWorkspaceLeaseDir, leaseAcquisitionOutcome, leaseReleaseLedgerOutcome, type LeaseReleaseOutcome, type WorkspaceLease, } from "./workspace-lease.ts";
|
|
32
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAGrE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,CAAC,CAAC;IACX,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA6BxF;AAED,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAUxH;AAED;;;GAGG;AACH,wBAAsB,2BAA2B,CAAC,KAAK,EAAE;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyC9B;AAED;;;;GAIG;AACH,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,EACzB,KAAK,mBAAmB,EACxB,KAAK,cAAc,GACpB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { once } from "node:events";
|
|
4
|
+
import { mkdir, readFile, realpath, rename, stat, writeFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { isAbsolute, join } from "node:path";
|
|
7
|
+
import { promisify } from "node:util";
|
|
8
|
+
import { GovernanceRefusal, refusal } from "./refusals.js";
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
export const ENV_WORKSPACE_REGISTRY = "PI_GRANTS_WORKSPACE_REGISTRY";
|
|
11
|
+
export async function loadWorkspaceRegistry(path) {
|
|
12
|
+
let parsed;
|
|
13
|
+
try {
|
|
14
|
+
parsed = JSON.parse(await readFile(path, "utf8"));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} could not be read (${String(error)})`, { registry_path: path }));
|
|
18
|
+
}
|
|
19
|
+
const file = parsed;
|
|
20
|
+
if (file?.version !== 1 || !file.workspaces || typeof file.workspaces !== "object" || Array.isArray(file.workspaces)) {
|
|
21
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry ${path} must contain {version:1, workspaces:{id:{path}}}`, { registry_path: path }));
|
|
22
|
+
}
|
|
23
|
+
for (const [id, value] of Object.entries(file.workspaces)) {
|
|
24
|
+
if (!id || !value || typeof value.path !== "string" || !isAbsolute(value.path)) {
|
|
25
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace registry entry ${JSON.stringify(id)} must name an absolute path`, { registry_path: path, workspace_id: id }));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { version: 1, workspaces: structuredClone(file.workspaces) };
|
|
29
|
+
}
|
|
30
|
+
export async function resolveWorkspace(registry, workspaceId) {
|
|
31
|
+
const registered = Object.hasOwn(registry.workspaces, workspaceId) ? registry.workspaces[workspaceId] : undefined;
|
|
32
|
+
if (!registered) {
|
|
33
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace ${JSON.stringify(workspaceId)} is not present in the operator-owned registry`, { workspace_id: workspaceId }));
|
|
34
|
+
}
|
|
35
|
+
return validateRegisteredWorkspace({ workspaceId, registeredRoot: registered.path });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Canonicalize and validate the initial workspace against Git's registered worktree list.
|
|
39
|
+
* This prevents accidental misrouting. It does not constrain any path a child accesses after spawn.
|
|
40
|
+
*/
|
|
41
|
+
export async function validateRegisteredWorkspace(input) {
|
|
42
|
+
let registered;
|
|
43
|
+
let supplied;
|
|
44
|
+
try {
|
|
45
|
+
registered = await realpath(input.registeredRoot);
|
|
46
|
+
supplied = await realpath(input.suppliedRoot ?? input.registeredRoot);
|
|
47
|
+
if (!(await stat(registered)).isDirectory())
|
|
48
|
+
throw new Error("registered root is not a directory");
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace ${input.workspaceId} root could not be canonicalized (${String(error)})`, { workspace_id: input.workspaceId }));
|
|
52
|
+
}
|
|
53
|
+
if (registered !== supplied) {
|
|
54
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace ${input.workspaceId} resolved to ${supplied}, not its registered worktree ${registered}`, { workspace_id: input.workspaceId, supplied_root: supplied, registered_root: registered }));
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const top = (await execFileAsync("git", ["-C", registered, "rev-parse", "--show-toplevel"], { encoding: "utf8" })).stdout.trim();
|
|
58
|
+
const canonicalTop = await realpath(top);
|
|
59
|
+
if (canonicalTop !== registered)
|
|
60
|
+
throw new Error(`path is inside worktree ${canonicalTop}, not its root`);
|
|
61
|
+
const commonRaw = (await execFileAsync("git", ["-C", registered, "rev-parse", "--path-format=absolute", "--git-common-dir"], { encoding: "utf8" })).stdout.trim();
|
|
62
|
+
const gitCommonDir = await realpath(commonRaw);
|
|
63
|
+
const list = (await execFileAsync("git", ["-C", registered, "worktree", "list", "--porcelain"], { encoding: "utf8" })).stdout;
|
|
64
|
+
const registeredWorktrees = await Promise.all(list.split("\n").filter((line) => line.startsWith("worktree ")).map((line) => realpath(line.slice(9))));
|
|
65
|
+
if (!registeredWorktrees.includes(registered))
|
|
66
|
+
throw new Error("Git does not list this path as a worktree");
|
|
67
|
+
return { workspaceId: input.workspaceId, root: registered, gitCommonDir };
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
throw new GovernanceRefusal(refusal("WORKSPACE_NOT_REGISTERED", `workspace ${input.workspaceId} is not the registered Git worktree it claims to be (${String(error)})`, { workspace_id: input.workspaceId, registered_root: registered }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The governed-writer lease lives in `./workspace-lease.ts` and is re-exported here so that
|
|
75
|
+
* "the workspace module" remains one import for callers. Split only to stay under the 400-line
|
|
76
|
+
* module ceiling this project enforces mechanically.
|
|
77
|
+
*/
|
|
78
|
+
export { ENV_WORKSPACE_LEASE_DIR, acquireWorkspaceLease, defaultWorkspaceLeaseDir, leaseAcquisitionOutcome, leaseReleaseLedgerOutcome, } from "./workspace-lease.js";
|
|
79
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Taking back authority a gate banked for an operation that was then refused.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `./approvals.ts` only to stay under the 400-line module ceiling this project enforces
|
|
5
|
+
* mechanically; `./approvals.ts` re-exports both names.
|
|
6
|
+
*/
|
|
7
|
+
import { revokeApproval } from "../src/approval-store.ts";
|
|
8
|
+
import type { Capability } from "../src/resolve.ts";
|
|
9
|
+
import { snapshotOf } from "./approvals.ts";
|
|
10
|
+
import type { GrantsSession } from "./session.ts";
|
|
11
|
+
|
|
12
|
+
/** One piece of authority a gate banked, and where it lives, so it can be undone. */
|
|
13
|
+
export interface BankedApproval {
|
|
14
|
+
key: string;
|
|
15
|
+
capability: Capability;
|
|
16
|
+
subject: string;
|
|
17
|
+
/** True when a 30-day entry reached the on-disk store, which outlives the process. */
|
|
18
|
+
persisted: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* False when this call did not CREATE the authority — it joined a dialog another delegation had already
|
|
21
|
+
* opened, or the key was already standing from an earlier grant.
|
|
22
|
+
*
|
|
23
|
+
* Load-bearing: unbanking revoked by `capability@subject` with no ownership check, so one refused
|
|
24
|
+
* delegation could destroy an approval a live sibling was running under. Two reachable shapes — a
|
|
25
|
+
* joined gate (one human answer shared by concurrent waiters, each recording it as its own) and a
|
|
26
|
+
* legacy-then-bound sequence, where a bound call re-prompts over a plain key that already exists and
|
|
27
|
+
* then deletes both on refusal. Only what this call actually created may be taken back.
|
|
28
|
+
*/
|
|
29
|
+
owned: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Give back authority a gate banked for an operation that was then refused.
|
|
34
|
+
*
|
|
35
|
+
* Best-effort by necessity — the persisted store can be busy — but never silent: an approval that could
|
|
36
|
+
* not be revoked is exactly the one an operator needs to know is still standing (R-113).
|
|
37
|
+
*/
|
|
38
|
+
export async function unbankApprovals(
|
|
39
|
+
session: GrantsSession,
|
|
40
|
+
ctx: { ui: { notify: (message: string) => void } },
|
|
41
|
+
banked: BankedApproval[] | undefined,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
if (!banked || banked.length === 0) return;
|
|
44
|
+
const stranded: string[] = [];
|
|
45
|
+
for (const entry of banked) {
|
|
46
|
+
// Never take back authority this call did not create — see `owned`.
|
|
47
|
+
if (!entry.owned) continue;
|
|
48
|
+
session.sessionApprovals.delete(entry.key);
|
|
49
|
+
session.sessionApprovalBindings.delete(entry.key);
|
|
50
|
+
if (!entry.persisted) continue;
|
|
51
|
+
const outcome = await revokeApproval(session.cwd, entry.key, (subject) => snapshotOf(session, subject), new Date());
|
|
52
|
+
// `"absent"` is NOT proof the entry is gone. `revokeApproval` reports it when the key is missing from
|
|
53
|
+
// the *valid* set, and `loadApprovals` excludes entries whose ceiling or body digest no longer
|
|
54
|
+
// matches — those are still physically in the file and revive the moment they validate again. So an
|
|
55
|
+
// entry that is merely stale reads as "nothing to revoke" and is silently left standing.
|
|
56
|
+
if (outcome !== "revoked") stranded.push(entry.key);
|
|
57
|
+
}
|
|
58
|
+
// Children inherit from the published set, so it must shrink with the session state, not after it.
|
|
59
|
+
session.publishChildEnv();
|
|
60
|
+
if (stranded.length > 0) {
|
|
61
|
+
ctx.ui.notify(
|
|
62
|
+
`grants: this delegation was refused, but a stored approval for ${stranded.join(", ")} could not be ` +
|
|
63
|
+
`revoked and still stands — remove it with \`/grants revoke\` if it was not intended.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
package/extensions/approvals.ts
CHANGED
|
@@ -28,7 +28,12 @@ import type { createApprovalGate } from "../src/approval-prompt.ts";
|
|
|
28
28
|
import { timeoutMsFromEnv, type PromptOutcomeKind } from "../src/approval-prompt.ts";
|
|
29
29
|
import { ceilingForDefinition, digestDefinition } from "../src/definitions.ts";
|
|
30
30
|
import type { Capability } from "../src/resolve.ts";
|
|
31
|
+
import { approvalBindingDigest, type ApprovalBinding } from "../src/correlation.ts";
|
|
32
|
+
import type { RefusalCode } from "../src/refusals.ts";
|
|
31
33
|
import type { GrantsSession } from "./session.ts";
|
|
34
|
+
import type { BankedApproval } from "./approval-banking.ts";
|
|
35
|
+
export { unbankApprovals } from "./approval-banking.ts";
|
|
36
|
+
export type { BankedApproval } from "./approval-banking.ts";
|
|
32
37
|
|
|
33
38
|
/**
|
|
34
39
|
* What a subject looks like right now, for the confused-deputy check in the approval store.
|
|
@@ -102,6 +107,8 @@ export interface ApprovalOutcome {
|
|
|
102
107
|
* and the behaviour that was already in place.
|
|
103
108
|
*/
|
|
104
109
|
scopes: Record<Capability, ApprovalScope>;
|
|
110
|
+
/** Complete scope map for the ledger, including inherited, session, and persisted answers. */
|
|
111
|
+
recordedScopes: Record<Capability, ApprovalScope>;
|
|
105
112
|
/**
|
|
106
113
|
* Where EACH approved capability's yes came from (R-46).
|
|
107
114
|
*
|
|
@@ -110,6 +117,10 @@ export interface ApprovalOutcome {
|
|
|
110
117
|
* always computed this map; the bug was that it was thrown away.
|
|
111
118
|
*/
|
|
112
119
|
sources: Record<Capability, ApprovalSource>;
|
|
120
|
+
/** Exact binding per approved capability when this is a correlated controller call. */
|
|
121
|
+
bindings: Record<Capability, ApprovalBinding>;
|
|
122
|
+
expiresAt: Record<Capability, string>;
|
|
123
|
+
uses: Record<Capability, { max: number; remaining: number }>;
|
|
113
124
|
humanDenied: boolean;
|
|
114
125
|
/**
|
|
115
126
|
* Which of the five prompt outcomes ended the loop, when one did (ADR-0026's F5).
|
|
@@ -119,6 +130,18 @@ export interface ApprovalOutcome {
|
|
|
119
130
|
* dismissal is a queue or a longer timeout, `no-ui` is an operator pre-approving, `error` is a defect.
|
|
120
131
|
*/
|
|
121
132
|
gateOutcome?: PromptOutcomeKind;
|
|
133
|
+
/**
|
|
134
|
+
* Authority this gate LEFT BEHIND: session keys added, and 30-day entries written to disk.
|
|
135
|
+
*
|
|
136
|
+
* Recorded so a caller that refuses after the gate can take it back. `run-delegation.ts` already
|
|
137
|
+
* documents the rule at length — "a refused operation must not leave authority behind" — and moved the
|
|
138
|
+
* executor check before the gate to honour it. The adjacent path did not: an operator clicks *Always*,
|
|
139
|
+
* the load-bearing ledger append then fails (a lock timeout under fan-out is a documented condition),
|
|
140
|
+
* the delegation is refused, and a project-wide 30-day approval survives for a spawn that never
|
|
141
|
+
* happened (R-113).
|
|
142
|
+
*/
|
|
143
|
+
banked?: BankedApproval[];
|
|
144
|
+
refusalCode?: RefusalCode;
|
|
122
145
|
reason?: string;
|
|
123
146
|
}
|
|
124
147
|
|
|
@@ -143,8 +166,9 @@ export async function storedApprovals(
|
|
|
143
166
|
session: GrantsSession,
|
|
144
167
|
gated: Capability[],
|
|
145
168
|
subject: string,
|
|
169
|
+
expectedBinding?: ApprovalBinding,
|
|
146
170
|
): Promise<ResolveApprovalsResult> {
|
|
147
|
-
const { valid } = await loadApprovals({
|
|
171
|
+
const { valid, dropped } = await loadApprovals({
|
|
148
172
|
cwd: session.cwd,
|
|
149
173
|
now: new Date(),
|
|
150
174
|
snapshotOf: (name) => snapshotOf(session, name),
|
|
@@ -153,7 +177,10 @@ export async function storedApprovals(
|
|
|
153
177
|
gated,
|
|
154
178
|
subject,
|
|
155
179
|
sessionApprovals: session.sessionApprovals,
|
|
180
|
+
sessionApprovalBindings: session.sessionApprovalBindings,
|
|
156
181
|
persisted: valid,
|
|
182
|
+
expectedBinding,
|
|
183
|
+
expiredKeys: new Set(dropped.filter((item) => item.verdict === "expired").map((item) => item.key)),
|
|
157
184
|
// ADR-0022. Verified HERE rather than at parse time because it needs `session.definitions`, which
|
|
158
185
|
// arrives at `session_start` — after the session object is built.
|
|
159
186
|
inherited: verifyInherited(session.inheritedApprovals, (name) => snapshotOf(session, name)),
|
|
@@ -180,11 +207,23 @@ export async function obtainApprovals(
|
|
|
180
207
|
ctx: ApprovalUIContext | null,
|
|
181
208
|
task?: string,
|
|
182
209
|
signal?: AbortSignal,
|
|
210
|
+
expectedBinding?: ApprovalBinding,
|
|
183
211
|
): Promise<ApprovalOutcome> {
|
|
184
212
|
const snapshot = (name: string) => snapshotOf(session, name);
|
|
185
|
-
const pre = await storedApprovals(session, gatedBlocked, subject);
|
|
213
|
+
const pre = await storedApprovals(session, gatedBlocked, subject, expectedBinding);
|
|
214
|
+
const preBindings: Record<Capability, ApprovalBinding> = {};
|
|
215
|
+
if (expectedBinding) for (const capability of pre.approved) preBindings[capability] = expectedBinding;
|
|
186
216
|
if (ctx === null || pre.needsPrompt.length === 0) {
|
|
187
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
approved: pre.approved,
|
|
219
|
+
sources: pre.sources,
|
|
220
|
+
scopes: {},
|
|
221
|
+
recordedScopes: pre.scopes,
|
|
222
|
+
bindings: preBindings,
|
|
223
|
+
expiresAt: pre.expiresAt,
|
|
224
|
+
uses: {},
|
|
225
|
+
humanDenied: false,
|
|
226
|
+
};
|
|
188
227
|
}
|
|
189
228
|
|
|
190
229
|
// The gate PROVIDER lives on the session, not here: `obtainApprovals` runs once per `tool_call` and once
|
|
@@ -203,12 +242,21 @@ export async function obtainApprovals(
|
|
|
203
242
|
// about — so a mixed set reports exactly which yes came from where.
|
|
204
243
|
const sources: Record<Capability, ApprovalSource> = { ...pre.sources };
|
|
205
244
|
const scopes: Record<Capability, ApprovalScope> = {};
|
|
245
|
+
const recordedScopes: Record<Capability, ApprovalScope> = { ...pre.scopes };
|
|
246
|
+
const bindings: Record<Capability, ApprovalBinding> = { ...preBindings };
|
|
247
|
+
const expiresAt: Record<Capability, string> = { ...pre.expiresAt };
|
|
248
|
+
const uses: Record<Capability, { max: number; remaining: number }> = {};
|
|
206
249
|
let humanDenied = false;
|
|
250
|
+
const banked: BankedApproval[] = [];
|
|
207
251
|
let gateOutcome: PromptOutcomeKind | undefined;
|
|
252
|
+
let refusalCode: RefusalCode | undefined;
|
|
208
253
|
let reason: string | undefined;
|
|
209
254
|
|
|
210
255
|
for (const capability of pre.needsPrompt) {
|
|
211
|
-
const outcome = await gate.request({
|
|
256
|
+
const outcome = await gate.request({
|
|
257
|
+
capability, subject, path, task, signal,
|
|
258
|
+
...(expectedBinding ? { bindingKey: approvalBindingDigest(expectedBinding) } : {}),
|
|
259
|
+
});
|
|
212
260
|
if (outcome.scope === null) {
|
|
213
261
|
// Forward the gate's own discriminant rather than re-deriving it from `hasUI`: `hasUI` is true in
|
|
214
262
|
// RPC mode too, so an automated client's timeout or dismissal there would misreport as "a human
|
|
@@ -219,6 +267,11 @@ export async function obtainApprovals(
|
|
|
219
267
|
// so "was there an operator who timed out, or was there nobody?" had no answer, and the two want
|
|
220
268
|
// different fixes. It was computed here all along and thrown away.
|
|
221
269
|
gateOutcome = outcome.kind;
|
|
270
|
+
refusalCode = pre.expired.includes(capability)
|
|
271
|
+
? "APPROVAL_EXPIRED"
|
|
272
|
+
: pre.scopeMismatched.includes(capability)
|
|
273
|
+
? "APPROVAL_SCOPE_MISMATCH"
|
|
274
|
+
: "GATED_UNAPPROVED";
|
|
222
275
|
reason = outcome.reason;
|
|
223
276
|
break;
|
|
224
277
|
}
|
|
@@ -230,9 +283,20 @@ export async function obtainApprovals(
|
|
|
230
283
|
// were not.
|
|
231
284
|
sources[capability] = outcome.joined ? "session" : "prompt";
|
|
232
285
|
scopes[capability] = outcome.scope;
|
|
286
|
+
recordedScopes[capability] = outcome.scope;
|
|
287
|
+
if (expectedBinding) bindings[capability] = expectedBinding;
|
|
288
|
+
if (outcome.scope === "once") uses[capability] = { max: 1, remaining: 0 };
|
|
233
289
|
|
|
234
290
|
if (outcome.scope === "session" || outcome.scope === "always") {
|
|
235
|
-
|
|
291
|
+
const key = approvalKey(capability, subject);
|
|
292
|
+
// Whether THIS call created the authority, decided before we add it. `joined` means a human answer
|
|
293
|
+
// opened by another delegation was shared with us; an existing key means it was already standing.
|
|
294
|
+
// Either way it is not ours to take back if we are refused — see `BankedApproval.owned`.
|
|
295
|
+
const owned = !outcome.joined
|
|
296
|
+
&& !(expectedBinding ? session.sessionApprovalBindings.has(key) : session.sessionApprovals.has(key));
|
|
297
|
+
if (expectedBinding) session.sessionApprovalBindings.set(key, expectedBinding);
|
|
298
|
+
else session.sessionApprovals.add(key);
|
|
299
|
+
banked.push({ key, capability, subject, persisted: false, owned });
|
|
236
300
|
}
|
|
237
301
|
if (outcome.scope === "always") {
|
|
238
302
|
const now = new Date();
|
|
@@ -242,6 +306,8 @@ export async function obtainApprovals(
|
|
|
242
306
|
// "type-missing" or "type-changed". Writing it is not unsafe (it fails closed), it is simply a
|
|
243
307
|
// dead entry that silently accumulates in the file. Skip it and say so, taking the same
|
|
244
308
|
// downgrade-to-session path as a failed write below: the human's yes still stands.
|
|
309
|
+
const expires = expiryFor(now);
|
|
310
|
+
expiresAt[capability] = expires;
|
|
245
311
|
const written =
|
|
246
312
|
current === null
|
|
247
313
|
? false
|
|
@@ -250,12 +316,13 @@ export async function obtainApprovals(
|
|
|
250
316
|
approvalKey(capability, subject),
|
|
251
317
|
{
|
|
252
318
|
approvedAt: now.toISOString(),
|
|
253
|
-
expiresAt:
|
|
319
|
+
expiresAt: expires,
|
|
254
320
|
cwd: session.cwd,
|
|
255
321
|
grantAtApproval: current.ceiling,
|
|
256
322
|
// ADR-0019: the tools AND the instructions the human actually saw. Pinning only the
|
|
257
323
|
// former would let a rewritten body inherit a yes that was given about different text.
|
|
258
324
|
bodyAtApproval: current.bodySha256,
|
|
325
|
+
...(expectedBinding ? { binding: expectedBinding } : {}),
|
|
259
326
|
// The TASK is deliberately absent (ADR-0021). It is shown in the dialog, where a human
|
|
260
327
|
// needs it, and never written down, because the model assembles it from the parent's
|
|
261
328
|
// context and it can carry anything the parent could see.
|
|
@@ -263,6 +330,12 @@ export async function obtainApprovals(
|
|
|
263
330
|
snapshot,
|
|
264
331
|
now,
|
|
265
332
|
);
|
|
333
|
+
if (written) {
|
|
334
|
+
// Mark the on-disk half so a later refusal knows there is a file entry to take back, not just a
|
|
335
|
+
// session key that dies with the process.
|
|
336
|
+
const persistedKey = approvalKey(capability, subject);
|
|
337
|
+
for (const entry of banked) if (entry.key === persistedKey) entry.persisted = true;
|
|
338
|
+
}
|
|
266
339
|
if (!written) {
|
|
267
340
|
// The human already said yes; the security decision stands. Only the convenience cache
|
|
268
341
|
// failed, so this downgrades scope rather than refusing the delegation (see approval-store.ts).
|
|
@@ -276,10 +349,25 @@ export async function obtainApprovals(
|
|
|
276
349
|
// The human's yes stands; only the cache failed. Downgrade THIS capability, not the set — under
|
|
277
350
|
// the old scalar this also rewrote the scope of every other capability answered in the same call.
|
|
278
351
|
scopes[capability] = "session";
|
|
352
|
+
recordedScopes[capability] = "session";
|
|
353
|
+
delete expiresAt[capability];
|
|
279
354
|
}
|
|
280
355
|
}
|
|
281
356
|
session.publishChildEnv(); // a new session approval widens what children may inherit — republish now
|
|
282
357
|
}
|
|
283
358
|
|
|
284
|
-
return {
|
|
359
|
+
return {
|
|
360
|
+
approved,
|
|
361
|
+
sources,
|
|
362
|
+
scopes,
|
|
363
|
+
recordedScopes,
|
|
364
|
+
bindings,
|
|
365
|
+
expiresAt,
|
|
366
|
+
uses,
|
|
367
|
+
humanDenied,
|
|
368
|
+
gateOutcome,
|
|
369
|
+
refusalCode,
|
|
370
|
+
reason,
|
|
371
|
+
banked,
|
|
372
|
+
};
|
|
285
373
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { InheritableApproval } from "../src/approval.ts";
|
|
2
|
+
import type { Capability } from "../src/resolve.ts";
|
|
3
|
+
import type { ApprovalOutcome } from "./approvals.ts";
|
|
4
|
+
|
|
5
|
+
export interface ChainApprovalAudit {
|
|
6
|
+
sources: Map<string, ApprovalOutcome["sources"][Capability]>;
|
|
7
|
+
scopes: Map<string, ApprovalOutcome["recordedScopes"][Capability]>;
|
|
8
|
+
expiresAt: Map<string, string>;
|
|
9
|
+
uses: Map<string, { max: number; remaining: number }>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function newChainApprovalAudit(): ChainApprovalAudit {
|
|
13
|
+
return { sources: new Map(), scopes: new Map(), expiresAt: new Map(), uses: new Map() };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function rememberChainApproval(
|
|
17
|
+
audit: ChainApprovalAudit,
|
|
18
|
+
capability: Capability,
|
|
19
|
+
subject: string,
|
|
20
|
+
outcome: ApprovalOutcome,
|
|
21
|
+
): void {
|
|
22
|
+
const key = `${capability}@${subject}`;
|
|
23
|
+
const source = outcome.sources[capability];
|
|
24
|
+
const scope = outcome.recordedScopes[capability];
|
|
25
|
+
if (source) audit.sources.set(key, source);
|
|
26
|
+
if (scope) audit.scopes.set(key, scope);
|
|
27
|
+
const expiresAt = outcome.expiresAt[capability];
|
|
28
|
+
if (expiresAt) audit.expiresAt.set(key, expiresAt);
|
|
29
|
+
const uses = outcome.uses[capability];
|
|
30
|
+
if (uses) audit.uses.set(key, uses);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function chainApprovalFacts(
|
|
34
|
+
audit: ChainApprovalAudit,
|
|
35
|
+
available: InheritableApproval[],
|
|
36
|
+
subject: string,
|
|
37
|
+
): Pick<ApprovalOutcome, "approved" | "sources" | "scopes" | "expiresAt" | "uses" | "humanDenied"> {
|
|
38
|
+
const entries = available.filter((approval) => approval.subject === subject);
|
|
39
|
+
const values = <T>(map: Map<string, T>) => Object.fromEntries(entries.flatMap((approval) => {
|
|
40
|
+
const value = map.get(`${approval.capability}@${approval.subject}`);
|
|
41
|
+
return value === undefined ? [] : [[approval.capability, value]];
|
|
42
|
+
}));
|
|
43
|
+
return {
|
|
44
|
+
approved: entries.map((approval) => approval.capability),
|
|
45
|
+
sources: values(audit.sources),
|
|
46
|
+
scopes: values(audit.scopes),
|
|
47
|
+
expiresAt: values(audit.expiresAt),
|
|
48
|
+
uses: values(audit.uses),
|
|
49
|
+
humanDenied: false,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ApprovalOutcome } from "./approvals.ts";
|
|
2
|
+
import type { Delegation } from "../src/delegate.ts";
|
|
3
|
+
import { appendRecord, buildRecord } from "../src/ledger.ts";
|
|
4
|
+
import type { StructuredRefusal } from "../src/refusals.ts";
|
|
5
|
+
import { childSpawnId } from "../src/fanout.ts";
|
|
6
|
+
import type { GrantsSession } from "./session.ts";
|
|
7
|
+
|
|
8
|
+
/** Audit a chain preflight/gate refusal with the same trusted planner facts as a normal delegation. */
|
|
9
|
+
export async function recordChainRefusal(input: {
|
|
10
|
+
session: GrantsSession;
|
|
11
|
+
plan: Delegation;
|
|
12
|
+
stepIndex: number;
|
|
13
|
+
agent?: string;
|
|
14
|
+
reason: string;
|
|
15
|
+
refusal?: StructuredRefusal;
|
|
16
|
+
approval?: ApprovalOutcome;
|
|
17
|
+
}): Promise<void> {
|
|
18
|
+
if (!input.session.ledgerPath) return;
|
|
19
|
+
await appendRecord(
|
|
20
|
+
{ path: input.session.ledgerPath, strict: true },
|
|
21
|
+
buildRecord({
|
|
22
|
+
parentId: input.session.ownSpawnId,
|
|
23
|
+
childId: childSpawnId(input.session.ownSpawnId, input.stepIndex),
|
|
24
|
+
depth: input.plan.childDepth,
|
|
25
|
+
agentType: input.agent ?? "delegate",
|
|
26
|
+
requested: input.plan.requested,
|
|
27
|
+
parentGrant: input.session.ownGrant,
|
|
28
|
+
result: input.plan.result,
|
|
29
|
+
blocked: true,
|
|
30
|
+
reason: input.reason,
|
|
31
|
+
approved: input.approval?.approved,
|
|
32
|
+
approvalSources: input.approval?.sources,
|
|
33
|
+
approvalScopes: input.approval?.recordedScopes,
|
|
34
|
+
approvalExpiresAt: input.approval?.expiresAt,
|
|
35
|
+
approvalUses: input.approval?.uses,
|
|
36
|
+
humanDenied: input.approval?.humanDenied,
|
|
37
|
+
gateOutcome: input.approval?.gateOutcome,
|
|
38
|
+
definitionDigest: input.plan.definitionDigest,
|
|
39
|
+
taskDigest: input.plan.taskDigest,
|
|
40
|
+
correlation: input.plan.correlation,
|
|
41
|
+
// An approval banked before a later chain decline is a yes that led to no spawn, not the stale
|
|
42
|
+
// GATED_UNAPPROVED refusal from the pre-approval plan.
|
|
43
|
+
refusal: input.refusal ?? (input.approval?.approved.length ? undefined : input.plan.refusal),
|
|
44
|
+
executor: input.session.executor.kind,
|
|
45
|
+
now: new Date(),
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
}
|