@kortix/agent-tunnel 0.13.41 → 0.13.42
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 +120 -11
- package/dist/agent-cli.js +1144 -435
- package/dist/client-cli.js +1 -3
- package/package.json +1 -1
- package/src/agent/access.test.ts +164 -0
- package/src/agent/access.ts +176 -0
- package/src/agent/agent.test.ts +641 -0
- package/src/agent/agent.ts +333 -10
- package/src/agent/capabilities/security.test.ts +20 -1
- package/src/agent/cli-device-auth.test.ts +114 -0
- package/src/agent/cli-reauth.test.ts +108 -8
- package/src/agent/cli.ts +201 -57
- package/src/agent/config.test.ts +5 -0
- package/src/agent/config.ts +17 -2
- package/src/agent/credential-probe.ts +3 -3
- package/src/agent/credential-store.ts +2 -2
- package/src/agent/device-auth.test.ts +57 -0
- package/src/agent/device-auth.ts +45 -3
- package/src/agent/security/path-validator.ts +3 -1
- package/src/agent/service-control.ts +5 -2
- package/src/agent/service-drivers.test.ts +164 -0
- package/src/agent/service-drivers.ts +205 -56
- package/src/agent/service-lifecycle.test.ts +32 -18
- package/src/agent/service-paths.ts +42 -10
- package/src/agent/service.test.ts +126 -5
- package/src/agent/service.ts +99 -12
- package/src/agent/state-file.test.ts +32 -0
- package/src/agent/state-file.ts +58 -0
- package/src/client/tunnel-client.ts +6 -3
- package/src/server/ws-handler.test.ts +31 -1
- package/src/server/ws-handler.ts +3 -3
- package/src/shared/types.ts +12 -0
package/README.md
CHANGED
|
@@ -2,16 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
`@kortix/agent-tunnel` connects a local computer to Kortix through an authenticated reverse tunnel.
|
|
4
4
|
|
|
5
|
+
Each connected computer is an account of a project's **computer** connector,
|
|
6
|
+
private to the person who connected it unless they share it with the project.
|
|
7
|
+
The Kortix desktop app bundles this agent and connects in one click. Without
|
|
8
|
+
the desktop app, use the command below.
|
|
9
|
+
|
|
5
10
|
## Connect once
|
|
6
11
|
|
|
7
|
-
Run the command shown
|
|
8
|
-
the device code in your browser:
|
|
12
|
+
Run the command shown under **Connect your computer** in a project. Then
|
|
13
|
+
approve the device code in your browser:
|
|
9
14
|
|
|
10
15
|
```bash
|
|
11
16
|
npx --yes @kortix/agent-tunnel@latest connect \
|
|
12
|
-
--api-url https://api.kortix.com/v1/tunnel
|
|
17
|
+
--api-url https://api.kortix.com/v1/tunnel \
|
|
18
|
+
--project-id <project-uuid>
|
|
13
19
|
```
|
|
14
20
|
|
|
21
|
+
The computer belongs to you in every project and workspace you are a member
|
|
22
|
+
of, in your private sessions. `--project-id` only offers "Also share with
|
|
23
|
+
<project>" on the approval page; without it the computer is still yours
|
|
24
|
+
everywhere.
|
|
25
|
+
|
|
15
26
|
After approval, the interactive flow asks whether it should install a persistent background service. The default answer is yes.
|
|
16
27
|
|
|
17
28
|
## Run in the background
|
|
@@ -25,7 +36,30 @@ npx --yes @kortix/agent-tunnel@latest connect \
|
|
|
25
36
|
```
|
|
26
37
|
|
|
27
38
|
The service uses LaunchAgent on macOS, a user systemd service on Linux, and Task Scheduler on Windows.
|
|
28
|
-
It starts at login and
|
|
39
|
+
It starts at login, and the supervisor restarts it after every exit (launchd
|
|
40
|
+
`KeepAlive` with a 10 s throttle, systemd `Restart=always`, a 5 s Windows loop).
|
|
41
|
+
On Linux, install enables `loginctl enable-linger` so the user service keeps
|
|
42
|
+
running after logout and starts at boot; when that is not allowed, install
|
|
43
|
+
prints a warning. The Windows task runs hidden, on battery, with no time limit.
|
|
44
|
+
The agent itself never stops on its own:
|
|
45
|
+
|
|
46
|
+
- It reconnects with exponential backoff from 1 s to 30 s, ±20 % jitter, forever.
|
|
47
|
+
- It drops a socket that received no relay ping for 75 s, and it reconnects at
|
|
48
|
+
once after the machine wakes from sleep (a 5 s timer that sees a jump of more
|
|
49
|
+
than 30 s). A wake resets the backoff.
|
|
50
|
+
- A refused credential puts it in state `rejected`. It checks `config.json`
|
|
51
|
+
every 5 s and connects as soon as a new pairing writes another credential;
|
|
52
|
+
it also retries the old one every 5 minutes.
|
|
53
|
+
- The relay accepts 5 connections per machine per minute. A process that
|
|
54
|
+
restarts faster than that waits up to 12 s for the next slot.
|
|
55
|
+
- A second process with the same credential puts it in state `standby`. It
|
|
56
|
+
tries again after 1 minute, doubling each time up to 30 minutes, so two
|
|
57
|
+
holders of one credential do not trade the connection back and forth.
|
|
58
|
+
- A handshake that does not reach `auth_ok` within 20 s is dropped and retried.
|
|
59
|
+
- No saved credential: it waits and checks `config.json` every 60 s.
|
|
60
|
+
|
|
61
|
+
It changes the computer's sleep settings only when `access.json` sets
|
|
62
|
+
`keepAwake` (see below).
|
|
29
63
|
|
|
30
64
|
## Manage the background service
|
|
31
65
|
|
|
@@ -33,10 +67,24 @@ It starts at login and restarts after failures. It does not change the computer'
|
|
|
33
67
|
npx --yes @kortix/agent-tunnel@latest service-status
|
|
34
68
|
npx --yes @kortix/agent-tunnel@latest logs
|
|
35
69
|
npx --yes @kortix/agent-tunnel@latest restart
|
|
36
|
-
npx --yes @kortix/agent-tunnel@latest stop
|
|
70
|
+
npx --yes @kortix/agent-tunnel@latest stop # pause: stays stopped after login and reboot
|
|
71
|
+
npx --yes @kortix/agent-tunnel@latest start # resume
|
|
37
72
|
npx --yes @kortix/agent-tunnel@latest uninstall-service
|
|
73
|
+
npx --yes @kortix/agent-tunnel@latest logout # remove this computer from Kortix, then sign out
|
|
38
74
|
```
|
|
39
75
|
|
|
76
|
+
`stop` disables the job (`launchctl disable`, `systemctl --user disable --now`,
|
|
77
|
+
`schtasks /Change /DISABLE`), so it stays stopped until `start`.
|
|
78
|
+
|
|
79
|
+
`logout` first calls `DELETE /v1/tunnel/self` with the machine's own credential,
|
|
80
|
+
which removes the machine and its accounts in Kortix. It then clears the local
|
|
81
|
+
credential and removes the service. If Kortix cannot be reached, the local
|
|
82
|
+
sign-out still completes; `logout --json` then reports `"serverUnpaired": false`.
|
|
83
|
+
|
|
84
|
+
`service-status --json` prints the pairing, the service (`installed`, `active`,
|
|
85
|
+
`enabled` = not paused, `upToDate` = the unit matches what `install-service`
|
|
86
|
+
writes now), the live connection state, and `access`.
|
|
87
|
+
|
|
40
88
|
Credentials are stored in `~/.agent-tunnel/config.json`. Agent Tunnel requires
|
|
41
89
|
the file to be regular, owned by the current user, and mode `0600` on POSIX.
|
|
42
90
|
Protect the operating-system account because this setup token can authenticate
|
|
@@ -45,16 +93,77 @@ the machine until you rotate or delete the connection.
|
|
|
45
93
|
Remote API URLs must use HTTPS. Plain HTTP is accepted only for `localhost`,
|
|
46
94
|
`127.0.0.1`, and `::1` development endpoints.
|
|
47
95
|
|
|
96
|
+
## Files and isolation
|
|
97
|
+
|
|
98
|
+
| Path (under the config directory) | Content |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `config.json` | Credential and local limits, mode `0600`. |
|
|
101
|
+
| `state.json` | `{ tunnelId, apiUrl, status: online\|offline\|connecting\|rejected\|standby, since, agentVersion, pid }`, rewritten atomically on every connection change. No credential. |
|
|
102
|
+
| `access.json` | `{ mode: ask\|always\|off, grantedUntil, deniedUntil, keepAwake }`, mode `0600`. See "Access control". |
|
|
103
|
+
| `access-request.json` | `{ id, requestedAt, capability, method }`: the call waiting for the owner. |
|
|
104
|
+
| `desktop-app.json` | Written by the Kortix desktop app: how to start it to show an access prompt. |
|
|
105
|
+
| `logs/` | Service output. |
|
|
106
|
+
|
|
107
|
+
`AGENT_TUNNEL_HOME` replaces the config directory (default `~/.agent-tunnel`).
|
|
108
|
+
A non-default directory also gets its own service,
|
|
109
|
+
`ai.kortix.agent-tunnel.<first 8 hex of sha256(directory)>`, so a second
|
|
110
|
+
identity never replaces the default `ai.kortix.agent-tunnel` service. The
|
|
111
|
+
service definition carries `AGENT_TUNNEL_HOME` into the service environment.
|
|
112
|
+
|
|
113
|
+
## Access control
|
|
114
|
+
|
|
115
|
+
The machine decides, before every call, whether an agent may use it.
|
|
116
|
+
`access.json` holds the owner's answer:
|
|
117
|
+
|
|
118
|
+
| `mode` | Effect |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `always` | Every call runs. A machine without `access.json` behaves like this. |
|
|
121
|
+
| `ask` | A call runs while `grantedUntil` is in the future (at most 24 h ahead). Otherwise the agent writes `access-request.json`, starts the desktop app if it is not running, and holds the call for 20 s. A grant runs it. No answer returns `-32010 computer_access_pending`. A denial sets `deniedUntil` 10 minutes ahead and returns `-32011 computer_access_denied`; calls fail at once until then. |
|
|
122
|
+
| `off` | Every call returns `-32012 computer_access_off`. |
|
|
123
|
+
|
|
124
|
+
A pairing made from the Kortix desktop app starts in `ask`: the app shows the
|
|
125
|
+
prompt. A pairing made with this CLI alone starts in `always`, because nothing
|
|
126
|
+
on the machine could answer a prompt. This is a deliberate deviation from
|
|
127
|
+
"new pairings default to ask". Every new pairing resets `access.json`, so a
|
|
128
|
+
grant or `always` from an earlier pairing never carries over, and `logout`
|
|
129
|
+
deletes it. The agent home (`config.json`, `access.json`, `desktop-app.json`)
|
|
130
|
+
is always a blocked path: no file or shell call can change these files. The agent reports `{ mode, grantedUntil }`
|
|
131
|
+
to Kortix as the signed notification `tunnel.access.state` on connect and on
|
|
132
|
+
every change.
|
|
133
|
+
|
|
134
|
+
`keepAwake: true` keeps the computer from sleeping while the agent runs:
|
|
135
|
+
`caffeinate -s` on macOS (on AC power only), `systemd-inhibit --what=sleep` on
|
|
136
|
+
Linux. Windows is not supported.
|
|
137
|
+
|
|
138
|
+
## Machine-readable connect
|
|
139
|
+
|
|
140
|
+
`connect --json` prints newline-delimited JSON events on stdout instead of the
|
|
141
|
+
terminal UI. It never prompts and never opens a browser; the caller shows the
|
|
142
|
+
approval URL.
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{"event":"challenge","deviceCode":"ABCD-1234","verificationUrl":"https://…","expiresAt":"…"}
|
|
146
|
+
{"event":"approved","tunnelId":"…","capabilities":["filesystem","shell"]}
|
|
147
|
+
{"event":"service","action":"install","ok":true,"active":true,"detail":"…"}
|
|
148
|
+
{"event":"error","message":"…"}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`approved` carries `"existing": true` when a saved pairing was still valid.
|
|
152
|
+
`service` follows only with `--daemon`.
|
|
153
|
+
|
|
154
|
+
Run under Electron (`ELECTRON_RUN_AS_NODE=1`), the installed service runs the
|
|
155
|
+
same Electron binary with `ELECTRON_RUN_AS_NODE=1` and the bundle in place.
|
|
156
|
+
|
|
48
157
|
## Permission boundaries
|
|
49
158
|
|
|
50
|
-
Kortix checks
|
|
51
|
-
|
|
52
|
-
|
|
159
|
+
Kortix checks that the session may use the computer account (owner,
|
|
160
|
+
sharing, and connector policies such as `require_approval`) before relaying an
|
|
161
|
+
operation. The capabilities approved at pairing are fixed; pair again to change
|
|
162
|
+
them. The local agent then checks the operation again.
|
|
53
163
|
|
|
54
|
-
The local config is the maximum boundary.
|
|
164
|
+
The local config is the maximum boundary. The server cannot widen configured
|
|
55
165
|
filesystem paths, blocked paths, shell commands, timeouts, file sizes, or desktop
|
|
56
|
-
features.
|
|
57
|
-
Use scoped permissions and short expiries for sensitive machines.
|
|
166
|
+
features.
|
|
58
167
|
|
|
59
168
|
## Computer Use driver
|
|
60
169
|
|