Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-09-16 07:42:05 -04:00
Commit graph pkg-proxy/internal/storage
Author SHA1 Message Date
montehurd
0089917485
Stop writing fileblob's .attrs sidecar (#328)
* Stop writing fileblob's .attrs sidecar

fileblob stores blob metadata in an ".attrs" file per object and rewrites
it with os.Create, truncating in place outside the atomic rename that
protects the blob. A read overlapping a write decodes a partial file and
fails with "opening reader: EOF", served as a 502. One writer against
four readers on a single key failed 408 of 2000 reads. cacheMetadataBlob
is most exposed to it, rewriting a key on every refresh while readers
are served from it.

Nothing in the proxy reads what the sidecar holds. gocloud.dev/blob is
imported only by internal/storage, Store sets no ContentType, and
Attributes is used only for Size, which comes from os.Stat. A missing
sidecar already defaults cleanly, so "metadata=skip" removes the hazard
rather than locking around it, and saves a write per store.

* Clear .attrs sidecars left by earlier versions

metadata=skip stops fileblob rewriting sidecars but does not delete ones
already on disk, so a sidecar left partial by an interrupted write now
fails every read of its key for good. Before, a later store repaired it
by rewriting.

Store therefore removes the sidecar for the key it writes. Removal is
atomic where the rewrite was not, so a concurrent reader gets the whole
old file or nothing. Delete already removes sidecars, so the two paths
drain a cache between them.

Deriving that path is necessary because fileblob's key escaping is
unexported. It is the identity for a plain key and parts from one only
for keys that are not valid local paths, which is what filepath.Localize
rejects. That also keeps the removal inside the cache directory: without
it a key holding ".." resolves outside.

The clearing test runs one key per storage path the proxy builds, seeded
through a bucket that still writes sidecars so the path under test is
fileblob's own.

* Explain why failed sidecar cleanup does not fail the store

Move the removal into clearLegacySidecar and say why its error is
dropped rather than returned. A failed removal leaves exactly the state
this change inherited, while failing the write would turn a cleanup miss
into a failed request.

Windows makes that concrete: Go opens files with FILE_SHARE_READ and
FILE_SHARE_WRITE but not FILE_SHARE_DELETE, so a reader holding the
sidecar open blocks deletion, and that reader is the workload this
change exists to protect. Propagating would fail stores during exactly
the overlap being fixed. The next store of the key retries.

A test pins it, using a non-empty directory at the sidecar path to make
os.Remove fail with something other than not-exist on any platform.

* Fail the concurrency test if its writer stops

The writer returned silently when Store failed, so the test could pass
with no concurrent writes at all. Its error is now reported, and the
test also checks that at least one write completed.

Reporting it showed the writer had been dying on Windows at its first
collision: Go opens files without FILE_SHARE_DELETE, so a reader holding
the file open makes the writer's rename fail with access denied. The
test now skips there, since it cannot contend a writer with readers on
that platform.

* Clear legacy sidecars for keys fileblob escapes

legacySidecarPath declined any key filepath.Localize rejects, which on
Windows is every key with a colon: OCI digests and Debian epochs. Their
sidecars were never cleared there, and a truncated one kept failing
reads, since fileblob still reads a sidecar it finds under metadata=skip.

fileblob hex-escapes such characters on the way to disk. The path is now
derived the same way, so the sidecar is looked for where fileblob wrote
it. Localize still validates the escaped form, which keeps the removal
inside the cache directory.

* Drop stale comment about declining colon keys on Windows

623ff3e made legacySidecarPath escape keys the way fileblob does, so
colon-bearing keys are now cleared on Windows and the OCI and Debian
rows in TestStoreClearsLegacyAttrsSidecar prove it. The comment
described the behaviour before that commit.

---------

