Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Hosted deployment: spike: prove the hardened Worker container inside a Sandbox VM

Open
#317 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
12/100
Issue type
Documentation
Clarity
Mostly clear
Activity status
Active
Tech stack
docker, linux, typescript

Research direction

Start by reading the flags in compose.dynamic.yml and the hardening requirements in parent issue #316, then set up the throw-away Vercel project in fra1 and build the golden snapshot. Each probe T01 to T14 is run by hand and its measured result goes into the write-up in docs/spike/ and the ADR in docs/decisions/. Done means every test case in the table has a recorded result and the VM size and container limit recommendation is written down.

Written by the indexing model from the issue text.

Description

area: ops type: security

Part of ##316.

Problem

The hosted deployment runs our hardened Worker container inside a Vercel Sandbox VM that hosts Docker. Nothing about nested Docker, the VM kernel, memory use or startup time is known yet. Vercel's firewall and isolation are not part of our security boundary: our container must carry all hardening, and the Dynamic-Worker must fail closed where it cannot. We need facts before building the Sandbox-Launcher.

Design

Manual, time-boxed (3 days). The result is a write-up in docs/spike/ and an ADR in docs/decisions/, with the measured numbers in the PR. No production code. Use a throw-away Vercel project in region fra1.

  • Build a golden snapshot by hand: Docker installed with the package manager of the default Ubuntu image, the Dynamic image pre-pulled by digest from Vercel Container Registry, dockerd stopped cleanly, snapshot. Then clone it once per probe (persistent:false).
  • Run the real container flags of compose.dynamic.yml (user, caps, no-new-privileges, read-only root, tmpfs, memory, pids) with docker run, and the real code and checks. Vercel's network policy stays at its default; no firewall rule is used or relied on.
  • VM sizes. Per the Vercel Sandbox docs each vCPU includes 2 GB of memory (1 vCPU, or an even number from 2 to 32), so the smallest size is 1 vCPU / 2 GB. T10 confirms this on a real VM. Starting points: Dynamic-Worker VM 1 vCPU / 2 GB with the Worker container limited to about 1.5 GB (--memory 1.5g --memory-swap 1.5g, leaving room for dockerd and the OS); Diff-Worker VM the smallest size, 1 vCPU / 2 GB. The 2g memory cap of the self-hosted Dynamic compose service was only a cap and was never measured; T10 produces the first real peak numbers.
  • VM size and container memory limit are configuration per Worker kind in the later issues, not constants. If Dynamic is killed by the OOM killer at 1.5 GB, the recommendation steps up one size (2 vCPU / 4 GB) and the container limit is raised accordingly.
  • Decision rule: any failure of T03 to T07 keeps opencode off (Diff may still proceed). T01 or T02 failing ends the approach and triggers the documented fallback (boot the Worker image directly as the sandbox image and re-create the compose hardening in its entry point; its cost is a new hardening module and its privileged tests).
  • Do not change the self-hosted compose limits in this issue. Record a recommendation and open a follow-up if the measured numbers justify one.

Scope

The probes below, the write-up, the ADR. Findings that need code become new issues.

Out of scope

Any production code, the golden snapshot pipeline (##330), the Sandbox-Launcher (##329), egress restriction (#82).

Related

#82 (egress gate; T11 only records what the container can reach), #202 (Dynamic engine packaging and release gates).

Test cases

ID kind level case expected
T01 probe manual install Docker in the default image, start dockerd, run docker info in fra1 daemon runs; storage driver, cgroup version, memory controller, seccomp and LSM state recorded
T02 probe manual create a VM from the golden snapshot with persistent:false, start dockerd, run the image images are present after restore; the container starts without a pull
T03 security manual run the container with the exact flags of compose.dynamic.yml; inspect it HostConfig matches; inside: effective and bounding capabilities equal the list, no-new-privileges set, root filesystem read-only, three tmpfs mounts with noexec,nosuid,nodev and their sizes, memory and pids limits visible in the cgroup
T04 security manual container start: install the engine uid's nft rules, drop NET_ADMIN and SETPCAP rules installed in the container's network namespace; a probe as uid 10101 reaches only the two loopback ports; nft fails afterwards for every process
T05 security manual run the Dynamic startup self-check in the container passes with no failing reason
T06 security manual run the repository's privileged test suite and the Dynamic e2e journey inside the container (fakes only) both pass
T07 security manual from root and from uid 10101 inside the container: AF_VSOCK connect to the host and agent, gateway ports, /proc/net/unix, access to the VM's Docker socket the engine uid reaches nothing; anything root reaches is listed; a positive finding creates a follow-up for a seccomp rule
T08 edge manual job isolation: write a marker in job A (container layer, tmpfs, /var/lib/docker), then run job B from a fresh clone of the snapshot marker absent; a scan of the golden snapshot finds no job data and no secret
T09 measure manual timeline: create-from-snapshot, dockerd ready, container ready, self-check done, first heartbeat; cold and warm snapshot numbers recorded per segment and compared with the target of 45 s from claim to first Worker heartbeat
T10 measure manual worst-case Dynamic job and worst-case Diff job in the container with a 1.5 GB limit on a 1 vCPU / 2 GB VM; confirm the VM's memory (free) and that no smaller size exists peak memory per kind (container cgroup and VM), OOM behavior (container killed, VM alive), recommended VM size and container limit per kind; if Dynamic is OOM-killed, the same run on 2 vCPU / 4 GB with a recommended larger limit
T11 probe manual egress from the container (bridge NAT) to the App, the Git host and the model host; DNS; IPv6; MTU works; failures listed
T12 probe manual snapshot lifecycle and registry: expiry setting, restore in the same region, behavior of an uncached snapshot; push the Worker image to Vercel Container Registry and pull it by digest in the builder VM with the project's OIDC login documented limits and durations; the pull works without a long-lived secret
T13 probe manual teardown: docker run ...; poweroff, stop(), and a lost SDK call with only the VM timeout which option ends the VM; worst-case idle time
T14 probe manual a Hono default export deployed as Functions with a cron route and waitUntil use works, or the exact workaround
Dominant language
TypeScript
Stars
0
Forks
1
Avg merge
1h 15m
Merged PRs (30d)
217

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ExpidetGames/code-reviewer

All issues in ExpidetGames/code-reviewer

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.