feat(box): restrict box creation to the supported pinned images#758
Conversation
main already accepts a free-form image string (#755). This adds the curated allowlist on top: box creation validates the image against the deployment's supported, sha256-pinned ghcr refs (base/python/node) and rejects anything else with a 400 listing the supported set. Undefined defaults to the base image. This is the pre-launch security gate — without it a request could make the runner pull an arbitrary image with its private-registry token. - add curated-images.constant.ts (supportedImages / assertSupportedImage, env-overridable, pinned fallbacks) + spec - box.service create: validate createBoxDto.image at the request boundary Scope: server-side allowlist only. No client regen (image field shape is unchanged), no SDK/dashboard/identity changes. API jest 106/106 (curated spec 5/5).
📝 WalkthroughWalkthroughA new image allowlist module restricts Box creation to three pinned OCI refs with environment variable overrides. The BoxService now validates and normalizes the requested image via ChangesImage Allowlist Validation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/api/src/box/constants/curated-images.constant.ts`:
- Around line 39-41: supportedImages currently trusts raw env overrides from
SUPPORTED_IMAGE_SOURCES and can accept unpinned or non-GHCR refs; change
supportedImages() so that for each entry (from SUPPORTED_IMAGE_SOURCES.map(({
envVar, fallbackRef })) you read process.env[envVar] but only accept it if it
matches a pinned GHCR digest pattern (e.g.
/^ghcr\.io\/[^\s@]+@sha256:[a-f0-9]{64}$/i); if the env value fails validation,
fall back to fallbackRef instead (no throw), and return the array of validated
refs. Use the function name supportedImages and the SUPPORTED_IMAGE_SOURCES
entries to locate and implement this validation logic.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 2c2b4acb-f945-4e61-aad6-ce24865dfde1
📒 Files selected for processing (3)
apps/api/src/box/constants/curated-images.constant.spec.tsapps/api/src/box/constants/curated-images.constant.tsapps/api/src/box/services/box.service.ts
#758 dropped the docker.io/library/alpine entry from supportedImages, so the chore-conftest's bare 'alpine:3.23' default now gets 400 'Unsupported image' on Tokyo Api. Send the curated-images constant's default ghcr ref (which the 20260605-p0-r3 tag also points at), so the test exercises the runner toolbox fix end-to-end. Tokyo runner has GHCR_USERNAME/GHCR_TOKEN injected via systemd drop-in for the pull. Local-verified: yaml parses, conftest reads the env into DEFAULT_IMAGE, ghcr token exchange + manifest fetch returns 200.
Summary
main already accepts a free-form
imagestring on box creation (landed in #755). This PR adds only the curated allowlist on top — the pre-launch security gate.Without this gate, a request can make the runner pull an arbitrary image using its private-registry token — so the allowlist is required before launch.
Changes (server-side only)
apps/api/src/box/constants/curated-images.constant.ts—supportedImages()/assertSupportedImage(); env-overridable (BOXLITE_SYSTEM_{BASE,PYTHON,NODE}_IMAGE) with sha256-pinned fallbacks. + spec.box.servicecreate: validatecreateBoxDto.imageat the request boundary.Scope boundary (what this PR is NOT)
imagefield shape is unchanged (still a string), only its accepted values are restricted server-side.Verification
API jest 106/106 (curated allowlist spec 5/5).
Summary by CodeRabbit
Tests
New Features