@intentic/sandbox-run 1.309.0 → 1.311.0

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.
Files changed (2) hide show
  1. package/README.md +29 -58
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,61 +1,32 @@
1
- # @intentic/sandbox-run
2
-
3
- The sandbox container's run contract: every path that creates a sandbox composes its `docker run` from here.
4
-
5
- Names, capability posture, the environment allowlist, runtime directives, and the emitter that turns all of it
6
- into a command line. There are several ways a sandbox comes into existence (the CLI, the daemon, the desktop
7
- app); this package is why they cannot disagree about what one is.
8
-
9
- ## Responsibilities
10
-
11
- - Define the container's identity: its name, image, labels and volumes.
12
- - Define its posture: which capabilities it gets, and which it is denied.
13
- - Bound a local workspace to its share of the machine, and carry the owner's own asks about that share. The
14
- derived memory cap is everything the docker engine has minus a fixed 3 GiB the host keeps (floor 4 GiB,
15
- swap unbounded; `index.ts` says why each of those replaced a fraction and a no-swap rule that froze real
16
- machines). CPUs are unbounded unless asked. Three replayed env vars carry what the owner asked for instead,
17
- said once ON the container and re-emitted onto every container that replaces it: `SANDBOX_MEMORY` (whole
18
- GiB, the number typed: the 4 GiB floor holds, the reserve and the engine's size do not, since the owner may give the
19
- sandbox all of their machine), `SANDBOX_CPUS` (whole cores, at most the engine's), and `SANDBOX_RUNTIME`
20
- (allowlisted directives the owner added beyond the approved overlay's, `--privileged`, `--gpus=all`). The
21
- run carries the UNION of the overlay's directives and the owner's, and stamps the overlay's half on the
22
- container as `SANDBOX_OVERLAY_RUNTIME`, so a reader can tell a capability's demand (which a view draws locked)
23
- from an owner's ask (which they may withdraw). The policy is pure arithmetic so this package stays
24
- browser-importable; the caller that can measure (`intentic sandbox run-command`, inside the image) reads
25
- /proc and the probe's own env for the seeds and passes the results in. Hosted providers keep owning their
26
- machine limits.
27
- - Define the environment allowlist: what is allowed to cross into the box.
28
- - Carry an optional sandbox definition (`definition`, a `sandbox.toml` text) into the box as
29
- `SANDBOX_DEFINITION_SEED` (base64, so its quotes and newlines never meet a shell): the daemon seeds an EMPTY
30
- workspace from it on first boot — repos cloned, connections listed unauthenticated, the overlay parked at the
31
- approval gate — which is how one definition stamps out a fleet.
32
- - Emit the `docker run` invocation, correctly quoted.
1
+ # sandbox-run
2
+
3
+ The sandbox container's run contract: names, privileges, resource caps, the env a recreate replays, and the `docker run` line and Fly Machine config built from them.
4
+
5
+ ```mermaid
6
+ flowchart LR
7
+ ic["ic"] -- "runs the new image's<br/>run-command" --> cli["intentic sandbox<br/>run-command"]
8
+ cli --> run(["sandbox-run"])
9
+ providers["SSH host provider"] --> run
10
+ hosted["Platform api<br/>hosted machines"] --> run
11
+ run -- "docker run argv" --> docker["Docker engine"]
12
+ run -- "flyMachineConfig" --> fly["Fly Machine"]
13
+ ```
14
+
15
+ - One definition for every way a sandbox starts. TypeScript callers import it, so drift is a compile error. `ic`
16
+ runs the target image's own `intentic sandbox run-command` and executes the line it prints, so each image starts
17
+ with its own flags.
18
+ - Privilege arrives only through `RUNTIME_DIRECTIVES`, an allowlist read from an overlay's `# intentic:runtime` lines
19
+ and the owner's `SANDBOX_RUNTIME`. An `OPTIONAL_DIRECTIVES` entry such as `--gpus=all` is probed on the host and
20
+ dropped when the host cannot honour it.
21
+ - `REPLAY_ENV` is what a recreate carries over. `parseNulEnv` reads it NUL-framed because a value can be a multi-line
22
+ private key.
23
+ - `localDaemonPort` derives a sandbox's host loopback port from its id, so a recreate lands on the same port and the
24
+ editor and machine agent compute it without being told.
25
+ - `./quote` holds the shell, SQL and env-file quoters the daemon, providers and CLI share.
33
26
 
34
27
  ## Key files
35
28
 
36
- - [src/index.ts](src/index.ts): the contract and the docker-run emitter; the surface every docker-shaped flow uses.
37
- - [src/fly.ts](src/fly.ts), the hosted flavor: the same contract emitted as a Fly Machine config (one VM per
38
- sandbox, one volume standing in for the three docker ones, the `SANDBOX_VM` switch, the approved overlay's
39
- hash as `SANDBOX_ENVIRONMENT_HASH` when the image was built from one), the shape of the one other machine a
40
- hosted sandbox runs (`flyBuildMachineConfig`: the builder the platform creates in the sandbox's app to build
41
- that overlay, its recipe delivered as `files`, no volume, no restart), plus the one thing a
42
- docker run never declares: the machine's **front door**, the preview proxy as a Fly service with a health
43
- check under the sandbox's own hostname, because a hosted machine is reached by a replay from the platform's
44
- edge rather than through a tunnel it dials.
45
- - [src/quote.ts](src/quote.ts): shell quoting, which is the part that is easy to get subtly wrong.
46
- - [src/quote-contract.integration.test.ts](src/quote-contract.integration.test.ts): the emitted command run for
47
- real, because a quoting bug is invisible to a unit test that only compares strings.
48
-
49
- ## How it fits
50
-
51
- Consumed by every creation path. It depends on nothing that would stop a browser importing it, which is
52
- deliberate: the UI that offers to create a sandbox and the daemon that creates one describe it identically.
53
-
54
- ## Conventions & gotchas
55
-
56
- - The allowlist is a floor, not a suggestion. Anything not named does not cross into the container, and widening
57
- it is a security decision rather than a convenience one.
58
- - A container name is written and read in one place: `sandboxNames(slug).container` composes it,
59
- `sandboxSlugOf(container)` takes the slug back out, and it answers `undefined` for a name that is not one
60
- rather than handing back a plausible slug. Three callers had their own regex for that before, and a caller with
61
- no slug must be told so, not aimed at whichever sandbox the string resembled.
29
+ - [src/index.ts](src/index.ts) — names, capabilities, caps, directives, replay env and `sandboxRunArgv`.
30
+ - [src/fly.ts](src/fly.ts) — the hosted flavour: `flyMachineConfig` and the single-volume layout.
31
+ - [src/quote.ts](src/quote.ts) — quoters to compose outward, one per parser a value crosses.
32
+ - [src/index.test.ts](src/index.test.ts) — the emitted argv and directive handling, by example.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentic/sandbox-run",
3
- "version": "1.309.0",
3
+ "version": "1.311.0",
4
4
  "description": "The sandbox container's run contract, names, capability posture, env allowlist, runtime directives, and the docker-run emitter every creation path composes from",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -52,7 +52,7 @@
52
52
  }
53
53
  },
54
54
  "dependencies": {
55
- "@intentic/constants": "1.309.0",
55
+ "@intentic/constants": "1.311.0",
56
56
  "tslib": "2.8.1"
57
57
  },
58
58
  "devDependencies": {