Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-11 00:29:15 -05:00
Commit graph pkg-proxy/internal/handler/integrity.go
Author SHA1 Message Date
Simon Chrzanowski
bf74d982d7 Verify npm and Composer archives against their SHA-1 shasum
npm versions published before dist.integrity existed carry only a SHA-1
dist.shasum, and Composer metadata lists only a SHA-1 dist.shasum, so
neither could be checked.

- Accept native integrity given as an algorithm-prefixed hex checksum,
  verified with integrity's exact-digest check, so a recorded "sha1-<hex>"
  is also checked on cache hits
- npm: fall back to dist.shasum when dist.integrity is missing or cannot
  be parsed; a usable dist.integrity still takes precedence
- Composer: verify an archive against its dist.shasum, except another
  commit of a branch fetched in place of the listed one, which the listed
  shasum does not describe
- Fetch unverified as before when no shasum is listed, as Packagist does
  for GitHub archives, or it is not a SHA-1 digest
2026-10-14 18:04:31 +02:00
Simon Chrzanowski
2d258ddc4b Verify npm tarballs against dist.integrity
The proxy cached the first tarball upstream sent for a version without
checking it against the packument, so a tampered tarball was served to
every client after it.

- Pass the packument's dist.integrity to the existing integrity checks, so
  a fresh tarball is verified as it is stored or streamed; a mismatch is
  discarded and returns 502, or aborts the streamed response
- Record it with the cached version, so cache hits are verified against it
  through the same check as before
- Verify with integrity.Result.Verify, which accepts any digest of the
  strongest algorithm listed
- Fetch unverified as before when dist.integrity is missing or cannot be
  parsed, or the packument cannot be fetched
2026-10-14 15:40:36 +02:00
PhantomPhoton
f60772d2d8
Support HTTP byte-range requests for local file cached artifact downloads (#404)
* feat(storage): expose efficient seek for local files

Open file-backed artifacts with os.Open so local readers support
efficient seeking. Leave cloud storage readers unchanged.

Keep the legacy sidecar mapping test focused on fileblob's reader:
Blob.Open now reads local files directly and no longer consults the
sidecar. Continue checking sidecar cleanup and post-store reads.

* feat(handler): preserve efficient seek through integrity checks

Keep the cache result's single Reader field and preserve io.Seeker
when the underlying storage reader supports efficient seeking.

Sequential reads continue through whole-object integrity verification.
A successful seek switches subsequent reads to the source for range
responses, where full-object verification is not possible.

Test both modes and verify the source is closed once.

* feat(handler): add request-aware byte range responses

Add a request-aware artifact serving helper for bounded, open-ended,
and suffix byte ranges, including If-Range handling, 206 responses,
and 416 responses for valid unsatisfiable ranges.

Ignore malformed and multi-range requests by serving the full artifact.
Advertise byte-range support only for seekable readers, preserving HEAD,
redirect, and non-seekable behavior. Clarify that net/http recovers
ErrAbortHandler per request and keeps the server running.

* feat(handler): enable byte ranges across artifact downloads

Forward each artifact request to the shared range-aware response helper,
including cached generic release assets and OCI blobs. This lets the
handler honor ranges only when its reader supports efficient seeking,
without changing direct-storage redirect behavior.

Add warm-cache endpoint tests that assert partial response headers and
bytes without an upstream refetch. Document supported range behavior,
unsupported reader fallback, and the integrity limitation of partial reads.
2026-10-04 17:48:41 +01:00
Daniil Skripchenko
b40a50aad8
Add storage.cache_artifacts to serve artifacts without storing them (#387)
* Add storage.passthrough to serve artifacts without storing them

With storage.passthrough enabled the proxy streams every artifact from
upstream to the client and never writes it to storage or the cache
database. Metadata filtering, cooldown and the denylist work as before,
so the proxy can sit behind another cache (e.g. an Artifactory remote)
purely as a policy layer without holding a second copy of every package.

Artifacts whose digest is known up front (OCI, Swift, Helm) are verified
while streaming. Their responses are sent chunked and the connection is
aborted on a mismatch, so a client never receives a tampered artifact as
a complete response.

Passthrough is rejected together with scanning, direct_serve and
mirror_api, and the mirror command refuses to run with it, since all of
them depend on stored artifacts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Address review: abort truncated streams, guard every cache read

- serveArtifact aborts the response on any body read error, and when fewer
  bytes than the declared size were written, not only on a digest mismatch.
  A failed or short upstream body in passthrough mode no longer reaches the
  client as a complete 200.
- Streamed upstream read failures are logged and counted as
  stream_failed upstream errors before the response is aborted.
- checkCache reports a miss when artifact caching is off, so every cache
  read path, including Swift archive HEAD requests, ignores entries stored
  before the mode was enabled. Denylisted versions are still rejected.
- Rename storage.passthrough to storage.cache_artifacts (default true,
  PROXY_STORAGE_CACHE_ARTIFACTS), which names what actually changes.

Tests cover an OCI blob shorter than its Content-Length and an npm tarball
whose chunked response ends without the final chunk, both served through
the HTTP handlers, plus a Swift HEAD request against a cached archive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rename Proxy.Passthrough to StreamArtifacts

Match the storage.cache_artifacts option: the field says what changes
(artifacts are streamed instead of stored) and its zero value keeps the
usual caching behaviour for every Proxy built without the server config,
such as the mirror command and tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:28:20 +01:00
Andrew Nesbitt
1a814c7e1f
Use shared integrity verification (#260)
* Use shared integrity verification

* Finish integrity migration
2026-08-17 09:20:11 +01:00
Andrew Nesbitt
61741123bf
Verify cached artifacts on read (#111)
checkCache opened the storage reader and streamed it to the client
without checking that the bytes still matched what was originally
stored, or what the upstream registry declared. Disk corruption,
accidental overwrites, or local tampering would go unnoticed.

Wrap the storage reader in a verifyingReader that computes SHA256
(against artifact.content_hash) and, when version.integrity holds an
SRI string, the corresponding sha256/384/512 digest as bytes flow
through. At EOF the digests are compared; on mismatch we log at
error level, bump proxy_integrity_failures_total, and clear the
artifact's cache entry so the next request refetches from upstream.

Verification is skipped when the stream was not fully consumed
(client disconnect) to avoid evicting good artifacts on partial
reads. The DirectServe presigned-URL path is unverified since the
proxy never sees those bytes.

Refs #42 (part 1)
2026-05-03 10:36:28 +01:00