feat(demo): opt-in public sandbox scans + BomLens SBOM upload (CAX11-friendly) - #519
Merged
Conversation
…friendly)
Lets a read-only public demo offer a bounded live scan / SBOM ingest
without surrendering the read-only safety boundary, cheaply enough to run
on a ~4 GB box (Hetzner CAX11, ~$4/mo).
Carve-out (off by default; both flags required):
- DEMO_ALLOW_SANDBOX_SCANS gates a middleware allow-list extension that
opens exactly POST /v1/projects/{id}/scans and .../sbom-ingest, matched
on the normalized path (traversal-safe). Flag off = 100% locked as before.
- Service-layer guards confine writes to the seeded "Demo Sandbox" project
(403 otherwise) and to kind==source (container/sbom kinds 422 — no
unguarded trivy-image ref pull / SSRF). Order: 404 -> 403 -> 422.
- Boot-time validate_demo_sandbox_limits() fails fast if the carve-out is
on but the safe ceilings aren't applied (source 10 MiB, concurrency 1,
scancode off, SBOM 10 MiB / 3000 components) — so a deploy that forgot
the overlay refuses to start wide-open.
- /health surfaces demo_sandbox_scans (read_only AND allow) for the SPA.
Deployment:
- docker-compose.demo.yml overlay: worker mem_limit 2g + memswap_limit 2g
(+ --concurrency 1), small-box sizing, the demo scan safety rails, no
extra port exposure. Runbook (EN/KO) gains the CAX11 (~$4) path, a demo
scan-mode section, and mandatory demo-reset timer (daily, shared sandbox
is wiped + reseeded).
Frontend:
- SPA re-enables scan + SBOM-upload only on the Demo Sandbox project when
demo_sandbox_scans is true; SbomIngestDialog, a ≤10 MiB / "use BomLens
for larger" notice, and a shared-public-sandbox warning. EN/KO.
Security: Producer-Reviewer, two rounds. Initial review found container-scan
SSRF, non-sandbox write reach, and unbound limits; all fixed and confirmed
closed in the re-review, no regressions.
Backend 4155 unit green, mypy 549, ruff; FE typecheck + 1470 unit green;
compose overlay merge-validated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lets a read-only public demo offer a bounded live scan / SBOM ingest without surrendering the read-only safety boundary — cheaply enough to run on a ~4 GB box (Hetzner CAX11, ~$4/mo), so the demo doesn't need the $18/mo CAX31 the runbook originally assumed.
The architecture
Heavy scanning happens on the visitor's own machine (BomLens, local-first); the demo runs only tiny scans + cheap SBOM ingest. Small inputs (≤10 MiB) scan live in the demo; larger projects are scanned in BomLens and the resulting CycloneDX SBOM is uploaded — ingest is light (
trivy sbom+ conformance), so even large projects cost the demo box almost nothing. This mirrors the real product story (BomLens scans, TRUSCA governs).Carve-out (off by default — both flags required)
DEMO_ALLOW_SANDBOX_SCANSgates a middleware allow-list extension opening exactlyPOST /v1/projects/{id}/scansand.../sbom-ingest, matched on the normalized path (traversal-safe). Flag off ⇒ demo is 100% locked as before.kind==source(container / sbom kinds → 422, so no unguardedtrivy image <ref>pull / SSRF). Ordering: 404 → 403 → 422.validate_demo_sandbox_limits()fails fast if the carve-out is on but safe ceilings aren't applied — a deploy that forgot the overlay refuses to start wide-open./healthsurfacesdemo_sandbox_scans(= read_only AND allow) for the SPA.Deployment
docker-compose.demo.yml: workermem_limit 2g+memswap_limit 2g+--concurrency 1(a runaway scan is OOM-killed inside its container, not the host), small-box sizing, the demo scan safety rails (10 MiB source, 10 MiB / 3000-component SBOM, scancode off, 5/min), no extra port exposure.Frontend
demo_sandbox_scansis true; ingest dialog, a ≤10 MiB / "use BomLens for larger" notice, and a shared-public-sandbox warning. EN/KO.Security (Producer-Reviewer, two rounds)
First review found container-scan SSRF (H), non-sandbox write reach (H), and limits decoupled from the flag (M). All fixed; the closing review confirms 6/6 findings closed, no regressions, carve-out safe to enable (bypass paths — webhooks, rematch — verified blocked). Remaining items are Info-level.
Testing
docker-compose -f docker-compose.yml -f docker-compose.demo.yml configmerge-validated.Ships disabled — enabling requires the demo overlay + both flags + reset timer (the boot check enforces the bounds).