@ours.network/fleet 1.2.0-nightly.43 → 1.2.0-nightly.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/build-info.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.2.0-nightly.
|
|
3
|
-
"buildId": "
|
|
4
|
-
"commit": "
|
|
2
|
+
"version": "1.2.0-nightly.44",
|
|
3
|
+
"buildId": "0814e82b7dde",
|
|
4
|
+
"commit": "94ad261abac133a3c17081c1a531a8a363178470",
|
|
5
5
|
"dirty": true,
|
|
6
|
-
"builtAt": "2026-10-
|
|
6
|
+
"builtAt": "2026-10-04T08:52:19.101Z",
|
|
7
7
|
"capabilities": [
|
|
8
8
|
"workspace.enroll.preserve-profile-v1",
|
|
9
9
|
"cowork.http-management-v1",
|
package/dist/session/control.js
CHANGED
|
@@ -567,7 +567,13 @@ export async function controlRequest(stateDir, request, timeoutMs = 120_000) {
|
|
|
567
567
|
socket.once('error', error => {
|
|
568
568
|
clearTimeout(timer);
|
|
569
569
|
const code = error.code;
|
|
570
|
-
|
|
570
|
+
const permissionHint = code === 'EPERM' || code === 'EACCES'
|
|
571
|
+
? `; the operating system denied access before '${request.command}' reached the supervisor. `
|
|
572
|
+
+ 'Check socket permissions and the command execution sandbox. '
|
|
573
|
+
+ 'An existing socket does not prove this process can connect; do not bypass Fleet audit. '
|
|
574
|
+
+ 'For managed workspace sessions, see docs/validation/managed-cli-permissions.md.'
|
|
575
|
+
: '';
|
|
576
|
+
reject(new SessionControlError(code === 'ENOENT' || code === 'ECONNREFUSED' ? 'control-unavailable' : 'backend', `role control socket: ${error.message}${permissionHint}`));
|
|
571
577
|
});
|
|
572
578
|
socket.on('data', chunk => {
|
|
573
579
|
buffer += chunk;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Managed Fleet CLI from Codex and Claude Code workspace sandboxes
|
|
2
|
+
|
|
3
|
+
A managed Fleet CLI invocation sends `fleet_audit_begin` to the supervisor's Unix
|
|
4
|
+
socket before parsing commands, including `--help`. A socket that exists and is
|
|
5
|
+
owned by the current user can still return `connect EPERM` from a restricted
|
|
6
|
+
command sandbox. This is not evidence that the supervisor is down or Fleet needs
|
|
7
|
+
reinstallation. Check filesystem permissions too: `EACCES`/`EPERM` alone does not
|
|
8
|
+
identify which policy denied access.
|
|
9
|
+
|
|
10
|
+
## Use native execution rules, without a new transport
|
|
11
|
+
|
|
12
|
+
Keep the role's `approval: auto`, `filesystem: workspace`, and `unattended: deny`.
|
|
13
|
+
For an operator authorized to manage rooms, explicitly approve the necessary CLI
|
|
14
|
+
operations using Codex's standard execution rules. A matching operation executes
|
|
15
|
+
outside Codex's command sandbox, retaining the normal CLI, supervisor audit,
|
|
16
|
+
configuration, credentials, and confirmation checks. Other shell commands remain
|
|
17
|
+
sandboxed. This does not override an outer container or host sandbox.
|
|
18
|
+
|
|
19
|
+
In the **trusted workspace** create `.codex/rules/ours-fleet.rules`, substituting
|
|
20
|
+
absolute paths to the installed Node binary, installed Fleet CLI, and approved
|
|
21
|
+
configuration. Example for an operator allowed to delete rooms in this Fleet:
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
prefix_rule(
|
|
25
|
+
pattern=["/opt/node/bin/node", "/opt/fleet/dist/cli.js", "room", "delete",
|
|
26
|
+
"--configuration", "/srv/fleet/fleet.yaml", "--json", "--"],
|
|
27
|
+
decision="allow",
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Invoke exactly that prefix, followed by the room ID and the confirmation ID:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
/opt/node/bin/node /opt/fleet/dist/cli.js room delete --configuration /srv/fleet/fleet.yaml --json -- ROOM_ID ROOM_ID
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
To authorize only one room, append both concrete IDs to the rule's pattern.
|
|
38
|
+
The `--` terminator prevents trailing arguments from changing the fixed options.
|
|
39
|
+
Do not approve the entire Node executable or the entire Fleet CLI. Do not add
|
|
40
|
+
`spawn`, `ours call`, arbitrary scripts, or configuration overrides to this rule.
|
|
41
|
+
A separate fixed `[NODE, CLI, "--help"]` rule can authorize managed help.
|
|
42
|
+
|
|
43
|
+
Restart the Codex session after changing rules. Native Fleet and bundled Codex ACP
|
|
44
|
+
use the same workspace rules. Codex must trust that workspace; configure trust
|
|
45
|
+
through the normal operator workflow rather than enabling it from an agent tool.
|
|
46
|
+
No runtime services or installed packages need restarting for this policy change.
|
|
47
|
+
|
|
48
|
+
## Boundaries
|
|
49
|
+
|
|
50
|
+
- A rule grants the named operation real authority. The repeated room ID is CLI
|
|
51
|
+
confirmation, not a substitute for user authorization.
|
|
52
|
+
- Rules apply to trusted Codex sessions in this workspace, not exclusively to one
|
|
53
|
+
Fleet identity. They depend on the launcher's inherited environment. Keep the
|
|
54
|
+
executable, CLI installation, credentials, and configuration outside the
|
|
55
|
+
agent-writable workspace. Do not treat this as an identity isolation feature.
|
|
56
|
+
- User/organization denied-read rules or an outer sandbox may forbid execution
|
|
57
|
+
outside the command sandbox. These restrictions take precedence; do not remove
|
|
58
|
+
them implicitly to make Fleet work.
|
|
59
|
+
- On tested Codex 0.159.0, quoting the executable/script tokens prevented the rule
|
|
60
|
+
from granting execution outside the sandbox. Use the canonical simple-token
|
|
61
|
+
invocation above. Paths needing shell quoting have not been qualified.
|
|
62
|
+
- Merely enabling network inside the Linux command sandbox was insufficient:
|
|
63
|
+
its user namespace maps ancestor directory owners to UID 65534, which the SDK's
|
|
64
|
+
strict credential ancestry checks reject. Approved CLI execution avoids that
|
|
65
|
+
namespace; SDK security checks remain unchanged.
|
|
66
|
+
|
|
67
|
+
## Reproduction and regression checks
|
|
68
|
+
|
|
69
|
+
The [issue author’s validation matrix](https://github.com/adapt-toolkit/ours-fleet/issues/231)
|
|
70
|
+
used Codex 0.159.0 on macOS/Linux, native and ACP. Those results are not new runs
|
|
71
|
+
on every revision of this fixture. Build Fleet and supply the complete installed
|
|
72
|
+
Codex distribution (including its adjacent helper binaries) and a built Cowork CLI.
|
|
73
|
+
Run from the Fleet repo:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
FLEET_CODEX_BIN=/absolute/codex \
|
|
77
|
+
FLEET_COWORK_CLI=/absolute/cowork/dist/cli.js \
|
|
78
|
+
FLEET_TEST_SESSION=codex-app-server \
|
|
79
|
+
FLEET_TEST_TMP_PREFIX=/absolute/private-test-parent/fleet-ipc- \
|
|
80
|
+
node test/fleet-cli-permissions.integration.mjs
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Repeat with `FLEET_TEST_SESSION=acp`. The test parent must be writable, outside
|
|
84
|
+
`/tmp` and outside the tested workspace: ACP may allow `/tmp` independently.
|
|
85
|
+
Omit `FLEET_TEST_SESSION` to test standalone `codex exec`.
|
|
86
|
+
|
|
87
|
+
The local scripted Responses provider supplies only command requests. Real Codex,
|
|
88
|
+
Fleet adapters, CLI, control socket, audit store, daemon, and Cowork perform the
|
|
89
|
+
operations. No external model or production identities/rooms are used. Child processes are stopped and temporary state is removed afterward. To retain
|
|
90
|
+
fixture evidence, set `FLEET_TEST_KEEP_ARTIFACTS=1`. The fixture allowlists its
|
|
91
|
+
launcher environment and uses a disposable HOME; no provider keys, preloads, or
|
|
92
|
+
user configuration are inherited.
|
|
93
|
+
|
|
94
|
+
Checks: baseline network-denied `--help`; permitted help; wrong confirmation
|
|
95
|
+
leaves the room intact; correct confirmation deletes the actual empty test room
|
|
96
|
+
from Fleet and Cowork; caller audit remains present; unrelated outside-workspace
|
|
97
|
+
write, `NODE_OPTIONS` injection, and a different configuration remain denied.
|
|
98
|
+
The fixture uses `OURS_FLEET_SUPERVISOR=none`: launchctl/systemd workers and deletion
|
|
99
|
+
of a live room containing agents are outside this test's coverage.
|
|
100
|
+
|
|
101
|
+
Reference: [Codex execution rules](https://learn.chatgpt.com/docs/agent-configuration/rules).
|
|
102
|
+
|
|
103
|
+
## Claude Code: the same CLI path, different permission settings
|
|
104
|
+
|
|
105
|
+
The issue author verified Claude Code 2.1.284 on macOS and Linux, both standalone and through
|
|
106
|
+
Fleet's bundled Claude ACP adapter (0.63.0). Fleet `approval: auto` maps to
|
|
107
|
+
`acceptEdits`, which is not blanket permission for Bash. Fleet's `filesystem:
|
|
108
|
+
workspace` also does not by itself enable Claude's OS sandbox. Explicitly enable
|
|
109
|
+
it and configure both the execution exclusion and the command permission:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"sandbox": {
|
|
114
|
+
"enabled": true,
|
|
115
|
+
"failIfUnavailable": true,
|
|
116
|
+
"allowUnsandboxedCommands": false,
|
|
117
|
+
"excludedCommands": [
|
|
118
|
+
"/opt/node/bin/node /opt/fleet/dist/cli.js room delete --configuration /srv/fleet/fleet.yaml --json -- *"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"permissions": {
|
|
122
|
+
"allow": [
|
|
123
|
+
"Bash(/opt/node/bin/node /opt/fleet/dist/cli.js room delete --configuration /srv/fleet/fleet.yaml --json -- *)"
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Use operator-controlled Claude settings. The fixture uses an isolated settings
|
|
130
|
+
file delivered with `--settings` (standalone) or Fleet's supported settings overlay
|
|
131
|
+
metadata (bundled ACP). It does not modify the user's settings. As with the Codex
|
|
132
|
+
rule, append exact room IDs instead of `*` to restrict this to one room.
|
|
133
|
+
|
|
134
|
+
`excludedCommands` controls placement outside the command sandbox;
|
|
135
|
+
`permissions.allow` authorizes the action. Neither should be replaced with global
|
|
136
|
+
`bypassPermissions`, blanket `Bash(*)`, or an exception for all Node programs.
|
|
137
|
+
An external sandbox or managed policy can still override this configuration.
|
|
138
|
+
|
|
139
|
+
Linux inside an unprivileged Docker container additionally needed
|
|
140
|
+
`sandbox.enableWeakerNestedSandbox: true`: otherwise bubblewrap failed to mount
|
|
141
|
+
`/proc` before any CLI command ran. This documented setting bind-mounts the
|
|
142
|
+
container's existing `/proc`, weakening that part of the nested isolation. It is
|
|
143
|
+
specific to the nested test environment, not an unconditional Linux requirement.
|
|
144
|
+
The tests still prove Unix-socket denial and filesystem write denial. The outer
|
|
145
|
+
Docker seccomp profile was unconfined to support nesting, as in the Codex tests.
|
|
146
|
+
|
|
147
|
+
Run the same integration scenario with:
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
FLEET_CLAUDE_BIN=/absolute/claude \
|
|
151
|
+
FLEET_COWORK_CLI=/absolute/cowork/dist/cli.js \
|
|
152
|
+
FLEET_TEST_TMP_PREFIX=/absolute/private-test-parent/fleet-claude- \
|
|
153
|
+
FLEET_TEST_SESSION=claude-acp \
|
|
154
|
+
node test/fleet-cli-permissions.integration.mjs
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Omit `FLEET_TEST_SESSION` for standalone Claude. In the nested Linux fixture add
|
|
158
|
+
`FLEET_TEST_NESTED_SANDBOX=1` explicitly. A scripted local Anthropic Messages/SSE
|
|
159
|
+
provider requests the real Bash call and captures the actual tool result. The
|
|
160
|
+
negative baseline grants Bash permission without an exclusion and verifies that
|
|
161
|
+
the supervisor socket is still blocked. The write probe is separately authorized
|
|
162
|
+
inside the sandbox; it must execute and report an OS denial, not merely fail an
|
|
163
|
+
approval prompt. No real model/account credentials are used.
|
|
164
|
+
|
|
165
|
+
All other limits above apply: empty room, isolated audit/control server,
|
|
166
|
+
`supervisor=none` workers, and adapter coverage rather than full production runner.
|
|
167
|
+
|
|
168
|
+
Reference: [Claude sandbox exclusions and permissions](https://code.claude.com/docs/en/sandboxing#run-commands-outside-the-sandbox-with-excludedcommands).
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
## Port validation for issue #231
|
|
172
|
+
|
|
173
|
+
The separate upstream port was rerun on Linux amd64 in a disposable Node 22.23.1
|
|
174
|
+
container with Codex 0.160.0 and Claude Code 2.1.289:
|
|
175
|
+
|
|
176
|
+
| Harness execution | Result |
|
|
177
|
+
| --- | --- |
|
|
178
|
+
| Codex native app-server | PASS |
|
|
179
|
+
| Bundled Codex ACP | PASS |
|
|
180
|
+
| Claude standalone | PASS |
|
|
181
|
+
| Bundled Claude ACP | PASS |
|
|
182
|
+
|
|
183
|
+
Each complete run checks actual socket denial, permitted help, wrong-confirmation
|
|
184
|
+
refusal, deletion of its own empty Fleet/Cowork room, preserved caller audit, and
|
|
185
|
+
OS denial of an unrelated write, preload injection, and alternate configuration.
|
|
186
|
+
The scripted providers and all state are local; external network access is disabled.
|
|
187
|
+
For these nested tests only, the outer Docker seccomp and AppArmor profiles were
|
|
188
|
+
unconfined and Claude used `enableWeakerNestedSandbox: true`. No host policies or
|
|
189
|
+
production services were changed. The inner command sandbox remains enforced by
|
|
190
|
+
the negative checks. These are container results, not a qualification of normal
|
|
191
|
+
host settings. Initial missing-helper and outer-policy failures were retained
|
|
192
|
+
alongside the passing runs; they are not counted as passing tests.
|
|
193
|
+
|
|
194
|
+
The port also passed 88 diagnostic/conversation/audit unit checks, a build, and an
|
|
195
|
+
npm package dry-run check for this document. The diagnostic preserves the prior
|
|
196
|
+
error kinds and audited CLI failure before parsing. This does not claim a fresh
|
|
197
|
+
macOS run, full production runner coverage, or live-agent room deletion.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ours.network/fleet",
|
|
3
|
-
"version": "1.2.0-nightly.
|
|
3
|
+
"version": "1.2.0-nightly.44",
|
|
4
4
|
"description": "Harness-agnostic fleet of persistent, identity-bound AI agents. Declarative fleet.yaml, managed native/ACP sessions, supervision, and ours.network messaging.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "FSL-1.1-Apache-2.0",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"README.md",
|
|
21
21
|
"docs/task-workspaces.md",
|
|
22
22
|
"docs/room-layouts.md",
|
|
23
|
+
"docs/validation/managed-cli-permissions.md",
|
|
23
24
|
"LICENSE"
|
|
24
25
|
],
|
|
25
26
|
"engines": {
|