toolroll 0.9.61 → 0.9.63
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 +46 -0
- package/README.md +51 -3
- package/dist/agent-fence.d.ts +155 -10
- package/dist/agent-fence.js +473 -38
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +21 -21
- package/dist/browser-workspace.d.ts +28 -0
- package/dist/chat-actions.js +2 -2
- package/dist/check-levels.js +3 -0
- package/dist/claim.js +1 -1
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +1 -0
- package/dist/cli.js +31 -11
- package/dist/contracts/cli.d.ts +8 -0
- package/dist/contracts/cli.js +3 -1
- package/dist/contracts/console-api.d.ts +19 -1
- package/dist/contracts/console-api.js +2 -1
- package/dist/contracts/integration-metadata.d.ts +2 -1
- package/dist/contracts/integration-metadata.js +2 -1
- package/dist/desktop-update.d.ts +1 -1
- package/dist/dispatch.js +7 -4
- package/dist/doctor.d.ts +53 -0
- package/dist/doctor.js +427 -0
- package/dist/evidence-pack.d.ts +1 -1
- package/dist/evidence-pack.js +2 -2
- package/dist/exec.d.ts +3 -0
- package/dist/exec.js +5 -4
- package/dist/flow-code.d.ts +2 -2
- package/dist/flow-code.js +4 -15
- package/dist/flow-engine.js +11 -6
- package/dist/flow-triggers.d.ts +8 -4
- package/dist/flow-triggers.js +45 -25
- package/dist/flow-unattended-words.d.ts +28 -0
- package/dist/flow-unattended-words.js +50 -0
- package/dist/flow-unattended.d.ts +227 -0
- package/dist/flow-unattended.js +776 -0
- package/dist/flows-cli.d.ts +28 -1
- package/dist/flows-cli.js +55 -10
- package/dist/flows-ui.d.ts +2 -1
- package/dist/flows-ui.js +4 -1
- package/dist/google-mail.d.ts +1 -0
- package/dist/google-mail.js +61 -18
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +6 -3
- package/dist/integrations.d.ts +17 -3
- package/dist/integrations.js +38 -18
- package/dist/invoke.js +300 -168
- package/dist/landed-cleanup.d.ts +26 -12
- package/dist/landed-cleanup.js +199 -85
- package/dist/lead-contract.d.ts +1 -1
- package/dist/lead-contract.js +3 -3
- package/dist/lead-tools.js +11 -3
- package/dist/mcp-connect.d.ts +8 -7
- package/dist/mcp-connect.js +49 -51
- package/dist/oauth-run-token.d.ts +51 -0
- package/dist/oauth-run-token.js +127 -0
- package/dist/operate.js +74 -17
- package/dist/plan-auto.d.ts +11 -0
- package/dist/plan-auto.js +62 -11
- package/dist/process-recovery-eligibility.d.ts +1 -1
- package/dist/project-access.d.ts +3 -0
- package/dist/project-access.js +3 -0
- package/dist/project-admission.d.ts +10 -6
- package/dist/project-admission.js +33 -11
- package/dist/project-delete-ui.d.ts +1 -0
- package/dist/project-delete-ui.js +4 -1
- package/dist/project-delete.d.ts +3 -1
- package/dist/project-delete.js +10 -4
- package/dist/project-file.d.ts +3 -0
- package/dist/project-file.js +16 -0
- package/dist/project-tools.d.ts +99 -25
- package/dist/project-tools.js +394 -98
- package/dist/provider-home.d.ts +22 -0
- package/dist/provider-home.js +99 -0
- package/dist/provider.d.ts +17 -3
- package/dist/provider.js +34 -10
- package/dist/remote-main.d.ts +61 -0
- package/dist/remote-main.js +179 -0
- package/dist/scope.d.ts +1 -1
- package/dist/serve.js +11 -3
- package/dist/server/flows.js +27 -5
- package/dist/server/render-tasks.d.ts +3 -0
- package/dist/server/render-tasks.js +3 -0
- package/dist/server/route-table.js +3 -0
- package/dist/server/runtime.d.ts +1 -1
- package/dist/server/settings.js +14 -5
- package/dist/server/task-views.js +2 -0
- package/dist/storage-sweep-child.js +3 -1
- package/dist/storage-sweep-process.d.ts +14 -0
- package/dist/storage-sweep-process.js +37 -3
- package/dist/storage-sweep-schedule.d.ts +30 -0
- package/dist/storage-sweep-schedule.js +164 -0
- package/dist/storage-sweep.d.ts +6 -5
- package/dist/storage-sweep.js +10 -70
- package/dist/storage-ui.d.ts +2 -0
- package/dist/storage-ui.js +7 -4
- package/dist/store.d.ts +75 -7
- package/dist/store.js +241 -17
- package/dist/subagent-tools.d.ts +1 -1
- package/dist/surface.js +10 -6
- package/dist/task-base.d.ts +35 -0
- package/dist/task-base.js +51 -0
- package/dist/teardown-git.d.ts +14 -0
- package/dist/teardown-git.js +119 -0
- package/dist/tool-broker.d.ts +37 -0
- package/dist/tool-broker.js +369 -0
- package/dist/tool-launcher.js +5 -4
- package/dist/tool-secret-store.d.ts +170 -0
- package/dist/tool-secret-store.js +834 -0
- package/dist/toolroll-update.js +4 -2
- package/dist/tools-ui.d.ts +7 -1
- package/dist/tools-ui.js +17 -8
- package/dist/work-index.js +5 -3
- package/dist/worktree.d.ts +64 -6
- package/dist/worktree.js +171 -35
- package/package.json +3 -1
- package/scripts/provider-canary.mjs +210 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.63 — 2026-10-13
|
|
4
|
+
|
|
5
|
+
- **Scheduled flows run on their own.** Sign a flow once with limits
|
|
6
|
+
(runs a day, budget, end date); its on-time firings build without a
|
|
7
|
+
person, and the script it runs is checked again when it fires.
|
|
8
|
+
- **Secrets in the OS keychain.** Tool keys, the Linear key, Google mail and
|
|
9
|
+
flow secrets move into the macOS Keychain or Linux Secret Service, never
|
|
10
|
+
argv or the database. OAuth tools give each run a short-lived token, never
|
|
11
|
+
the refresh token. Settings shows how each tool's runs get credentials.
|
|
12
|
+
- **Builds stay in their own checkout.** A build can't read or write another
|
|
13
|
+
project's or another task's checkout, and a checkout swapped for a link
|
|
14
|
+
is refused at the next launch.
|
|
15
|
+
- **Safer cleanup.** Removing finished checkouts runs git with hooks,
|
|
16
|
+
filters and nested-repo config switched off.
|
|
17
|
+
- **Attack suite.** Every bypass found in review is a permanent test, run by
|
|
18
|
+
the Quick check whenever sandbox or secrets code changes.
|
|
19
|
+
- **Tool secrets stay outside the build.** A broker outside the sandbox
|
|
20
|
+
holds them. Codex refuses tools that carry secrets. Shared dependencies and
|
|
21
|
+
`git gc` work inside the fence.
|
|
22
|
+
- **Tighter sandbox.** Builds can no longer rename folders above protected
|
|
23
|
+
paths or inspect other processes' memory; tool servers get only the
|
|
24
|
+
environment they need.
|
|
25
|
+
- **Tools with secrets need the macOS sandbox.** A build without it, and
|
|
26
|
+
every build on Linux, leaves those tools out and says why.
|
|
27
|
+
- **`toolroll doctor`.** Checks that Toolroll's service holds no key a build
|
|
28
|
+
could read, and lists the steps to fix it. It reads only.
|
|
29
|
+
- **Research tools answer every refusal**, even when the service accepts the
|
|
30
|
+
rest with an empty reply.
|
|
31
|
+
|
|
32
|
+
## 0.9.62 — 2026-10-12
|
|
33
|
+
|
|
34
|
+
- **Release checks in minutes.** The upgrade path runs on a sample, CI's
|
|
35
|
+
passing run on the exact commit is reused, and the first failure stops it.
|
|
36
|
+
- **Storage sweep waits for quiet.** It runs when nothing is building, and
|
|
37
|
+
Settings → Storage says when it last ran and why it waits.
|
|
38
|
+
- **Landing proof you can trust.** A task completes on its own only for a
|
|
39
|
+
merged pull request or the project's recorded remote main, never a local
|
|
40
|
+
branch a build could move. Projects added before this need it once: you
|
|
41
|
+
(the owner) or an instance operator's lead runs
|
|
42
|
+
`toolroll repos add <project> --remote <url>`. Until then, their tasks wait
|
|
43
|
+
for you.
|
|
44
|
+
- **Cleanup follow-ups.** Only branches Toolroll created are removed, counted
|
|
45
|
+
from when it made them; scout branches stay, and duplicate teardowns merge.
|
|
46
|
+
- **Fresh base.** A task with no commits starts from current main; the task
|
|
47
|
+
page shows its base.
|
|
48
|
+
|
|
3
49
|
## 0.9.61 — 2026-10-12
|
|
4
50
|
|
|
5
51
|
- **Agents board.** One place to check on running agents: Needs you,
|
package/README.md
CHANGED
|
@@ -409,7 +409,7 @@ do not loosen when you leave the room:
|
|
|
409
409
|
| touch a default branch | builds land on `toolroll/<task>` in a leased worktree; push + PR happen only under a publication grant naming the exact repo, branch prefix, and base |
|
|
410
410
|
| approve its own work | approval nonces are minted only on screens that restate the digest-bound terms, and require your approver token typed again — **no LLM sits in any approval path** — and the [agent fence](#what-an-agent-can-reach) keeps your remembered login, runner tokens and the database out of the agent's reach |
|
|
411
411
|
| act on an irreversible option | `reversible` is a schema field; irreversible choices never auto-apply, and answering one from a phone takes a second minted confirmation tap |
|
|
412
|
-
| see Toolroll's secrets | the [agent fence](#what-an-agent-can-reach) blocks your login, runner and bot tokens, stored provider keys and project tool secrets at the operating system; other providers' keys are stripped from each agent's environment; secrets
|
|
412
|
+
| see Toolroll's secrets | the [agent fence](#what-an-agent-can-reach) blocks your login, runner and bot tokens, stored provider keys and project tool secrets at the operating system; other providers' keys are stripped from each agent's environment; tool secrets rest sealed in the OS keychain ([how](#how-build-sessions-are-protected)) and other secrets in 0600 files, never in the database, URLs, or logs |
|
|
413
413
|
| spend while idle | **an LLM never polls** — the daemon does every no-judgement chore at zero token cost and wakes an agent only on a real event |
|
|
414
414
|
| spend without being counted | every provider spawn is stamped *before* it spends, so cost is measured, never asserted |
|
|
415
415
|
| guess at a judgement call | it parks a typed decision — recap, options with reversibility, recommendation, evidence — and the other eleven tasks keep going |
|
|
@@ -572,6 +572,13 @@ runner and coordinator tokens, chat bot tokens, the database and its backups,
|
|
|
572
572
|
other runs' evidence) — everything there except the build's own worktree —
|
|
573
573
|
and `~/.toolroll` (stored provider keys and project tool secrets).
|
|
574
574
|
|
|
575
|
+
Seatbelt and bubblewrap deny the whole checkout pool and allow the build’s own
|
|
576
|
+
checkout back, covering other projects created after launch too. Codex keeps
|
|
577
|
+
the own checkout’s ancestors traversable and denies each other project folder
|
|
578
|
+
found in trusted checkout pools at launch. A project added after a Codex build
|
|
579
|
+
starts is covered on the next launch. Own Git data, linked shared dependencies
|
|
580
|
+
and launch tools remain available.
|
|
581
|
+
|
|
575
582
|
| | Auto | Full access |
|
|
576
583
|
|---|---|---|
|
|
577
584
|
| **Codex / OpenRouter** (any OS) | Codex's workspace sandbox (workspace writes, no network) with the fence | Codex's sandbox widened to write anywhere with network, with the fence |
|
|
@@ -581,8 +588,49 @@ and `~/.toolroll` (stored provider keys and project tool secrets).
|
|
|
581
588
|
Each attempt records how it was fenced. Two limits to know: in **API-key
|
|
582
589
|
mode** an agent's own provider key is in its environment, so its shell can
|
|
583
590
|
read it (subscription mode, the default, puts no key there); and a project's
|
|
584
|
-
own tool secrets reach that project's tools.
|
|
585
|
-
|
|
591
|
+
own tool secrets reach that project's tools. They stay in a per-run broker
|
|
592
|
+
outside the fence: the agent gets only its address and a token that stops
|
|
593
|
+
working when the run ends, and on macOS it can't read another process's
|
|
594
|
+
arguments or environment. Reviews and the lead chat run with no tools and are
|
|
595
|
+
confined to their own files. See [SECURITY.md](SECURITY.md).
|
|
596
|
+
|
|
597
|
+
### How build sessions are protected
|
|
598
|
+
|
|
599
|
+
A build runs as your own user, so Toolroll keeps the secrets it holds (tool
|
|
600
|
+
keys and sign-ins, the Linear key, a Google mail connection, flow webhook
|
|
601
|
+
secrets) away from it in layers:
|
|
602
|
+
|
|
603
|
+
- **The fence.** The operating system denies the build Toolroll's own
|
|
604
|
+
folders, your home configuration and other projects (the table above).
|
|
605
|
+
- **The broker.** A run's tools are served by a broker in Toolroll's own
|
|
606
|
+
process, outside the fence. The agent gets only the broker's local address
|
|
607
|
+
and a key for that run, which stops working when the run ends. Another
|
|
608
|
+
run's key opens nothing.
|
|
609
|
+
- **The keychain.** At rest, secrets are in the macOS Keychain (through
|
|
610
|
+
`security`, with the value on its input) or the Linux Secret Service (the
|
|
611
|
+
system's `secret-tool`, value on its input). A fenced build can still ask
|
|
612
|
+
the keychain for an item, so each is sealed with a key in `tool-secrets`
|
|
613
|
+
beside Toolroll's database. Toolroll makes that folder when it starts,
|
|
614
|
+
before any build, and records which key it made; a folder, key or link put
|
|
615
|
+
there by anything else is refused. What a build reads is ciphertext.
|
|
616
|
+
Secrets are read only when a run starts. Files from before move into the
|
|
617
|
+
keychain the first time they are used, and the plaintext copy is removed.
|
|
618
|
+
Where there is no keychain, or the keyring doesn't answer, secrets stay in
|
|
619
|
+
owner-only files, and Settings and `toolroll integrations` say so.
|
|
620
|
+
- **Short-lived tokens.** A service connected by signing in gives each run
|
|
621
|
+
a fresh access token of its own, made outside the fence when the run starts
|
|
622
|
+
and limited to read access for research steps where the service allows.
|
|
623
|
+
The refresh token never leaves Toolroll, and one renewal runs at a time
|
|
624
|
+
across Toolroll's processes. If a renewed sign-in can't be saved, the run
|
|
625
|
+
doesn't start and every token made for it is revoked. The run's token is
|
|
626
|
+
revoked when the run ends, or runs out on its own where the service has no
|
|
627
|
+
way to revoke it. Keys you paste in stay in the broker. Settings → Tools
|
|
628
|
+
shows which each tool uses.
|
|
629
|
+
|
|
630
|
+
What remains: any program of yours running outside the fence (not started by
|
|
631
|
+
a build) can read what you can, including Toolroll's folder and the keychain.
|
|
632
|
+
Toolroll protects your secrets from its builds, not from other software you
|
|
633
|
+
run.
|
|
586
634
|
|
|
587
635
|
Every new-task and task-scope form has the same two-choice control. A task's
|
|
588
636
|
choice is durable through planning rewrites and is sealed into the approved
|
package/dist/agent-fence.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/** How a launch was fenced, as recorded on the run and said on the task. */
|
|
2
2
|
export type FenceMethod = "codex-profile" | "macos-sandbox" | "linux-bubblewrap" | "claude-rules" | "none";
|
|
3
|
+
/** Only the plane's recorded repository may supply an own-Git exemption. */
|
|
4
|
+
export type WorktreeBinding = {
|
|
5
|
+
main: string;
|
|
6
|
+
gitdir: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class CheckoutBindingError extends Error {
|
|
9
|
+
}
|
|
10
|
+
export declare const HARDENED_GIT_ARGS: readonly ["--no-optional-locks", "-c", "core.fsmonitor=false", "-c", "core.hooksPath=/dev/null"];
|
|
11
|
+
export declare function checkoutGitEnv(base?: Readonly<NodeJS.ProcessEnv>): Record<string, string>;
|
|
12
|
+
export declare function trustedWorktreeBinding(repository: string, worktree: string, poolRoots?: readonly (string | null)[]): WorktreeBinding;
|
|
3
13
|
/**
|
|
4
14
|
* Every path an agent must not reach: the Toolroll state folder
|
|
5
15
|
* beside the database (all of it, except the folder that holds this run's
|
|
@@ -14,11 +24,17 @@ export declare function agentFence(options: {
|
|
|
14
24
|
home?: string;
|
|
15
25
|
extra?: readonly string[];
|
|
16
26
|
boundary?: TaskBoundary | null;
|
|
27
|
+
binding?: WorktreeBinding | null;
|
|
28
|
+
runFolders?: RunFolders;
|
|
17
29
|
}): string[];
|
|
18
|
-
/** The task's boundary: `shell` joins the OS fence; `fileTools` only Claude's file-tool deny rules
|
|
30
|
+
/** The task's boundary: `shell` joins the OS fence; `fileTools` only Claude's file-tool deny rules; `readOnly` and
|
|
31
|
+
* `lookup` are other tasks' git metadata and checkout roots (see FenceGrants). */
|
|
19
32
|
export type TaskBoundary = {
|
|
33
|
+
protectedShell?: string[];
|
|
20
34
|
shell: string[];
|
|
21
35
|
fileTools: string[];
|
|
36
|
+
readOnly: string[];
|
|
37
|
+
lookup: string[];
|
|
22
38
|
};
|
|
23
39
|
/**
|
|
24
40
|
* Everything outside a task's own folders that a build could otherwise
|
|
@@ -32,19 +48,145 @@ export declare function taskBoundary(options: {
|
|
|
32
48
|
worktree: string;
|
|
33
49
|
provider: string;
|
|
34
50
|
home?: string;
|
|
51
|
+
binding?: WorktreeBinding | null;
|
|
35
52
|
}): TaskBoundary;
|
|
53
|
+
/** Where launches keep their private folders (the system temp folder), and this launch's own tool folder. */
|
|
54
|
+
export type RunFolders = {
|
|
55
|
+
root: string;
|
|
56
|
+
own: string | null;
|
|
57
|
+
};
|
|
58
|
+
/** The prefixes of every launch's private folders: its tools' config and a Codex build's own home. */
|
|
59
|
+
export declare const RUN_FOLDER_PREFIXES: readonly ["so-tools-", "so-codex-"];
|
|
60
|
+
export declare function runFolders(own: string | null, root?: string): RunFolders;
|
|
61
|
+
/**
|
|
62
|
+
* What a fence gives back beside its denied paths. Each is narrow and none
|
|
63
|
+
* ever writes: `readOnly` is read, never written (other tasks' git
|
|
64
|
+
* metadata); `readable` is read and run inside a denied folder (the shared
|
|
65
|
+
* dependencies this checkout links); `lookup` is only looked up, never
|
|
66
|
+
* listed or read (the deps root and the copy linked, other tasks' checkout
|
|
67
|
+
* roots); `runFolders` denies every launch folder in the temp folder but
|
|
68
|
+
* this launch's own (macOS: by pattern, so a later one is denied too);
|
|
69
|
+
* `pool` denies the plane's checkout pools whole and gives this build's own
|
|
70
|
+
* checkout back (CheckoutPool).
|
|
71
|
+
*/
|
|
72
|
+
export type FenceGrants = {
|
|
73
|
+
readOnly: string[];
|
|
74
|
+
readable: string[];
|
|
75
|
+
lookup: string[];
|
|
76
|
+
runFolders?: RunFolders;
|
|
77
|
+
pool?: CheckoutPool;
|
|
78
|
+
};
|
|
79
|
+
export declare const NO_GRANTS: FenceGrants;
|
|
80
|
+
/**
|
|
81
|
+
* The plane's checkout pools, denied whole: every project's worktrees, and any made there after launch. `agentFence`
|
|
82
|
+
* drops a path at or above the checkout, so the deny lives here and each sandbox gives back, right after it, only
|
|
83
|
+
* `own` (this build's checkout, read and written) and `lookup` (the folders between, looked up, never listed).
|
|
84
|
+
*/
|
|
85
|
+
export type CheckoutPool = {
|
|
86
|
+
deny: string[];
|
|
87
|
+
own: string | null;
|
|
88
|
+
lookup: string[];
|
|
89
|
+
gitPaths?: string[];
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* The pool deny for one launch. `roots` come from the plane's own records (the pool beside the database, and the one
|
|
93
|
+
* the recorded checkout was made in), never from the checkout. A root that holds this checkout's own Git data (the
|
|
94
|
+
* binding's gitdir or the repository's .git) is never denied whole: it is split around that data instead, entry by
|
|
95
|
+
* entry, so it is denied as far as it can be (fail closed by denying more, never by refusing). A root inside the
|
|
96
|
+
* checkout, the home folder, a folder above it or / is left alone: the first is the build's own work, the others the
|
|
97
|
+
* whole machine.
|
|
98
|
+
*/
|
|
99
|
+
export declare function checkoutPool(options: {
|
|
100
|
+
roots: readonly (string | null)[];
|
|
101
|
+
worktree: string | null;
|
|
102
|
+
binding?: WorktreeBinding | null;
|
|
103
|
+
home?: string;
|
|
104
|
+
}, list?: (path: string) => string[]): CheckoutPool;
|
|
105
|
+
/** The grants for one build: its task boundary's git rules, the shared dependencies its checkout links, and the
|
|
106
|
+
* checkout pools (`poolRoots`, from the plane's records) denied around its own checkout. */
|
|
107
|
+
export declare function fenceGrants(options: {
|
|
108
|
+
databaseFile: string | null;
|
|
109
|
+
worktree: string | null;
|
|
110
|
+
boundary?: TaskBoundary | null;
|
|
111
|
+
runFolders?: RunFolders;
|
|
112
|
+
linked?: {
|
|
113
|
+
repo: string;
|
|
114
|
+
setupDigest: string | null;
|
|
115
|
+
} | null;
|
|
116
|
+
poolRoots?: readonly (string | null)[];
|
|
117
|
+
binding?: WorktreeBinding | null;
|
|
118
|
+
home?: string;
|
|
119
|
+
}): FenceGrants;
|
|
120
|
+
/**
|
|
121
|
+
* Git settings every fenced build runs with (GIT_CONFIG_COUNT, after any the
|
|
122
|
+
* caller already set): `git gc` never expires a reflog, so it never rewrites
|
|
123
|
+
* another task's reflog, which the fence would refuse mid-collection.
|
|
124
|
+
*/
|
|
125
|
+
export declare function fencedGitEnv(base?: Readonly<Record<string, string | undefined>>): Record<string, string>;
|
|
36
126
|
/**
|
|
37
127
|
* Codex's own sandbox, fenced. Auto: the `:workspace` profile Codex's
|
|
38
128
|
* `--sandbox workspace-write` already gives (workspace and temp writes, no
|
|
39
129
|
* network). Full access: the same profile widened to write anywhere with
|
|
40
130
|
* network on, instead of no sandbox at all. Either way the fenced paths are
|
|
41
|
-
* denied, which in Codex outranks any write or read grant.
|
|
131
|
+
* denied, which in Codex outranks any write or read grant. The checkout pools
|
|
132
|
+
* are never `flattened` (which leaves what is made after launch readable): see
|
|
133
|
+
* `codexPool`, which denies them around the build's own checkout, written back.
|
|
134
|
+
*/
|
|
135
|
+
export declare function codexFenceArgv(fence: readonly string[], fullAccess: boolean, grants?: FenceGrants): string[];
|
|
136
|
+
/**
|
|
137
|
+
* Codex cannot deny an ancestor and still traverse it to the own checkout. Deny existing
|
|
138
|
+
* siblings individually, from the trusted pool roots and a fresh listing, never through
|
|
139
|
+
* flattened or name patterns. A project added after launch is covered on the next launch;
|
|
140
|
+
* Seatbelt and bubblewrap retain the stronger whole-pool rule for later-created projects.
|
|
141
|
+
*/
|
|
142
|
+
export declare function codexPool(pool: CheckoutPool, list?: (path: string) => string[]): {
|
|
143
|
+
read: string[];
|
|
144
|
+
deny: string[];
|
|
145
|
+
write: string[];
|
|
146
|
+
};
|
|
147
|
+
/** Secret-looking names denied by pattern inside a folder `flattened` makes read-only, so one written there after
|
|
148
|
+
* launch is denied too (the database and its journals, tokens, login and other text files). */
|
|
149
|
+
export declare const SPLIT_SECRET_PATTERNS: readonly ["orders.db*", "*token*", "up-login*", "*.txt", "*secret*", "*password*", "*credential*", "*.pem", "*.key"];
|
|
150
|
+
/**
|
|
151
|
+
* A fence as plain denied and read-only paths, for a sandbox that can't
|
|
152
|
+
* grant inside a denied folder (Codex: a deny outranks any grant): a denied
|
|
153
|
+
* folder holding something readable becomes read-only, with each of its
|
|
154
|
+
* entries not on the way to what is readable denied instead. Fails closed: a
|
|
155
|
+
* folder that can't be listed stays denied whole and its grant is dropped.
|
|
156
|
+
* Residual: an entry made after launch in a read-only folder is denied only
|
|
157
|
+
* when its name matches SPLIT_SECRET_PATTERNS; any other new entry there is
|
|
158
|
+
* readable (never writable) until the next launch. The macOS fence has no
|
|
159
|
+
* such gap: it denies the folder and grants back only the readable path.
|
|
160
|
+
*/
|
|
161
|
+
export declare function flattened(fence: readonly string[], grants?: FenceGrants, list?: (path: string) => string[]): {
|
|
162
|
+
deny: string[];
|
|
163
|
+
readOnly: string[];
|
|
164
|
+
};
|
|
165
|
+
/** Claude's own file tools refuse the fenced paths in every mode (its shell is fenced by the macOS sandbox), and
|
|
166
|
+
* never edit a read-only one. */
|
|
167
|
+
export declare function claudeFenceSettings(fence: readonly string[], readOnly?: readonly string[]): string;
|
|
168
|
+
/**
|
|
169
|
+
* The folders the user owns above each path (never `/`, nor the path itself), and each `roots` folder itself when the
|
|
170
|
+
* user owns it. A Seatbelt path rule follows the name, not the folder: renaming one of these would bring a fenced path
|
|
171
|
+
* back under a name no rule mentions. A folder the user doesn't own can't be renamed by a build anyway.
|
|
172
|
+
*/
|
|
173
|
+
export declare function ownedAncestors(paths: readonly string[], roots?: readonly string[], uid?: number | undefined): string[];
|
|
174
|
+
/**
|
|
175
|
+
* A Seatbelt profile that allows everything except reading or writing the
|
|
176
|
+
* fenced paths, less what `grants` gives back (a later Seatbelt rule
|
|
177
|
+
* outranks an earlier one). Whatever the paths, the process can't read
|
|
178
|
+
* another's arguments and environment (`kern.procargs`, which `ps -E` and
|
|
179
|
+
* KERN_PROCARGS2 use) or inspect a process outside its own sandbox:
|
|
180
|
+
* `process-info*` limited by target alone doesn't stop the sysctl. It can't
|
|
181
|
+
* take another process's task port either (`task_for_pid`, what lldb attaches
|
|
182
|
+
* with; a task name port too), so a tool server's or Toolroll's own memory
|
|
183
|
+
* and environment stay out of reach. Last, every folder of the user's above
|
|
184
|
+
* a fenced or read-only path and above the temp folder (and the temp folder
|
|
185
|
+
* itself) can't be renamed or removed, though what is inside them stays
|
|
186
|
+
* writable as before. The checkout pools are denied first, and the build's own
|
|
187
|
+
* checkout given back right after, so every later deny still holds inside it.
|
|
42
188
|
*/
|
|
43
|
-
export declare function
|
|
44
|
-
/** Claude's own file tools refuse the fenced paths in every mode (its shell is fenced by the macOS sandbox). */
|
|
45
|
-
export declare function claudeFenceSettings(fence: readonly string[]): string;
|
|
46
|
-
/** A Seatbelt profile that allows everything except reading or writing the fenced paths. */
|
|
47
|
-
export declare function macosFenceProfile(fence: readonly string[]): string;
|
|
189
|
+
export declare function macosFenceProfile(fence: readonly string[], grants?: FenceGrants): string;
|
|
48
190
|
export declare const SANDBOX_EXEC = "/usr/bin/sandbox-exec";
|
|
49
191
|
/**
|
|
50
192
|
* Whether this machine can run an agent inside the macOS fence (checked once). Not from inside another
|
|
@@ -58,13 +200,16 @@ export declare function macosFenceAvailable(platform?: NodeJS.Platform, probe?:
|
|
|
58
200
|
stderr: string;
|
|
59
201
|
}): boolean;
|
|
60
202
|
/** The spawn that runs `file args` inside the macOS fence (same process: sandbox-exec replaces itself with the agent). */
|
|
61
|
-
export declare function macosFenced(file: string, args: readonly string[], fence: readonly string[]): {
|
|
203
|
+
export declare function macosFenced(file: string, args: readonly string[], fence: readonly string[], grants?: FenceGrants): {
|
|
62
204
|
file: string;
|
|
63
205
|
args: string[];
|
|
64
206
|
};
|
|
65
207
|
export declare function linuxFenceAvailable(platform?: NodeJS.Platform, probe?: () => boolean): boolean;
|
|
66
|
-
/** The spawn that runs `file args` inside the Linux fence: the whole filesystem as it is,
|
|
67
|
-
|
|
208
|
+
/** The spawn that runs `file args` inside the Linux fence: the whole filesystem as it is, the checkout pools masked
|
|
209
|
+
* and the build's own checkout bound back read-write over them, then every fenced path masked whole (an empty
|
|
210
|
+
* folder, or /dev/null for a file), so what is made there after launch is masked too; then only the explicit grants
|
|
211
|
+
* bound back read-only (bubblewrap binds from the original root, so a grant inside a mask still reaches its files). */
|
|
212
|
+
export declare function linuxFenced(file: string, args: readonly string[], fence: readonly string[], grants?: FenceGrants): {
|
|
68
213
|
file: string;
|
|
69
214
|
args: string[];
|
|
70
215
|
};
|