Skip to content

Scan and sign build zips: vapour scan, vapour verify, signed publish - #19

Merged
madhavkhoslaa merged 1 commit into
mainfrom
feat/zip-verification
Oct 16, 2026
Merged

madhavkhoslaa merged 1 commit into
mainfrom
feat/zip-verification

Conversation

@madhavkhoslaa

Copy link
Copy Markdown
Contributor

Features

  • Local scan before upload. vapour publish scans the zip first. Any error cancels the upload: nothing sent, no version used. No flag to skip it.
    • zip bombs: file count, total and per-file size (server limits: 5,000 files, 1 GiB, 512 MiB), ratio over 200:1, header size lies
    • unsafe paths: .., absolute, drive letters, backslashes, control chars, duplicates, over-long or too deep
    • symlinks, devices, pipes
    • native executables by content (ELF, PE, Mach-O), even renamed; .wasm allowed; native extensions
    • in-browser crypto miners, EICAR test file
    • warnings only: nested archives, double extensions, shebang, obfuscated or insecure scripts
    • never extracts to disk, reads at most 4 MiB per file, bounded decompression
  • Signed attestation. SHA-256 of the exact zip, signed with a local ed25519 key (~/.config/vapour/signing.key, mode 0600, created on first publish). Written to .vapour/build.zip.attestation.json and sent as the attestation part.
  • vapour scan [zip|folder]: scan on its own, --json, exit 1 on errors.
  • vapour verify [zip]: checks signature, key id, hash and size; --remote compares with the server's record and requires verified. Zip optional with --remote.
  • After upload, publish says the server verifies the zip and an admin reviews it, and how to check progress.
  • Experimental chunk publish also scans the folder (no attestation).

Safe to merge

  • Old servers ignore the extra attestation part, so publishing keeps working until the API ships.
  • Risk: a scan false positive blocks publishing locally. Messages name the file and the rule.
  • Merging to main auto-releases a CLI patch to all users (vapour update). Add [minor] to a commit subject if this should be v0.2.
  • Overlaps with CLI: reject an already-published version before uploading anything #18 (duplicate-version pre-check) in cmd/publish.go; needs a rebase on whichever lands second.

Needs (other repos)

  • Backend: async verification, signature check, admin approval (vapour-infra). Contract: docs/zip-verification-api.md.
  • Docs: vapour-dev-docs#17.

Tests

gofmt, go vet, go test ./... -race pass. New: scanner table tests per finding code, bomb and lying-header cases, signing round trip and tamper cases, key file mode, publish with zero HTTP on bad builds, upload carries a verifiable attestation, verify --remote statuses, and a deterministic fixture (internal/zipsign/testdata/) for the Rust backend to verify.
Not tested against a real API (not deployed).

Built with opencode (GLM and GPT 5.3) from written specs, then reviewed. Fixed in review: limits now match the server, no full decompression of already-rejected entries, entry_unreadable finding.

🤖 Generated with Claude Code

publish now scans the zip locally before anything is uploaded (zip
bombs, unsafe paths, symlinks, native executables even when renamed,
in-browser miners, EICAR) and cancels on any error: no upload, no
version used. It then signs the zip's SHA-256 with a local ed25519 key
and sends the attestation with the build. vapour scan runs the scan on
its own; vapour verify checks a zip against its attestation and, with
--remote, against the server's record.

The server contract is in docs/zip-verification-api.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@madhavkhoslaa
madhavkhoslaa merged commit 640afdc into main Oct 16, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant