Skip to content

Commit cb02ca2

Browse files
committed
feat: let agents ask for software, which their pod keeps for its sandbox
request_software asks for a package from nixpkgs, stable or unstable, and the turn waits for whoever manages the pod's sandbox to allow it. Allowed, it is installed into the pod's shared Nix profile, on every command's PATH, and recorded at the nixpkgs commit it came from; each turn's first use of the sandbox gives it exactly the pod's recorded packages, so a new or upgraded sandbox gets them back. The pod's settings list its software, which its admins can remove.
1 parent 1ba02c4 commit cb02ca2

29 files changed

Lines changed: 10066 additions & 24 deletions

‎docker/sandbox/Dockerfile‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ COPY nix/nix.conf nix/registry.json /etc/nix/
8282
# Nix looks for its state here, and without it falls back to a store in the
8383
# user's home that needs namespaces the agents' user can't make.
8484
RUN mkdir -p /nix/store /nix/var/nix && chown -R 1000:1000 /nix
85+
# The pod's software, on the PATH of login shells, as agents' commands run,
86+
# and of interactive ones, as in the dock's terminal.
87+
COPY nix/software-path.sh /etc/profile.d/sugabots-software.sh
88+
RUN echo '. /etc/profile.d/sugabots-software.sh' >> /etc/bash.bashrc
8589

8690
COPY sugabots-desktop /usr/local/bin/sugabots-desktop
8791

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The pod's software, which Sugabots installs into this Nix profile and keeps
2+
# on every sandbox the pod has, ahead of the image's own.
3+
case ":$PATH:" in
4+
*:/nix/var/nix/profiles/sugabots/bin:*) ;;
5+
*) PATH="/nix/var/nix/profiles/sugabots/bin:$PATH" ;;
6+
esac

‎packages/contracts/src/http/groups/pod-sandbox.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ import {
33
newSandboxHostSchema,
44
podSandboxNetworkSchema,
55
podSandboxSchema,
6+
podSandboxSoftwareSchema,
67
sandboxHostSchema,
8+
sandboxPackageNameSchema,
9+
sandboxSoftwareChannelSchema,
710
} from "../../sandbox-providers.ts";
811
import { uuidSchema } from "../../uuid.ts";
912
import { BadRequest, Conflict, refused } from "../errors.ts";
@@ -14,7 +17,8 @@ const params = { podId: uuidSchema };
1417

1518
/**
1619
* A pod's sandbox: how it stands, starting it afresh or moving its work to the
17-
* current image, and the hosts it may reach beyond what the workspace allows.
20+
* current image, the hosts it may reach beyond what the workspace allows, and
21+
* the software it has beyond its image.
1822
*/
1923
export class PodSandboxApi extends HttpApiGroup.make("podSandbox")
2024
.add(
@@ -45,5 +49,15 @@ export class PodSandboxApi extends HttpApiGroup.make("podSandbox")
4549
success: podSandboxNetworkSchema,
4650
error: refused,
4751
}),
52+
HttpApiEndpoint.get("software", `${root}/software`, {
53+
params,
54+
success: podSandboxSoftwareSchema,
55+
error: refused,
56+
}),
57+
HttpApiEndpoint.delete("removePackage", `${root}/software/:channel/:name`, {
58+
params: { ...params, channel: sandboxSoftwareChannelSchema, name: sandboxPackageNameSchema },
59+
success: podSandboxSoftwareSchema,
60+
error: refused,
61+
}),
4862
)
4963
.middleware(Session) {}

‎packages/contracts/src/sandbox-providers.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,36 @@ export const podSandboxNetworkSchema = Schema.Struct({
244244
export type PodSandboxNetwork = typeof podSandboxNetworkSchema.Type;
245245

246246
export const newSandboxHostSchema = Schema.Struct({ host: sandboxHostSchema });
247+
248+
/** Which nixpkgs a package comes from: a NixOS release, or unstable for newer versions. */
249+
export const sandboxSoftwareChannelSchema = Schema.Literals(["stable", "unstable"]);
250+
251+
export type SandboxSoftwareChannel = typeof sandboxSoftwareChannelSchema.Type;
252+
253+
/**
254+
* A package's attribute in nixpkgs, such as `ffmpeg` or
255+
* `python3Packages.pandas`: names joined by dots, of letters, digits, `_`,
256+
* `-` and `+`.
257+
*/
258+
export const sandboxPackageNameSchema = Schema.String.check(
259+
Schema.isMaxLength(200),
260+
Schema.isPattern(/^[A-Za-z_][A-Za-z0-9_+-]*(?:\.[A-Za-z_][A-Za-z0-9_+-]*)*$/, {
261+
message: "Enter a nixpkgs package name, such as ffmpeg or python3Packages.pandas",
262+
}),
263+
);
264+
265+
/** Software a pod's sandbox has, each package at the nixpkgs commit it was installed from. */
266+
export const podSandboxSoftwareSchema = Schema.Struct({
267+
packages: Schema.Array(
268+
Schema.Struct({
269+
name: sandboxPackageNameSchema,
270+
channel: sandboxSoftwareChannelSchema,
271+
nixpkgsRev: Schema.String,
272+
/** Who allowed the agent's request for it; null once they've left. */
273+
addedByName: Schema.NullOr(Schema.String),
274+
addedAt: isoTimestampSchema,
275+
}),
276+
),
277+
});
278+
279+
export type PodSandboxSoftware = typeof podSandboxSoftwareSchema.Type;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CREATE TABLE "sandbox_pod_package" (
2+
"workspace_id" uuid NOT NULL,
3+
"pod_id" uuid,
4+
"name" text,
5+
"channel" text,
6+
"nixpkgs_rev" text NOT NULL,
7+
"added_by_id" uuid,
8+
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
9+
CONSTRAINT "sandbox_pod_package_pkey" PRIMARY KEY("pod_id","channel","name"),
10+
CONSTRAINT "sandbox_pod_package_channel_check" CHECK ("channel" in ('stable', 'unstable'))
11+
);
12+
--> statement-breakpoint
13+
ALTER TABLE "sandbox_pod_package" ADD CONSTRAINT "sandbox_pod_package_added_by_id_user_id_fkey" FOREIGN KEY ("added_by_id") REFERENCES "user"("id") ON DELETE SET NULL;--> statement-breakpoint
14+
ALTER TABLE "sandbox_pod_package" ADD CONSTRAINT "sandbox_pod_package_pod_workspace_fkey" FOREIGN KEY ("pod_id","workspace_id") REFERENCES "pod"("id","workspace_id") ON DELETE CASCADE;

0 commit comments

Comments
 (0)