Skip to content

feat(serve): add Sonatype Nexus as a shared cache tier - #514

Merged
tinder-maxwellelliott merged 1 commit into
masterfrom
claude/nexus-caching-bazel-diff-34420b
Oct 5, 2026
Merged

tinder-maxwellelliott merged 1 commit into
masterfrom
claude/nexus-caching-bazel-diff-34420b

Conversation

@tinder-maxwellelliott

Copy link
Copy Markdown
Collaborator

What

Adds a Sonatype Nexus raw hosted repository as a shared cache tier for bazel-diff serve, alongside the existing S3 tier. You can use one or the other, not both.

Cache entries are read and written with plain GET/PUT on <nexusUrl>/repository/<repo>/<prefix>/<key>.json. The Nexus tier fails the same way S3 does: a failed read is treated as a cache miss and the revision is regenerated, and a failed write leaves the entry on local disk only. An outage slows things down but never fails a request.

Changes

  • src/server.rs: RemoteCache is now an enum over S3 (the existing code, renamed S3Cache) and a new Nexus backend. The Nexus client:
    • sets a connect timeout (10s) and a read timeout (60s);
    • does not follow redirects, so basic-auth credentials are never sent to another host;
    • shortens error bodies (Nexus often returns full HTML pages) in its warnings;
    • adds a hint on a 400 when writing: it usually means the repository's deployment policy forbids redeploy.
  • src/main.rs: new flags --nexusUrl, --nexusRepository, --nexusPrefix, --nexusUsername (also BAZEL_DIFF_NEXUS_USERNAME), and --nexusCaCert (a PEM bundle of extra CA certificates, for a Nexus behind an internal CA).
    • The password is read only from the BAZEL_DIFF_NEXUS_PASSWORD environment variable, so it never shows up in a process listing.
    • Credentials embedded in the URL are rejected, and the password is redacted in Debug output.
    • --nexusUrl and --nexusRepository require each other and conflict with --s3Bucket.
    • A username without a password, or a password without a username, fails at startup.
    • Commands::Serve now wraps its args in a Box, because clippy's large_enum_variant fired once the new fields were added.
  • Dependencies: attohttpc (already pulled in by rust-s3; this enables its basic-auth feature) and rustls-pki-types (for PEM parsing). No new crates are downloaded. cargo-bazel-lock.json is repinned.
  • Docs: adds a "Shared Sonatype Nexus cache" section to tools/readme_template.md and regenerates README.md. It covers repository setup, credentials and user tokens, required privileges, TLS, redirects, and retention via a Nexus cleanup policy.

Why

This gives teams that run Nexus instead of AWS a way to share the hash cache across a fleet of serve instances. A revision then gets hashed once across the fleet instead of once per instance.

Notes for reviewers

  • Setup requirement: the raw hosted repository must use the Allow redeploy deployment policy. Instances that race on the same revision each upload identical content, and "Disable redeploy" answers every second upload with a 400. Requests still succeed, but each one logs a warning.
  • CA file checking: --nexusCaCert is only checked as valid PEM at startup. A file that parses but contains a broken certificate would fail on every request (each logged as a cache miss), not at startup.
  • Testing:
    • Unit tests run against a tiny_http mock. They cover a hit, a miss, an upload with basic auth, failure statuses (500/401/302/400) each making exactly one request with no redirect followed, connection errors, URL building and validation, error-body truncation, password redaction, and loading the CA bundle.
    • CLI tests cover parsing the new flags, their validation, and the conflict with --s3Bucket.
    • cargo test --lib --bins passes, and so do clippy (-D warnings), cargo fmt --check, bazel build //:bazel-diff-rust, and bazel test //src:rust_tests //src:cli_tests.
    • I also ran two instances of the real binary against a mock Nexus with basic auth. The second instance served both revisions from Nexus without running bazel query. I have not tested against a real Nexus instance.
  • Possible follow-up: tools/serve_consistency.py only covers the S3 tier so far. A mock Nexus mode for it would extend the multi-instance consistency checks to this backend.

🤖 Generated with Claude Code

Adds a Nexus raw hosted repository as an alternative to the S3 shared
cache tier for multi-instance `serve` deployments. Entries are read and
written with plain GET/PUT on
<nexusUrl>/repository/<repo>/<prefix>/<key>.json and degrade exactly
like S3: a failed read is a miss, a failed write stays local-only.

New flags: --nexusUrl, --nexusRepository, --nexusPrefix,
--nexusUsername (env BAZEL_DIFF_NEXUS_USERNAME) and --nexusCaCert. The
password is environment-only (BAZEL_DIFF_NEXUS_PASSWORD) so it never
appears in a process listing; URL-embedded credentials are rejected and
redirects are not followed so basic auth is never replayed elsewhere.
The Nexus and S3 flags are mutually exclusive.

Uses attohttpc (already in the graph via rust-s3) with basic-auth
enabled, plus rustls-pki-types for PEM parsing; no new crates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tinder-maxwellelliott
tinder-maxwellelliott marked this pull request as ready for review October 5, 2026 15:33
@tinder-maxwellelliott
tinder-maxwellelliott merged commit 6403467 into master Oct 5, 2026
24 checks passed
@tinder-maxwellelliott
tinder-maxwellelliott deleted the claude/nexus-caching-bazel-diff-34420b branch October 5, 2026 16:37
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