| 1 | import assert from "node:assert/strict"; |
| 2 | import { readFileSync } from "node:fs"; |
| 3 | import { test } from "node:test"; |
| 4 | |
| 5 | import type { WorkflowDomain } from "@g1t/contracts"; |
| 6 | |
| 7 | import { INSTANCE_TYPES } from "../../../packages/contracts/src/instances.ts"; |
| 8 | |
| 9 | import { SANDBOX_BINDINGS, jobHosts, sandboxNamespace } from "./egress.ts"; |
| 10 | |
| 11 | const domains: WorkflowDomain[] = [ |
| 12 | { domain: "api.cloudflare.com", workflows: ["deploy.yml"], environments: ["production"] }, |
| 13 | { domain: "*.example.com", workflows: [], environments: [] }, |
| 14 | ]; |
| 15 | const policy = { workflowDomains: domains }; |
| 16 | const deploy = { workflow: ".g1t/workflows/deploy.yml", environment: "production", trusted: true }; |
| 17 | |
| 18 | test("a trusted workflow job reaches the workflow-only domains that name it", () => { |
| 19 | assert.deepEqual(jobHosts(policy, "actions", deploy), ["api.cloudflare.com", "*.example.com"]); |
| 20 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, workflow: "DEPLOY.yml", environment: "Production" }), [ |
| 21 | "api.cloudflare.com", |
| 22 | "*.example.com", |
| 23 | ]); |
| 24 | // Another environment, none, or another workflow: only the open entry. |
| 25 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, environment: "staging" }), ["*.example.com"]); |
| 26 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, environment: null }), ["*.example.com"]); |
| 27 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, workflow: ".g1t/workflows/ci.yml" }), ["*.example.com"]); |
| 28 | }); |
| 29 | |
| 30 | test("nothing else ever reaches them: forks, deploy builds, unknown jobs", () => { |
| 31 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, trusted: false }), []); |
| 32 | assert.deepEqual(jobHosts(policy, "deploy", deploy), []); |
| 33 | assert.deepEqual(jobHosts(policy, "actions", null), []); |
| 34 | assert.deepEqual(jobHosts(policy, "actions", { ...deploy, workflow: null }), []); |
| 35 | // Guardrails from before the list existed. |
| 36 | assert.deepEqual(jobHosts({}, "actions", deploy), []); |
| 37 | }); |
| 38 | |
| 39 | test("each sandbox class reports to its own namespace", () => { |
| 40 | const env = { SANDBOX: "standard", SANDBOX_2CORE: "two", SANDBOX_4CORE: "four" } as unknown as object; |
| 41 | assert.equal(sandboxNamespace(env, "AttemptSandbox"), "standard"); |
| 42 | assert.equal(sandboxNamespace(env, "Sandbox4Core"), "four"); |
| 43 | assert.equal(sandboxNamespace(env, "Sandbox2Core"), "two"); |
| 44 | assert.equal(sandboxNamespace(env, undefined), "standard"); |
| 45 | assert.equal(sandboxNamespace({ SANDBOX: "standard" }, "Sandbox4Core"), "standard"); |
| 46 | assert.deepEqual(Object.keys(SANDBOX_BINDINGS), ["AttemptSandbox", "Sandbox2Core", "Sandbox4Core"]); |
| 47 | }); |
| 48 | |
| 49 | test("each sandbox class is the size the contracts give its runs-on label", () => { |
| 50 | type Size = { vcpu: number; memory_mib: number; disk_mb: number }; |
| 51 | // wrangler.jsonc's comments are whole lines. |
| 52 | const text = readFileSync(new URL("../wrangler.jsonc", import.meta.url), "utf8").replace(/^\s*\/\/.*$/gm, ""); |
| 53 | const config = JSON.parse(text) as { containers: { class_name: string; instance_type: string | Size }[] }; |
| 54 | // The named Cloudflare instance types a machine may be. |
| 55 | const named: Record<string, Size> = { "standard-4": { vcpu: 4, memory_mib: 12 * 1024, disk_mb: 20_000 } }; |
| 56 | const classes = Object.keys(SANDBOX_BINDINGS); |
| 57 | assert.equal(INSTANCE_TYPES.length, classes.length); |
| 58 | INSTANCE_TYPES.forEach((instance, i) => { |
| 59 | const type = config.containers.find((c) => c.class_name === classes[i])?.instance_type; |
| 60 | const size = typeof type === "string" ? named[type] : type; |
| 61 | assert.ok(size, `${classes[i]}: ${JSON.stringify(type)}`); |
| 62 | assert.equal(typeof type === "string" ? type : "custom", instance.container, instance.label); |
| 63 | assert.deepEqual( |
| 64 | { vcpu: size.vcpu, memoryGib: size.memory_mib / 1024, diskGb: size.disk_mb / 1000 }, |
| 65 | { vcpu: instance.vcpu, memoryGib: instance.memoryGib, diskGb: instance.diskGb }, |
| 66 | instance.label, |
| 67 | ); |
| 68 | }); |
| 69 | }); |