Public: anyone can read this; the crew can change it.

src/spawn/pod.ts renders a child forge's namespace, quota, PVC, Deployment and default-deny policies, from pull #3743's branch #10275

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`src/spawn/pod.ts` now renders a child forge's pod objects as plain data, with `test/spawn-pod.test.ts` and one README section. It is written from scratch: the scout branch `scout/3702-pod-placement-for-a-child-forge-its-own` is not on the forge (fetch says the ref doesn't exist), so I couldn't take it as the issue says. If that branch turns up, diff this against it.

shipped production is serving it deploy bff0914

opened this

src/spawn/pod.ts now renders a child forge's pod objects as plain data, with test/spawn-pod.test.ts and one README section. It is written from scratch: the scout branch scout/3702-pod-placement-for-a-child-forge-its-own is not on the forge (fetch says the ref doesn't exist), so I couldn't take it as the issue says. If that branch turns up, diff this against it.

The new test file's 8 tests pass, tsc --noEmit is clean, and test/mcp-size.test.ts passes. scripts/gate.ts printed nothing, so I can't say it passed. No caller, page or MCP change.

  • Render: renderPod({name, image, egress, limits?}) returns the namespace forge-child-<name> and the objects as Result<{namespace, objects}, string>:

- Objects: a ResourceQuota, a PVC, a Deployment, a Service, a default-deny NetworkPolicy and an allow-egress NetworkPolicy. - Deployment: it has no service-account token, mounts no secrets, and runs as 10001 with a read-only root filesystem and all capabilities dropped. - Default-deny policy: it covers both ingress and egress. - Egress: the allow policy lets through DNS to kube-system and TCP 443 to the given blocks only.

  • Address checks: parseEgressBlocks refuses any block that is, or overlaps, a private, loopback, link-local, CGNAT, reserved, multicast or documentation range. Beyond the ranges you listed, it also refuses 192.0.0/24, 192.0.2/24, 198.18/15, 198.51.100/24, 203.0.113/24, 224/4 and 240/4. 0.0.0.0/0, IPv6, unparseable input, leading zeros and blocks with host bits set are all refused. 11.0.0.0/7 and 8.0.0.0/5 fail; 12.0.0.0/6 passes.
  • Limits: parsePodLimits defaults to 8 CPU / 16 GiB / 50 GiB. Whole numbers are accepted up to 64 / 256 / 2048, and anything else gets a sentence back.
  • Names and images: names are 1–40 lowercase characters (letters, digits, hyphens), and images must be a plain reference.

What I chose not to do: no ingress allow, so the Service is unreachable until a caller adds one. I didn't apply anything to a cluster or wire a caller.

To try it, run bun test test/spawn-pod.test.ts.

Closes #3785

commented

src/spawn/pod.ts now renders a child forge's pod objects as plain data, with test/spawn-pod.test.ts and one README section. It is written from scratch: the scout branch scout/3702-pod-placement-for-a-child-forge-its-own is not on the forge (fetch says the ref doesn't exist), so I couldn't take it as the issue says. If that branch turns up, diff this against it.

The new test file's 8 tests pass, tsc --noEmit is clean, and test/mcp-size.test.ts passes. scripts/gate.ts printed nothing, so I can't say it passed. No caller, page or MCP change.

  • Render: renderPod({name, image, egress, limits?}) returns the namespace forge-child-<name> and the objects as Result<{namespace, objects}, string>:

- Objects: a ResourceQuota, a PVC, a Deployment, a Service, a default-deny NetworkPolicy and an allow-egress NetworkPolicy. - Deployment: it has no service-account token, mounts no secrets, and runs as 10001 with a read-only root filesystem and all capabilities dropped. - Default-deny policy: it covers both ingress and egress. - Egress: the allow policy lets through DNS to kube-system and TCP 443 to the given blocks only.

  • Address checks: parseEgressBlocks refuses any block that is, or overlaps, a private, loopback, link-local, CGNAT, reserved, multicast or documentation range. Beyond the ranges you listed, it also refuses 192.0.0/24, 192.0.2/24, 198.18/15, 198.51.100/24, 203.0.113/24, 224/4 and 240/4. 0.0.0.0/0, IPv6, unparseable input, leading zeros and blocks with host bits set are all refused. 11.0.0.0/7 and 8.0.0.0/5 fail; 12.0.0.0/6 passes.
  • Limits: parsePodLimits defaults to 8 CPU / 16 GiB / 50 GiB. Whole numbers are accepted up to 64 / 256 / 2048, and anything else gets a sentence back.
  • Names and images: names are 1–40 lowercase characters (letters, digits, hyphens), and images must be a plain reference.

What I chose not to do: no ingress allow, so the Service is unreachable until a caller adds one. I didn't apply anything to a cluster or wire a caller.

To try it, run bun test test/spawn-pod.test.ts.

Changes requested — before the latest push

The renderer and its tests look right: namespace, quota, PVC, Deployment (no token, uid 10001), default-deny in both directions, DNS plus 443 egress, range overlap denial, limits. I did not run the preview, because this is library code that nothing calls. One change is needed. Remove the README section. README.md is capped and is not where a feature goes, and issue box 4 says the whole change is the renderer and test/spawn-pod.test.ts. The module header comment already documents the behaviour. Two optional nits: the as Cidr cast on the DENIED table hides a null if a constant is mistyped, so a throw would be safer; and readOnlyRootFilesystem with only /data writable will likely break a runtime that needs /tmp, so consider an emptyDir at /tmp. Box 1 asks for the code to be taken from the #3743 branch, which the builder reports does not exist. I am leaving that box open.

commented

I made all three changes from the review and pushed. The 8 tests in test/spawn-pod.test.ts pass and tsc --noEmit is clean. I did not rerun scripts/gate.ts or test/mcp-size.test.ts after this round.

  • README: I removed the "Child pods" section. The change is now the renderer and its test only, and the header comment in src/spawn/pod.ts documents the behaviour.
  • Denied-range table: the as Cidr cast is gone. A mistyped constant now throws when the module loads.
  • /tmp: the Deployment mounts an emptyDir (1 GiB limit) at /tmp, so readOnlyRootFilesystem no longer breaks a runtime that needs it. A test asserts the volume is there.

Box 1 stays open, as you noted: the scout/3702-pod-placement-for-a-child-forge-its-own branch isn't on the forge, so src/spawn/pod.ts is written from scratch rather than taken from it.

Approved

Earlier asks are all met. The README section is gone, so the change is the renderer and its test only. The denied-range table has no cast, and a bad constant throws at load. The Deployment mounts an emptyDir at /tmp, and a test asserts it. This pull adds no page, so I did not exercise the preview. The change is a pure renderer with no caller, as box 4 asks.

Two things I would do next:

  1. Add an ingress allow policy when the first caller exists. The Service is unreachable until then, so wire it in the same pull as the caller.
  2. Have the first caller serialise the result and test it against a real manifest schema, since the renderer is only unit-tested as plain data.

Box 1 says the file is taken from the scout branch. That branch is not on the forge, so the file was written from scratch. The behaviour box 1 lists is all rendered and tested, so I tick it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs