feat: bootstrap brand-list validator integration
Summary
Bootstrap the Artifact Registry integration with the Brand-List Validator (BLV): an HTTP client, a SaaS-only config block, and a startup smoke-test probe. This is the foundation, not the feature. It is the minimum needed to validate the end-to-end integration with the new BLV service running in Runway, and it is built production-ready so the S17 slug-claim work can plug in on top without reworking it. No slug-claim caller is wired yet.
Why now
This mechanical wiring is urgent to de-risk the Runway integration between two internal services. BLV is internal-only (ClusterIP, no ingress), so the AR<>BLV path cannot be exercised from a dev environment; we need AR deployed and connected in the staging/prod network to confirm Runway can route to a private/internal service. Keeping the change mechanical lets it land in a single MR within the documented LoC limits (aligns with the simplification proposed in work item 72). The slug-claim business logic is specified in S17 and tracked in #261 (closed).
What this adds
- HTTP client (
internal/brandlistvalidator): on LabKit's instrumentedhttpclient(spans, request logs, W3C trace propagation), injecting the correlation ID asX-Request-ID.Newvalidates the base URL and timeout;Reservedis fail-closed (transport error, non-200, or a malformed/missingreservedfield all return an error). - Config (
brand_list_validator): SaaS-only. Present enables it; absent skips it (Self-Managed / Dedicated).base_urlrequired,timeoutdefaults200ms. - Startup probe: a non-critical LabKit
app.Componentcalling the validator once at boot with a throwaway candidate. A failure warns and retries in the background rather than halting boot, and does not gate readiness. - CI integration test: runs the client against the BLV dev image (dummy list, pinned by digest) as a service container, exercising the live e2e path and the job-token allowlist.
Testing
Unit tests cover the fail-closed paths, base-URL/timeout validation, correlation-ID propagation, path escaping, the config load matrix, and the SaaS present/absent and invalid-config wiring branches; all pass under -race. The integration test runs in CI against the pinned dev image and hard-fails (rather than skipping) if its service URL is unset under CI.
Closes #193 (closed) (MVP mechanical wiring). Related to #261 (closed) (S17 slug-claim path).
Related to gitlab-org&22428 (closed)