fix(store): scan .zip bundles, and let owners re-scan - #44
Merged
Conversation
Every listing on the store reads "unscanned", including the only one live. Two causes, both in the publish path: 1. The gating scanner only ran when a publisher supplied a .crx. A .crx is just a signed header wrapped around a ZIP, and most publishers upload the bare .zip — those skipped the gate entirely and fell through to the async vu1nz path. 2. That async path records 'skipped' when VU1NZ_API_URL is unset, which it is in production (no vu1nz scan API is deployed — vu1nz.com/scan/* 404s). So the fallback could never produce a verdict either. Net effect: the store advertises "every listing carries a vu1nz.com scan" while nothing had ever been scanned. - artifactToZip() accepts a .crx or a bare .zip, so scanArtifact() works on whatever was actually published. scanCrx/fetchCrx stay as aliases. - The publish gate now scans crx || bundle. Verified against the live coinpay-wallet bundle: clean, 0 findings at every severity, so this tightens the gate without blocking a real publisher. - POST /extensions/:id/rescan re-runs the scan against the artifact already on file, so listings published before this can earn a badge without a re-upload or version bump — and a "🛡 Re-scan" button next to Edit listing, since owners shouldn't need curl for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
vu1nz Security Review0 finding(s) in PR #? No security issues found. |
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.
Every listing on the store shows "unscanned" — including the only one live. The footer meanwhile promises "every listing carries a vu1nz.com scan."
Two causes, both in the publish path
.crx. A.crxis a signed header wrapped around a ZIP, and most publishers upload the bare.zip. Those skipped the gate entirely and fell through to the async vu1nz path.enqueueScanrecordsskippedwhenVU1NZ_API_URLis unset — and it is unset in production (68 vars on the service, neitherVU1NZ_*present). No vu1nz scan API is deployed either:vu1nz.com/scan/extensionand/api/scan/extensionboth 404.So the fallback for the unscannable case was itself unscannable.
Changes
artifactToZip()accepts a.crxor a bare.zip, soscanArtifact()runs on whatever was actually published.scanCrx/fetchCrxremain as aliases.crx || bundle. This tightens the gate, so I verified it against the real live bundle first —coinpay-wallet.zipscans clean, 0 findings at every severity, so no existing publisher is blocked.POST /extensions/:id/rescan(owner) re-runs the scan against the artifact already on file, so listings published before this can earn a badge with no re-upload and no version bump.Note on
VU1NZ_API_URLLeft unset deliberately: the in-process scanner needs no external service, and there is nothing deployed to point it at. Wiring vu1nz later is now enrichment rather than the only path to a badge.
Verification
tsc --noEmitclean;vitest run src/store→ 37/37 (4 new covering bare-zip scanning, crx/zip verdict parity, a critical finding inside a plain zip, and rejection of non-archive bytes);node --checkon the frontend.🤖 Generated with Claude Code