feat(review): upload visual-capture screenshots to a public R2 bucket - #4209
feat(review): upload visual-capture screenshots to a public R2 bucket#4209JSONbored wants to merge 1 commit into
Conversation
…#4184) For a self-host instance that stays deliberately private (Tailscale-only, no public HTTP surface), PUBLIC_API_ORIGIN can never be fetched by GitHub, so every visual-capture screenshot embedded in a PR comment renders as a broken image. Adds an optional, config-driven upload path: when R2_PUBLIC_ACCOUNT_ID/BUCKET/ACCESS_KEY_ID/SECRET_ACCESS_KEY/BASE_URL are all set, every captured PNG/GIF (before/after shots, diff overlays, scroll GIFs, and the actions-fallback workflow's own captures) is also uploaded to a dedicated public R2 bucket via a hand-rolled SigV4 signer (no new dependency), and its direct URL used instead of the private origin's. Absent config is byte-identical to today.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
gittensory-ui | dddff88 | Commit Preview URL Branch Preview URL |
Jul 08 2026, 12:12 PM |
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4209 +/- ##
==========================================
+ Coverage 93.75% 93.77% +0.01%
==========================================
Files 389 390 +1
Lines 36495 36549 +54
Branches 13373 13384 +11
==========================================
+ Hits 34217 34273 +56
+ Misses 1621 1620 -1
+ Partials 657 656 -1
🚀 New features to boost your workflow:
|
|
Caution 🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥 🛑 Gittensory review result - fixes requiredReview updated: 2026-07-08 19:54:47 UTC
🛑 Suggested Action - Manual Review
Review summary Blockers
Nits — 5 non-blocking
Why this is blocked
CI checks failing
Review context
Contributor next steps
Signal definitions
Visual preview
Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy. 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
|
Closing as superseded by #4203, which landed a more complete version of this same idea (advances #4184) — a generic S3-compatible backend ( The bucket + credentials created for this PR ( |


Summary
PUBLIC_API_ORIGINthat looks private, but for an instance that's deliberately, permanently private (e.g. Tailscale-only, no public HTTP surface by design), no value ofPUBLIC_API_ORIGINcan ever fix the broken-screenshot symptom — the whole approach of linking through this instance's own origin is the wrong shape for that deployment.R2_PUBLIC_ACCOUNT_ID/R2_PUBLIC_BUCKET/R2_PUBLIC_ACCESS_KEY_ID/R2_PUBLIC_SECRET_ACCESS_KEY/R2_PUBLIC_BASE_URL(all five required together, otherwise not configured — byte-identical to today). When set, every captured screenshot (before/after PNGs, pixel-diff overlays, scroll-through GIFs, and the actions-fallback workflow's own captures) is uploaded a second time to a dedicated, deliberately public Cloudflare R2 bucket, and its direct URL used in the PR comment instead of the private instance's own origin — so the private instance itself never has to answer a single public request.src/selfhost/r2-public-upload.ts: a minimal, self-host-only (Nodenode:crypto) AWS SigV4 request signer for R2's S3-compatible API. No new dependency — hand-rolled rather than pulling in@aws-sdk/client-s3for the one operation this needs (a single-object PUT).Scope
CONTRIBUTING.md.Validation
git diff --checknpm run typechecknpm run docs:drift-checknpm run selfhost:env-reference— regenerated, 5 new vars appear.npm run db:migrations:check,npm run cf-typegen:check— clean (no schema/binding changes; these are plain self-host runtime env vars).npm audit --audit-level=moderate— 0 vulnerabilities.hmac/hashlib) reference implementation for a fixed test vector — exact match — before trusting it in any test.npx vitest run test/unit/r2-public-upload.test.ts test/unit/visual-capture.test.ts test/unit/queue.test.ts— all green; 100% line/branch/function coverage onsrc/selfhost/r2-public-upload.ts; every changed line/branch insrc/review/visual/capture.tsandsrc/queue/processors.tscovered (confirmed viagit diffcross-referenced against the coverage report — pre-existing gaps in code this PR doesn't touch were left alone).npm run test:changed(againstorigin/main) — 2181/2181 passing.npm run test:workers,build:mcp,test:mcp-pack,ui:openapi:check,ui:lint,ui:typecheck,ui:build— not re-run locally (no worker-entry/MCP/OpenAPI/UI-component code touched); CI runs them authoritatively.Safety
Notes
Remaining before this actually fixes the live instance: cut a new self-host release image including this code, deploy it, then set the five
R2_PUBLIC_*values in the live.env— none of that is part of this PR.