ReviewOS

pantry-pm/pantry

security(registry): gate every package publish surface on malware verdicts

#223
Closed chris opened this 2 months ago ·
2 months ago

Goal

Run malware scanning before persistence on every Pantry package publication surface, and expose safe scan metadata in API/package records.

Publish surfaces

  • POST /publish (multipart and JSON/base64)
  • POST /publish/commit (multipart and JSON/base64, every package in a batch)
  • POST /zig/publish
  • POST /php/publish

Direct object-storage/builder uploads must either move behind the API gate or document an equivalent trusted scanning gate; no public/installable artifact path may bypass scanning.

Required behavior

  • Validate cheap request constraints and duplicates first, then buffer/decode once, scan, and only then persist.
  • clean: publish normally and return scan metadata.
  • blocked: reject with a stable 422 response and never write tarball/version metadata.
  • review: hold outside public/installable namespaces until an explicit operator decision exists.
  • error: return 503 with retry guidance and never publish.
  • Batch/commit publication is atomic with respect to scanning: scan all members before writing any member.
  • Persist sanitized scan status, engine, signature/database version, timestamp, duration, and artifact SHA-256 with version metadata.
  • Never expose internal scanner errors or sensitive archive contents.

Acceptance criteria

  • Integration tests prove blocked/error artifacts are absent from metadata and tarball storage.
  • Integration tests cover all four routes and both core encodings.
  • A multi-package commit batch with one blocked member writes zero members.
  • Existing duplicate, ownership, plan-size, checksum, and auth semantics remain intact.
  • API documentation specifies status codes and retry behavior.
8 days ago

Implementation status (2026-07-28): all registry API publication surfaces are gated in the current worktree, pending review/merge.

Covered:

  • Core multipart and JSON publish routes.
  • Commit multipart and JSON routes, with the entire batch scanned before the first write for atomic failure.
  • Zig and PHP publish routes.
  • The legacy registry app publisher now calls the authenticated HTTP publish API instead of writing S3/DynamoDB directly.
  • Scan provenance is persisted with version/commit metadata and returned in publish responses.
  • Integration tests prove clean publication, blocked/error no-write behavior, commit-batch atomicity, and Zig/PHP rejection.

Remaining and intentionally still tracked here:

  • Native-binary build publishers (for example publish:binary and ts-pantry build/upload scripts) are a separate trusted artifact pipeline and still write object storage directly. They must be migrated to a scanned staging/promote flow, or the bucket must enforce that only a scanner-owned principal can write installable keys. Until then this issue should stay open and the claim is limited to registry API package publication.
8 days ago

Follow-up: the previously noted native direct-object publication gap is now logically complete in the local worktree. A reusable two-phase publisher creates HMAC-bound, short-lived uploads under an untrusted staging prefix; completion seals the object, streams it through malware scanning while rechecking size/SHA-256, and only then promotes tarball/checksum/scan attestation, writing metadata last. All first-party publishers now use the Registry API: central TypeScript upload workflows, Zig publish:binary, PHP bundling, fonts, bulk/sync flows, and pkgx fallback. Production reads hide unattested metadata and reject tarball/checksum delivery without a clean scan record. A source-boundary regression test asserts no first-party installable publisher writes directly to object storage. CloudFormation denies non-Registry-role writes to installable/sealed prefixes and expires abandoned staging objects. A controlled legacy backfill tool is included. Keep open until merge/deploy/backfill confirms the boundary in production.

8 days ago

Implemented on main in 673517231, 02b16e2ff, and 70f7a50bf. Every first-party installable package publisher now goes through Registry-controlled stage, scan, attest, and promote behavior; direct-writer regression coverage is landed.

Sign in to comment on this issue.