@gjermundgaraba/clankerbox-rivet-sandbox-agent 0.19.0 → 0.20.1

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/index.d.mts CHANGED
@@ -22,13 +22,19 @@ interface Options {
22
22
  readonly namePrefix?: string | undefined;
23
23
  /** The machine's own login user by default. */
24
24
  readonly sshUser?: string | undefined;
25
+ /**
26
+ * The path of a public-key file, such as your `id_ed25519.pub`, whose keys the host installs for
27
+ * the login user after a profile's setup, as the client config's `authorizedKeys` does: the key
28
+ * the tunnel's ssh logs in with. A profile with a setup needs it.
29
+ */
30
+ readonly authorizedKeys?: string | undefined;
25
31
  /**
26
32
  * Such as `["-i", "/path/to/key"]`. Neither these nor ssh config may fork the forward (`-f`,
27
33
  * `-N`, `ForkAfterAuthentication`, `SessionType none`) or give it to a connection master (`-M`,
28
34
  * `-S`): the tunnel ends with its ssh, and those would outlive it.
29
35
  */
30
36
  readonly sshArguments?: ReadonlyArray<string> | undefined;
31
- /** `/home/sandbox` by default, as the recipes make it. */
37
+ /** `/home/user` by default, the login user's home, where the Ubuntu recipe runs the server. */
32
38
  readonly cwd?: string | undefined;
33
39
  }
34
40
  /**
package/dist/index.mjs CHANGED
@@ -198,7 +198,7 @@ const make = (options, ssh = "ssh") => {
198
198
  machine: from.machine,
199
199
  name: named
200
200
  });
201
- const { spec, host } = yield* specRequest("create", yield* loadProfile(from.profile), {});
201
+ const { spec, host } = yield* specRequest("create", yield* loadProfile(from.profile), { authorizedKeys: options.authorizedKeys });
202
202
  const { machine } = yield* Prebuild.create(client, named, spec, {
203
203
  host,
204
204
  fresh: options.fresh
@@ -244,7 +244,7 @@ const provider = (options, layer, ssh) => {
244
244
  const sandboxes = make(options, ssh);
245
245
  return {
246
246
  name,
247
- defaultCwd: options.cwd ?? "/home/sandbox",
247
+ defaultCwd: options.cwd ?? "/home/user",
248
248
  create: () => runtime.runPromise(sandboxes.create),
249
249
  destroy: (id) => runtime.runPromise(sandboxes.destroy(id)),
250
250
  pause: (id) => runtime.runPromise(sandboxes.pause(id)),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjermundgaraba/clankerbox-rivet-sandbox-agent",
3
- "version": "0.19.0",
3
+ "version": "0.20.1",
4
4
  "description": "clankerbox machines as sandboxes for Rivet's Sandbox Agent",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -25,7 +25,7 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@gjermundgaraba/clankerbox-sdk": "0.19.0"
28
+ "@gjermundgaraba/clankerbox-sdk": "0.20.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@effect/platform-node": "4.0.5",
@@ -1,13 +1,13 @@
1
1
  #!/bin/sh
2
2
  # A clankerbox setup that makes a macOS machine (Tart, a Cirrus base) a sandbox for Rivet's
3
- # Sandbox Agent: your key for `admin`, the Sandbox Agent's server and Claude Code under `admin`,
4
- # a LaunchDaemon that runs the server on the guest's loopback, port 2468, and an
5
- # /etc/clankerbox/start that keeps it running. Give the provider `cwd: "/Users/admin"`.
3
+ # Sandbox Agent: the Sandbox Agent's server and Claude Code under `admin`, the login user, for
4
+ # whom the host then installs your keys, a LaunchDaemon that runs the server on the guest's
5
+ # loopback, port 2468, and an /etc/clankerbox/start that keeps it running. Give the provider
6
+ # `cwd: "/Users/admin"`.
6
7
  #
7
- # Copy this directory, put the public keys that may log in into `authorized_keys` beside this
8
- # file, and name the copy as a profile's `setup.path`. An optional `agent.env` beside it, of
9
- # `NAME=value` lines such as `ANTHROPIC_API_KEY=…`, becomes the server's environment, which is
10
- # where the agents it launches find their credentials.
8
+ # Name this directory, or a copy, as a profile's `setup.path`. An optional `agent.env` beside
9
+ # it, of `NAME=value` lines such as `ANTHROPIC_API_KEY=…`, becomes the server's environment,
10
+ # which is where the agents it launches find their credentials.
11
11
  set -eu
12
12
  PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
13
13
 
@@ -18,19 +18,11 @@ agent_sha256=58417cf5fa1e2dc417fc4a92d11840cc245ad599b87dd4c9a41686b05c36d877
18
18
  node_version=22.23.3
19
19
  node_sha256=23b25245dcfb9af7262f8ff142e9e2e0af025368117329e7a7458a51e5922f53
20
20
 
21
- if [ ! -s authorized_keys ]; then
22
- echo "this recipe needs an authorized_keys file beside setup.sh, holding your public key"
23
- exit 1
24
- fi
25
-
26
21
  # Softnet blocks the gateway's DNS, so public resolvers come first.
27
22
  networksetup -listallnetworkservices | tail -n +2 | sed 's/^\*//' | while IFS= read -r service; do
28
23
  networksetup -setdnsservers "$service" 1.1.1.1 9.9.9.9
29
24
  done
30
25
 
31
- install -d -m 700 -o admin -g staff /Users/admin/.ssh
32
- install -m 600 -o admin -g staff authorized_keys /Users/admin/.ssh/authorized_keys
33
-
34
26
  # Downloads $1 to $3 and refuses it unless its sha256 is $2.
35
27
  fetch() {
36
28
  curl -fsSL "$1" -o "$3"
@@ -1,12 +1,13 @@
1
1
  #!/bin/sh
2
2
  # A clankerbox setup that makes an x86_64 Ubuntu machine a sandbox for Rivet's Sandbox Agent:
3
- # sshd with your key, the Sandbox Agent's server and Claude Code under a `sandbox` user, and an
4
- # /etc/clankerbox/start that keeps the server running on the guest's loopback, port 2468.
3
+ # the login user `user` with passwordless sudo, for whom the host then installs your keys, sshd
4
+ # with root's login off where this recipe installs it, the Sandbox Agent's server and Claude Code
5
+ # under `user`, and an /etc/clankerbox/start that keeps the server running on the guest's
6
+ # loopback, port 2468.
5
7
  #
6
- # Copy this directory, put the public keys that may log in into `authorized_keys` beside this
7
- # file, and name the copy as a profile's `setup.path`. An optional `agent.env` beside it, of
8
- # `NAME=value` lines such as `ANTHROPIC_API_KEY=…`, becomes the server's environment, which is
9
- # where the agents it launches find their credentials.
8
+ # Name this directory, or a copy, as a profile's `setup.path`. An optional `agent.env` beside
9
+ # it, of `NAME=value` lines such as `ANTHROPIC_API_KEY=…`, becomes the server's environment,
10
+ # which is where the agents it launches find their credentials.
10
11
  set -eu
11
12
  PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
12
13
  export DEBIAN_FRONTEND=noninteractive
@@ -19,17 +20,27 @@ agent_sha256=5ebefccb130cccb0aa7972eacc8ff7c55550b959b2dd682a232a21a5712d955e
19
20
  node_version=22.23.3
20
21
  node_sha256=df450af89261115ef9f9e3830c3eeb2cc9213b63c720b1af623cb5dcbe2e02de
21
22
 
22
- if [ ! -s authorized_keys ]; then
23
- echo "this recipe needs an authorized_keys file beside setup.sh, holding your public key"
24
- exit 1
25
- fi
23
+ # A base with its own sshd, such as boat's, keeps it as it is.
24
+ if [ -x /usr/sbin/sshd ]; then own_sshd=false; else own_sshd=true; fi
26
25
 
27
26
  apt-get update -qq
28
27
  apt-get install -y -qq --no-install-recommends \
29
- openssh-server curl ca-certificates xz-utils procps >/dev/null
28
+ openssh-server sudo curl ca-certificates xz-utils procps >/dev/null
30
29
 
31
- install -d -m 700 /root/.ssh
32
- install -m 600 authorized_keys /root/.ssh/authorized_keys
30
+ if [ "$own_sshd" = true ]; then
31
+ install -d /etc/ssh/sshd_config.d
32
+ echo "PermitRootLogin no" >/etc/ssh/sshd_config.d/10-clankerbox.conf
33
+ fi
34
+
35
+ # The login user, which boat's bases already have.
36
+ if ! id user >/dev/null 2>&1; then
37
+ useradd -m -s /bin/bash user
38
+ fi
39
+
40
+ echo "user ALL=(ALL) NOPASSWD: ALL" >/var/tmp/sudoers-user
41
+ visudo -cf /var/tmp/sudoers-user >/dev/null
42
+ install -m 440 /var/tmp/sudoers-user /etc/sudoers.d/user
43
+ rm /var/tmp/sudoers-user
33
44
 
34
45
  # Downloads $1 to $3 and refuses it unless its sha256 is $2.
35
46
  fetch() {
@@ -47,18 +58,16 @@ fetch "https://nodejs.org/dist/v$node_version/node-v$node_version-linux-x64.tar.
47
58
  tar -xJf /var/tmp/node.tar.xz -C /usr/local --strip-components=1 --no-same-owner
48
59
  rm /var/tmp/node.tar.xz
49
60
 
50
- # The agents run as their own user: as root, Claude Code offers no bypass-permissions mode.
51
- useradd -m -s /bin/bash sandbox
52
-
61
+ # The agents run as `user`: as root, Claude Code offers no bypass-permissions mode.
53
62
  if [ -s agent.env ]; then
54
- install -m 600 -o sandbox -g sandbox agent.env /etc/sandbox-agent.env
63
+ install -m 600 -o user -g "$(id -gn user)" agent.env /etc/sandbox-agent.env
55
64
  fi
56
65
 
57
66
  # Claude Code at its latest release, and its adapter at the version the server pins. Other
58
67
  # agents install the same way; `install-agent codex` hangs in its own check at this version, so
59
68
  # give it a timeout too, and end what it leaves running. Claude's install takes about 30 s; 300 s
60
69
  # leaves room for a slow mirror.
61
- timeout 300 su - sandbox -c 'sandbox-agent install-agent claude' >/var/tmp/install-agent.log 2>&1 || {
70
+ timeout 300 su - user -c 'sandbox-agent install-agent claude' >/var/tmp/install-agent.log 2>&1 || {
62
71
  tail -n 15 /var/tmp/install-agent.log
63
72
  exit 1
64
73
  }
@@ -94,17 +103,17 @@ answers_within() {
94
103
  }
95
104
 
96
105
  running() {
97
- pgrep -u sandbox -f 'sandbox-agent server' >/dev/null
106
+ pgrep -u user -f 'sandbox-agent server' >/dev/null
98
107
  }
99
108
 
100
109
  # A running server gets 10 s to answer, since this runs at every start, a running machine's too,
101
110
  # before it is ended as hung: TERM, then KILL after 5 s, as a hung one may ignore TERM.
102
111
  if running && ! answers_within 10; then
103
- pkill -u sandbox -f 'sandbox-agent server' || true
112
+ pkill -u user -f 'sandbox-agent server' || true
104
113
  for tries in $(seq 40); do
105
114
  running || break
106
115
  if [ "$tries" -eq 20 ]; then
107
- pkill -KILL -u sandbox -f 'sandbox-agent server' || true
116
+ pkill -KILL -u user -f 'sandbox-agent server' || true
108
117
  fi
109
118
  sleep 0.25
110
119
  done
@@ -112,7 +121,7 @@ fi
112
121
 
113
122
  # The server listens on loopback alone, with no token: guest port 22 is the only way to it.
114
123
  if ! running; then
115
- su - sandbox -c '
124
+ su - user -c '
116
125
  if [ -r /etc/sandbox-agent.env ]; then set -a; . /etc/sandbox-agent.env; set +a; fi
117
126
  setsid -f sandbox-agent server --no-token --no-telemetry >/dev/null 2>&1
118
127
  '