@cabane/companion 0.6.214 → 0.6.216
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -7
- package/dist/cli.js +410 -190
- package/dist/credential-broker.js +653 -0
- package/dist/launch.js +4 -1
- package/dist/pairing-config.js +100 -37
- package/dist/runtime.js +44 -8
- package/package.json +10 -1
package/README.md
CHANGED
|
@@ -10,24 +10,40 @@ Pairing supplies a device token, not your Cabane password or a full-account toke
|
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
On the device, in a terminal. One of:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
curl -fsSL https://cabane.ai/install.sh | bash
|
|
16
|
+
curl -fsSL https://cabane.ai/install.sh | bash
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
The script brings its own Node (checksum-checked, into `~/.cabane`) and needs no sudo. Or, with Node 22 or newer already there (the only route on Windows):
|
|
20
20
|
|
|
21
21
|
```sh
|
|
22
|
-
npm i -g @cabane/companion && cabane setup
|
|
22
|
+
npm i -g @cabane/companion && cabane setup
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
`cabane setup
|
|
25
|
+
`cabane setup` on an unpaired device prints a code and a link:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Pair this device
|
|
29
|
+
Enter this code in Cabane, or press Return to open the page:
|
|
30
|
+
|
|
31
|
+
WXYZ-2345
|
|
32
|
+
https://app.cabane.ai/pair/enter-code?code=WXYZ-2345
|
|
33
|
+
|
|
34
|
+
⠋ Waiting for you to confirm in Cabane… (the code is good for 15 minutes)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Enter the code in Cabane, signed in as yourself: from your own Settings → Devices → Add a device, from a workspace's Settings → Devices → Set up a new device, or on the page the link opens. Cabane shows which device asked; confirming pairs it to your account and nothing else. A workspace's dialog then adds the device to that workspace; from anywhere else, add it to a workspace from that workspace's Settings → Devices. Pairing from a workspace you're setting up places its default agent on the device once a harness there is usable.
|
|
38
|
+
|
|
39
|
+
Without a terminal, setup prints the same lines once and waits, so a container's logs carry the code. An expired code is replaced by a fresh one, up to three; Ctrl-C stops cleanly. The link is on the server the device pairs with: pass `--server <url>` for your own Cabane.
|
|
40
|
+
|
|
41
|
+
From an interactive terminal, setup then starts the Companion in the background, waits for its first check-in and reports the device's state. Without an interactive terminal, setup stays attached to the running Companion.
|
|
26
42
|
|
|
27
43
|
If no harness is usable, interactive setup asks which one you want to set up. Follow the complete CLI installation and sign-in steps for [Mac setup](https://cabane.ai/docs/mac-setup#2-sign-in), [Windows setup](https://cabane.ai/docs/windows-setup#2-sign-in) or [Server and VPS setup](https://cabane.ai/docs/server-and-vps-setup#2-sign-in-without-a-browser), then check `cabane status`.
|
|
28
44
|
|
|
29
45
|
```
|
|
30
|
-
✓ Paired as "maya-mbp"
|
|
46
|
+
✓ Paired as "maya-mbp".
|
|
31
47
|
Cabane is running in the background. This device is ready — checked in 2s ago.
|
|
32
48
|
|
|
33
49
|
Harnesses on this device
|
|
@@ -38,7 +54,7 @@ If no harness is usable, interactive setup asks which one you want to set up. Fo
|
|
|
38
54
|
Status cabane status Stop cabane stop Log cabane logs
|
|
39
55
|
Start at login and keep Cabane updating itself: cabane service install
|
|
40
56
|
|
|
41
|
-
In Cabane: https://app.cabane.ai/
|
|
57
|
+
In Cabane: https://app.cabane.ai/settings/devices
|
|
42
58
|
```
|
|
43
59
|
|
|
44
60
|
Setup never installs the service. On macOS or Linux, run `cabane service install` when you want the Companion to start at login and keep itself updated; the closing block names it. Native Windows uses the background process and has no service installer.
|
|
@@ -51,7 +67,7 @@ The [server guide](https://cabane.ai/docs/server-and-vps-setup) provides a Docke
|
|
|
51
67
|
|
|
52
68
|
| Command | What it does |
|
|
53
69
|
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
-
| `setup
|
|
70
|
+
| `setup` | Unpaired: print a code to enter in Cabane, wait for the confirm, then detect harnesses and start. Paired: a re-runnable checklist that reports harnesses and starts what isn't running. |
|
|
55
71
|
| `start [--foreground]` | Start the Companion without prompts. From an interactive terminal, run in the background; noninteractive use may stay attached. Unpaired, it names `setup`. `--foreground` stays attached for your supervisor. |
|
|
56
72
|
| `stop` | Stop the Companion cleanly. Ends any turn in progress. |
|
|
57
73
|
| `status` | Version and install, the paired device by its Cabane name, its state in Cabane's words and when it last checked in, each harness's state, where agents work, declared secret names, and local overrides. |
|
|
@@ -136,6 +152,24 @@ What your command can rely on, and can set:
|
|
|
136
152
|
|
|
137
153
|
These names are a contract: changing one would break your command, so none changes without a note in the release.
|
|
138
154
|
|
|
155
|
+
### Keeping provider credentials outside a sandbox
|
|
156
|
+
|
|
157
|
+
An operator-managed sandbox can use the host-side `@cabane/companion/credential-broker` module. This is an embedding API for a trusted host adapter, not a proxy that becomes safe by listening on localhost. The adapter must authenticate the accepted socket as one live sandbox instance and revoke its grants when that instance is stopped. A shared UID, a copied placeholder, a socket filename or an HTTP header is not an instance identity. An unresolved, ambiguous or changed identity must return `null` from `resolveIdentity(socket)`.
|
|
158
|
+
|
|
159
|
+
Run the broker and its credential files under a host identity outside every sandbox UID mapping. Hold an exclusive process lock for the entire service lifetime, including shutdown: there must be exactly one renewal owner for each account file. The parent of an account file must be owned by that identity with mode `0700`; the file must be a regular, single-link `0600` file. Stop the service before importing or changing login state. `fileCredentialStore(path)` and `openBrokerCredentials(store)` read that state; share the resulting owner between every grant using the account. Renewal writes and fsyncs a replacement before releasing it. A failed persistence write refuses further use until the operator recovers the stored account.
|
|
160
|
+
|
|
161
|
+
The account format is `{ mode, accessToken, refreshToken?, idToken?, expiresAt?, accountId? }`. `mode` is `claude-setup`, `claude-oauth`, `codex-oauth` or `github`. OAuth modes require a refresh token and an expiry in epoch milliseconds. A setup token never renews. Normal Claude OAuth renews inside the broker before expiry, or on one upstream 401; Codex renewal returns fresh placeholders to its client. Never place the real account file, a credential-store bind, or an alternate harness login inside the sandbox. Real OAuth compatibility must be verified with the installed harness and login mode; a successful setup-token turn proves nothing about OAuth renewal.
|
|
162
|
+
|
|
163
|
+
Create the broker with `createCredentialBroker({ resolveIdentity, audit? })`. Its `server` handles model and git routes; bind it only to host loopback. Git's HTTP proxy requests are accepted only for the exact `http://github.com/` authority, then forwarded to fixed HTTPS GitHub upstreams. Arbitrary proxy destinations and CONNECT tunnels are refused. Its `githubServer` handles gh's `http_unix_socket` transport; authenticate that socket's peer too. Neither exposes a management endpoint. Call `grant({ identity, credentials, expiresAt })` only from the trusted host adapter. `credentials` maps `claude`, `codex` and `github` to their corresponding credential owners. The returned `token` is disposable; `revoke()` aborts active requests and removes its aliases. Teardown calls `revokeIdentity(identity)`; service shutdown calls `revokeAll()` and closes both servers. A restart creates fresh grants, so old placeholders stop working.
|
|
164
|
+
|
|
165
|
+
Scope the GitHub token on GitHub's side; the broker imposes no repository, branch, PR-action or GraphQL-shape policy.
|
|
166
|
+
|
|
167
|
+
Set `runner.brokeredCredentials: true` beside `runner.command` in the Companion config. This removes provider and GitHub credential variables from the launcher's environment, secret-store payload and device-grant payload before the wrapper receives them. The wrapper supplies `brokerClientConfiguration({ baseUrl, placeholder, githubSocket, codexConfig })`'s environment and generated configuration to the isolated home, and writes `await grant.codexAuth()` as its placeholder-only Codex `auth.json`. The helper preserves the supplied Codex settings while selecting the broker provider and HTTP Responses transport. Include its git configuration in the sandbox's global config and use its gh configuration there. For a GitHub-enabled box, provide `githubSocket`. The helper sets `GH_TOKEN` and preserves `github.com` in git's expanded remote so gh can resolve a tracked branch, without setting `GH_REPO`. The generated git config rewrites HTTPS URLs to an HTTP GitHub URL carrying only a placeholder, and sends that origin through the loopback broker using Git's per-origin `http.proxy`; the broker's upstream hop remains HTTPS. Install the entire generated config, replacing the previous generated file, rather than retaining an older rewrite. Do not bypass this proxy with `NO_PROXY` or a per-remote proxy override. For a model-only box, omit `githubSocket` or pass `null`; no GitHub environment is emitted and both git/gh config strings are empty, so an adapter can clear any previous generated routing. The wrapper must remove old credential mounts and alternate authentication helpers; this switch cannot inspect or secure an operator's filesystem mounts.
|
|
168
|
+
|
|
169
|
+
The fixed upstream hosts are `api.anthropic.com`, `chatgpt.com`, `api.github.com` and `github.com`. Paths and request bodies pass through without a workflow policy, except for known credential-minting, credential-registering or disclosure endpoints: Claude CLI API-key creation and OAuth token exchange, ChatGPT session/token disclosure, and GitHub app-manifest conversion, installation/application token endpoints, legacy authorizations, SSH user/deploy-key registration, runner registration/removal/JIT credentials and OAuth/device token endpoints. These return new secrets the echo filter cannot know in advance, or register box-chosen credentials that would outlive the grant. This deny-list must be revisited when providers add credential-returning or credential-registering routes; it is not a guarantee against unknown endpoints or arbitrary encodings. Redirects are refused and responses are filtered for known credential echoes. Credential-free injection is restricted to Codex's designated `/backend-api/ps/mcp` route. Each upstream exchange is capped at ten minutes, and request bodies at 64 MiB.
|
|
170
|
+
|
|
171
|
+
Arbitrary room secrets and other MCP credentials still follow their existing delivery contract. This API does not protect SSH keys or offer general secret injection into arbitrary HTTP destinations. Claude's feature flags fall back to defaults when their direct requests use placeholders. Before enabling a sandbox deployment, verify actual socket ownership, PID/namespace reuse, service UID separation, grant revocation, concurrent renewal and restart, required client operations, and a canary extraction attempt from inside the real sandbox. A successful unit test or package installation does not establish that host boundary.
|
|
172
|
+
|
|
139
173
|
### Harness permissions
|
|
140
174
|
|
|
141
175
|
The Companion approves Claude Code's tools through a hook and approves OpenCode permission requests; no turn waits for a tool-approval dialog. For Codex it disables approvals and, when your configuration sets a top-level `sandbox_mode`, passes no sandbox flag; without that setting it uses `danger-full-access`. Choose where agents run using [Agent access](https://cabane.ai/docs/agent-access), and configure the tools through [Harness sandboxes](https://cabane.ai/docs/harness-sandboxes).
|