Co-authored-by: Andrew Nesbitt <andrewnez@gmail.com>
2026-09-15 20:07:18 +01:00
Andrew Nesbitt
41ae7d6520
Add GCS storage backend with lighter dependencies (#179)
* Add GCS storage backend with Workload Identity support

Register gocloud.dev/blob/gcsblob so gs:// URLs are accepted as a storage
backend. Authentication uses Application Default Credentials, which makes
GKE Workload Identity work out of the box; signed URLs (direct_serve)
fall back to the IAM Credentials signBlob API when no private key is
available.

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

* Replace gcsblob with lightweight GCS backend

* Extract GCS client into standalone module

---------

Co-authored-by: Anthony A. <github@anthony-arnaud.fr>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-08-29 11:23:07 +01:00
Andrew Nesbitt
272e6d9040
Lint and dead-code cleanup (#279)
* Bump go tool golangci-lint to v2.13.1

The .golangci.yml goconst.ignore-tests setting was added in v2.12.0
(golangci/golangci-lint#6480). On the previously pinned v2.10.1,
config verify fails with "additional properties 'ignore-tests' not
allowed" and the setting is silently ignored at run time, so goconst
counts test-file literals toward min-occurrences.

* Apply gofmt and CutSuffix simplification

- gofmt -w internal/server/health_test.go
- Replace HasSuffix+TrimSuffix with CutSuffix in ParseSize

* Remove dead code and migrate tests off legacy Filesystem storage

Migrate the three test call sites of storage.NewFilesystem to
storage.OpenBucket("file://...") and drop the deprecated
StorageConfig.Path field from test configs, then delete code that
deadcode reports as unreachable from cmd/proxy:

- internal/storage/filesystem.go and its tests
- storage.HashingReader
- enrichment.Service.BulkCheckVulnerabilities and NormalizeLicense
- server.ActiveRequestsMiddleware (no-op body; the real tracking
  is the inline r.Use at server.go:226)
- mirror.RegistrySource (unimplemented stub)

metrics.UpdateCircuitBreakerState and RecordCircuitBreakerTrip are
kept because #275 wires them.

Update the CONTRIBUTING.md storage section to reflect blob.go.
2026-08-21 09:26:27 +01:00
Andrew Nesbitt
98150ea576
Name empty path validation subtest 2026-07-09 17:41:05 +01:00
Andrew Nesbitt
41465968cb
Validate filesystem storage paths 2026-07-09 17:36:18 +01:00
Mati Kepa
31a9ca75b2
add Gradle Build Cache support with handler and tests (#87)
* add Gradle Build Cache support with handler and tests

* linting issue

* MR Suggestions: Add Gradle HTTP Build Cache configuration to README

* implement  minor stuff: Refactor Gradle handler to remove unnecessary URL parameter and update related tests

Co-authored-by: Copilot <copilot@github.com>

* Add Gradle build cache configuration and eviction support

- Introduced configuration options for Gradle build cache in config files and documentation.
- Implemented read-only mode and upload size limits for the Gradle build cache.
- Added cache eviction logic based on age and size, with corresponding tests.
- Enhanced storage interfaces to support listing objects by prefix.

* implement minor stuff: Refactor Gradle handler to remove unnecessary URL parameter and update related tests

* last finding fix

* fix tests and implement PR suggestions

Co-authored-by: Copilot <copilot@github.com>

* unify path

---------

Co-authored-by: Mateusz (Mati) Kepa <m.kepa@sportradar.com>
Co-authored-by: Copilot <copilot@github.com>
2026-05-04 11:15:16 +01:00
Andrew Nesbitt
71e8d3b9eb
Reject path traversal in filesystem storage (#106) 2026-05-02 18:00:28 +01:00
Andrew Nesbitt
c73b0a35a1
Add direct-serve via presigned storage URLs
When storage.direct_serve is enabled and the backend supports it (S3,
Azure), cached artifact downloads return a 302 redirect to a presigned
URL instead of streaming bytes through the proxy. Falls back to
streaming when the backend can't sign (fileblob, local filesystem) or
signing fails.

Adds the azureblob driver so azblob:// storage URLs work.

Cache-hit accounting already happened before io.Copy so redirects are
counted correctly; the metrics calls are pulled into a helper so both
paths share them.

Closes #96
2026-04-27 12:04:38 +01:00
c655399a07 Apply 'go fmt' as suggested in CONTRIBUTING.md. 2026-04-18 07:43:22 -04:00
Andrew Nesbitt
24d5e77443
Fix cross-device link error when running in Docker with volumes (#66)
`fileblob` creates temp files in `os.TempDir()` (`/tmp`) by default,
then uses `os.Rename` to move them to the final path. When the storage
directory is on a different filesystem (e.g. a Docker volume mount at
`/data`), the rename fails with "invalid cross-device link".

Set `no_tmp_dir=true` on file:// bucket URLs so fileblob creates temp
files next to the final destination instead.

Fixes #65
2026-04-06 13:07:31 +01:00
Andrew Nesbitt
beddf8357a
Fix startup message and add connectivity check for S3 storage (#57)
* Fix startup message and add connectivity check for S3 storage

When S3 storage is configured, the startup log incorrectly showed the
default local path (./cache/artifacts) instead of the actual S3 URL.
This also adds a lightweight connectivity check at startup so bad
credentials or endpoints fail immediately rather than on first request.

Add URL() and Close() to the Storage interface so all backends report
their URL and can be cleaned up properly. Rename the stats JSON field
from storage_path to storage_url. Close storage in error paths and
during graceful shutdown.

Fixes #49

* Fix Windows test assertion for file:// URL format

OpenBucket normalizes Windows paths to file:///C:/path (three slashes)
but the test expected file://C:/path (two slashes).
2026-04-03 14:06:51 +01:00
Andrew Nesbitt
599fe9e254
Fix all golangci-lint issues across the codebase (#32)
* Fix all golangci-lint issues across the codebase

Resolve 77 lint issues reported by golangci-lint with gocritic, gocognit,
gocyclo, maintidx, dupl, mnd, unparam, ireturn, goconst, and errcheck
enabled. Net reduction of ~175 lines through shared helpers and
deduplication.

* Suppress staticcheck SA1019 for intentional deprecated field usage

The Storage.Path field is deprecated but still read for backwards
compatibility with existing configs that haven't migrated to the URL field.
2026-03-18 10:59:29 +00:00
Andrew Nesbitt
9c974a0a81
Fix Windows CI test failures
- Use proper file:/// URL format for Windows paths in blob storage tests
- Accept both text/javascript and application/javascript MIME types
2026-01-29 21:12:13 +00:00
Andrew Nesbitt
ba754f8a79
Add gocloud.dev/blob for S3 and filesystem storage
Replace custom filesystem storage with gocloud.dev/blob for unified
storage backend support.

Supported backends:
- file:///path/to/dir - Local filesystem (default)
- s3://bucket-name - Amazon S3
- s3://bucket?endpoint=http://localhost:9000 - S3-compatible (MinIO)

Configuration via:
- CLI flag: -storage-url
- Environment: PROXY_STORAGE_URL
- Config file: storage.url

The old storage.path config is deprecated but still supported.
2026-01-29 16:13:16 +00:00
Andrew Nesbitt
7b22638ef7
Hello world 2026-01-20 22:00:31 +00:00