feat(registry): render each published version's documentation with torb doc --no-run #237
Loading…
Reference in a new issue
No description provided.
Delete branch "loop/17-registry-doc-worker"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #17
Task
#17: the registry's documentation worker. It runs
torb docfor every published version (owner's option A: the work lives intools/registryand renders with the registry's own toolchain).What and why
documentationtable in the registry's SQLite. A publish queues its version in the same batch that records the release. At start, releases that have no row yet are back-filled.tools/registry/src/documentation.trb). It opens its own storage and database, becausespawncopies what it captures and refuses shared objects. For each version it:path:dependencies, and aproject.trbthat names another package, declares a workspace, or carries a nested name that is notowner/name;torb doc --check --no-run, thentorb doc --output.--no-runtype checks examples and builds none, andproject.trbis only read statically. Each run usestimeout+prlimit(120 s, 1 GiB data, 50 MiB file size) and an empty environment. These defaults can be changed withREGISTRY_DOC_*.docs/<owner>/<name>/<version>/and served by nginx at/docs/...with a strict Content-Security-Policy andnosniff. Pages that hold anything but files, have non-plain path segments, or exceed the output limit are refused.failedat once, with whattorb checksays.failed. Attempts are counted before the run, so a crash loop is bounded too.pendingand is re-checked daily and at start.GET /api/1/packages/<owner>/<name>/<version>/docsreturns the state, attempts, toolchain, problem and the pages URL.POSTon the same path re-queues the version; only the operator may do that.writeSiterefuses a page path that climbs out of--output. This is defence in depth: the package name comes fromproject.trb.Dockerfile.registryships the release's toolchain in/opt/torbbut the worker is off in the image (REGISTRY_DOC_TORBempty); the operator opts in viaREGISTRY_DOC_TORB=/opt/torb/bin/torbin compose. README and RELEASE.md 7.7/7.11 are updated as built.The diff was reviewed by an architect agent because the worker handles foreign input. Its two blocking findings are fixed in this PR with tests:
project.trbname such as../xlettorb docwrite outside the site.%2e%2eor#.The deferred findings are follow-ups:
Test
tools/registry/tests/documentation.test.trb(13 tests), run against a realtorb. It covers:torb check's output);path:pin refused;languagedeferred;../project name, a nestedproject.trband a#module name, all refused;failed).writeSiterefuses a page path that climbs out of the directory (absolute and.), and writes nothing; verified to fail with the guard removed.torb checkis clean for tools/registry and compiler.After merge
torb docfor every version #17Review of head
fc34b90. CI is green for this head, the scope matches #17, the docs (README, RELEASE.md 7.7/7.11, compose, pdisc sidecar/INDEX) are updated, and no secrets or new workflow files are in the diff. The worker itself is careful: the archive and every dependency are unpacked against their pinned hash,path:locks and foreign or nested names are refused, and plain-segment page paths are enforced before storing. Attempts are counted before the run, so retries stay bounded. One blocker remains.Checklist
language, re-queue authorisation traced through the code and the 13 tests)CREATE TABLE IF NOT EXISTS, back-fill of existing releases at start)Blocker
[blocker]The new guard inwriteSite(compiler/src/reference/site.trb) has no test. The PR body lists the../xproject name as a blocking finding "fixed with tests", but intools/registry/tests/documentation.test.trbthat case (escape) is refused earlier bymanifestProblem, sotorbnever runs and the guard is never reached. Nothing incompiler/testscovers it either (the existingwriteSiteuse there is the positive path only). Add a compiler test thatwriteSiterefuses a site whose page path climbs out of the directory (../x, and a relative directory such as.) with anIoError, and writes no file before refusing. The guard is also the only protection ifmanifestProblemis ever bypassed, which is the reason it exists.Non-blocking
[suggestion]Dockerfile.registrysetsREGISTRY_DOC_TORB=/opt/torb/bin/torb, so the next registry image runs the worker on strangers' packages by default. The PR body says #233 (isolation) and #234 should be done before that. Consider shipping the default off (empty) in the image and letting the operator opt in incompose.yml, so that an image pull alone cannot start the worker before those are done.[suggestion]prlimitbounds data and file size but not process count or network;--nprocwould be a cheap addition until #233 lands.Addressed in
3153c3dc(review 114):compiler/tests/reference.test.trb: two new tests forwriteSite: a package page that climbs out (../x) into a temp directory is refused with anIoErrornaming the page and nothing is created; in the working directory (.)../x,a/../../xand..are refused. Verified they fail with the guard removed.REGISTRY_DOC_TORBempty);compose.example.ymlpassesREGISTRY_DOC_TORBthrough, so the operator opts in with/opt/torb/bin/torb. README, RELEASE.md 7.7 and the Dockerfile header updated.prlimit --nprocadded (REGISTRY_DOC_PROCESSES, default 512; it limits the user, so the service counts in).Gates:
torb format --checkandtorb check tools/registryclean, pdisc stamp/index/check ok, reference.test.trb 23/23.tools/registry/tests/documentation.test.trbneedssqlite3, which is not on my host, so CI runs it.3153c3dc5841274821fatorb docfor every version #17Re-review of head
4127482(earlier review 114 onfc34b90). CI is green for this head (combined status success), and the PR is mergeable.Earlier findings
compiler/tests/reference.test.trbnow has two tests:../xinto a temp directory is refused with anIoErrornaming the page and nothing is created;../x,a/../../xand..are refused in the working directory. The guard insite.trbchecks every path before the first write.Dockerfile.registrysetsREGISTRY_DOC_TORB=(empty = off),compose.example.ymlpasses it through, and the empty compose defaults fall back to the built-in limits (integerOfreturnsNonefor an empty value). The docs are updated.prlimit --nproc): done, withREGISTRY_DOC_PROCESSES(default 512). The README says it is a limit of the user, the service included.Checklist
tools/release-sync and tools/registryandtier A/Bgreen)No blockers. Merging by rebase.