feat(maven): set the upstream request User-Agent (S14 plan: 19/20)

Summary

Maven remote upstream requests currently carry no User-Agent, so Go's transport sends Go-http-client/1.1 — and Maven Central answers 429 to that exact string, making a remote pointed at Central unusable. This MR sets the header in UpstreamRequestBuilder.BuildRequest, pins it with a regression test, and records the requirement in the specs and the S14 plan.

What's in this MR

  • internal/format/maven/remote_upstream.goUser-Agent set on every composed upstream request (gitlab-artifact-registry/0.1.0; the exact value is a spec decision, see the amended spec paragraph).
  • internal/format/maven/remote_upstream_test.go — regression pinning the outgoing header on the composed request: both credential states and the HEAD-probe shape, exactly one header value.
  • docs/specs/S14-maven-remote.md — the Maven remote operations paragraph requiring the header, and the new "Upstream request identity" acceptance criterion under Credentials and health.
  • docs/specs/S13-virtual-remote-foundation.md — corrects the claim that the S13 client "accepts arbitrary header maps"; names the format's request builder as the single outbound header-composition site.
  • docs/plans/2026-07-27-maven-remote.md — Step 19 ("upstream request User-Agent") and its Status row.

Evidence

  • 429 to Go-http-client/1.1 on both Central hosts (repeatedly verified); 200 to Maven-shaped and custom values including gitlab-artifact-registry/*.
  • End-to-end verification with the header set: cold mvn dependency:get through the registry made exactly 2 upstream requests to repo1.maven.org, both 200, zero 429s; a cold 6.7 MB artifact completed through the registry in 4.9 s.

Deviation from repo guardrails (operator-approved)

Guardrails 3 ("do not write code until the plan MR is merged") and 4 ("step MRs do not edit the plan file") are overridden for this change: spec addenda, plan amendment, and code ship in one MR per explicit operator request. The plan's approval-signal role is carried by this MR's review instead of a separately merged plan MR, and the plan edit rides this branch as a single-writer exception.

No e2e scenario added

The change is one outbound header; no proxy behavior changes. The composed-request header is pinned by the unit test, and the live-Central behavior is documented on the linked issue. No docs/testing/ update is needed.

Spec-review note

The spec additions normally land via a spec MR with status Approved; in this combined MR they are reviewed inline as part of the change.

Related to #813 (closed)

Merge request reports

Loading
Loading