Skip to content

[release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (2.7.0) - #123

Merged
pditommaso merged 1 commit into
claude/lib-util-net-proxy-configfrom
claude/lib-httpx-drop-hxproxyconfig
Sep 6, 2026
Merged

[release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (2.7.0)#123
pditommaso merged 1 commit into
claude/lib-util-net-proxy-configfrom
claude/lib-httpx-drop-hxproxyconfig

Conversation

@pditommaso

@pditommaso pditommaso commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #122 (which adds io.seqera.util.net.ProxyConfig to lib-util-net). This removes the near-identical duplicate the reviewer flagged: lib-httpx now depends on lib-util-net and HxProxyConfig is deleted, so the proxy selector / authenticator / no-proxy semantics live in exactly one place, shared with Wave and Nextflow.

Stacked on #122 — review/merge that first. This PR's base retargets to master once #122 lands.

Changes (BREAKING (shipped as a minor - see changelog) → lib-httpx 2.7.0)

  • Delete HxProxyConfig (and HxProxyConfigTest) — its parsing-free Endpoint/toProxySelector/toAuthenticator/isBypassed/credentialsFor were character-for-character identical to lib-util-net's ProxyConfig.
  • HxClient.Builder.withProxyConfig now accepts an io.seqera.util.net.ProxyConfig. The body is unchanged — it already used getHttpProxy()/getHttpsProxy()/toProxySelector()/toAuthenticator(), which ProxyConfig exposes with the same shape.
  • build.gradle: api project(':lib-util-net').
  • Javadoc references and HxClientProxyAuthIntegrationTest migrated to ProxyConfig (the integration test now resolves via ProxyConfig.fromUri(...)).

Migration for callers

Anything that built an HxProxyConfig resolves a ProxyConfig instead:

// before
HxClient.newBuilder().withProxyConfig(HxProxyConfig.newBuilder().httpProxy(host, port, user, pass).build())
// after
HxClient.newBuilder().withProxyConfig(ProxyConfig.fromUri("http://user:pass@host:port"))

The only in-repo/-org caller is Nextflow (nextflow.util.ProxyConfig + TowerXAuth), migrated alongside this change; Platform and Wave don't use HxProxyConfig.

Tests

:lib-httpx:test green, incl. HxClientProxyAuthIntegrationTest (9/9) driving a real HxClient through an authenticating proxy via the migrated ProxyConfig.

🤖 Generated with Claude Code

@pditommaso
pditommaso force-pushed the claude/lib-httpx-drop-hxproxyconfig branch 2 times, most recently from 18a1237 to 57fbb37 Compare September 6, 2026 19:25
@pditommaso pditommaso changed the title [release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (3.0.0) [release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (2.8.0) Sep 6, 2026
@pditommaso
pditommaso force-pushed the claude/lib-httpx-drop-hxproxyconfig branch from 57fbb37 to c947ddf Compare September 6, 2026 19:28
@pditommaso pditommaso changed the title [release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (2.8.0) [release] Remove HxProxyConfig from lib-httpx in favour of lib-util-net ProxyConfig (2.7.0) Sep 6, 2026
@pditommaso

Copy link
Copy Markdown
Contributor Author

This removes HxProxyConfig and points lib-httpx at io.seqera.util.net.ProxyConfig (from #122), so the proxy selector / authenticator / no-proxy semantics live in one place. Shipped as 2.7.0 — source-incompatible for any HxProxyConfig caller, but the only one (Nextflow) is migrated in lock-step; the changelog spells out why it's a minor rather than a major.

Stacked on #122 (already approved); its base retargets to master once #122 merges.

@claude review

@claude

claude Bot commented Sep 6, 2026

Copy link
Copy Markdown

Claude finished @pditommaso's task in 2m 24s —— View job


Review: remove HxProxyConfig in favour of io.seqera.util.net.ProxyConfig

  • Read the diff vs claude/lib-util-net-proxy-config
  • Compare deleted HxProxyConfig against ProxyConfig for behavioural parity
  • Check HxClient / HxConfig call sites and build wiring
  • Check test migration + coverage loss
  • Post review

Verdict: Comment — no defect found in the code, but I'm not approving

The diff itself is clean and I found no correctness, security or data-loss issue. I'm withholding approval purely on scope, not on a defect: this deletes a public type (HxProxyConfig) and changes the signature of a public method (HxClient.Builder.withProxyConfig). That's a backward-incompatible contract change, and the "ship it as a minor because the only consumer is migrated in lock-step" call is a human decision — the changelog argues it well, but it should be a maintainer's signature, not mine.

Everything below is either verification or a non-blocking fix.


Behavioural parity — verified

I diffed the deleted HxProxyConfig against lib-util-net's ProxyConfig method by method:

behaviour parity
toProxySelector() — precomputed lists, scheme routing, connectFailed logging identical
toAuthenticator()RequestorType.PROXY guard, host+port match, empty-password fallback identical
isBypassed() — loopback set, *, *.x / .x suffix-only, bare x = host + subdomains identical, character for character
credentialsFor() — https endpoint preferred, case-insensitive host identical
hasCredentials() identical

The withProxyConfig body (HxClient.java:1247-1256) is unchanged and still typechecks: getHttpProxy()/getHttpsProxy() return ProxyConfig.Endpoint instead of the package-private ProxyEntry, and the body only null-checks them. api project(':lib-util-net') (not implementation) is the right scope, since ProxyConfig is in the public signature of withProxyConfig.

Test coverage is not lost: every scenario in the deleted HxProxyConfigTest (scheme selection, direct-connect fallback, NO_PROXY matching, wildcard, loopback, authenticator scoping, no-credentials → null authenticator) has an equivalent in lib-util-net's ProxyConfigTest, which additionally covers parsing, credential decoding, and the CONNECT-tunnel case. HxClientProxyAuthIntegrationTest still exercises a real HxClient end-to-end through the authenticating proxy.


Blocking-ish for the release: lib-httpx/README.md is stale

CLAUDE.md says "When releasing a new version, update the module's README.md to reflect the new version number" — and beyond the version, the README still documents the class this PR deletes. A user copy-pasting from it gets code that does not compile:

  • lib-httpx/README.md:13implementation 'io.seqera:lib-httpx:2.6.0'2.7.0
  • lib-httpx/README.md:28 — feature bullet still says "an HxProxyConfig value"
  • lib-httpx/README.md:407-418 — the whole proxy example uses HxProxyConfig.newBuilder().httpsProxy(host, port, user, pass).noProxy(...), an API that no longer exists
  • lib-httpx/README.md:472Key Classes still lists HxProxyConfig: "assembled from explicit values via its builder"

Worth also noting in the README that the type now comes from io.seqera:lib-util-net, since it is an api dependency callers will see on their compile classpath.

Fix this →


Non-blocking notes

1. Point the migration at the 4-arg fromUri for raw credentials. The PR body and changelog suggest:

ProxyConfig.fromUri("http://user:pass@host:port")

That embeds credentials in a URI, so a password containing @, : or % has to be percent-encoded by the caller or it mis-parses silently — a footgun the old httpProxy(host, port, user, pass) builder didn't have. ProxyConfig already has the safe overload:

ProxyConfig.fromUri("http://host:port", user, pass, noProxy);  // explicit creds win over user-info

Calling that out in changelog.txt (and the README) would spare migrating callers a subtle bug. The integration test's "http://alice:s3cret@127.0.0.1:${proxyPort}" is fine as-is since those credentials are literal-safe.

2. Small semantic shift worth a changelog line. HxProxyConfig could carry an http proxy without an https one (and vice versa); ProxyConfig.fromUri always applies one endpoint to both. Asymmetric per-protocol config is now only reachable via fromEnvironment. Not a bug for any current caller — just no longer expressible from explicit values.

3. Publish ordering (informational). .github/workflows/build.yml publishes lib-httpx (line 88) before lib-util-net (line 97). Harmless here — #122 lands first, and even in a shared run both artifacts appear before the job ends — but if the two ever released together, lib-httpx's POM would briefly reference a coordinate not yet in S3.


What I could not verify

I couldn't run ./gradlew :lib-httpx:test — the build command needed approval in this sandbox, so the green test run reported in the PR body is unverified by me. The compile-level reasoning above is from reading the sources.
· branch claude/lib-httpx-drop-hxproxyconfig

@pditommaso
pditommaso force-pushed the claude/lib-httpx-drop-hxproxyconfig branch from c947ddf to 2cd40af Compare September 6, 2026 19:35
@pditommaso

Copy link
Copy Markdown
Contributor Author

Addressed the doc/changelog items:

  • Stale lib-httpx/README.md — bumped the dependency snippet to 2.7.0, and the proxy bullet, the proxy example, and the Key Classes entry now reference io.seqera.util.net.ProxyConfig (noting it comes from the api dependency io.seqera:lib-util-net); the deleted HxProxyConfig.newBuilder() example is gone.
  • Migration footgun (non-blocking 1) — the README example and changelog now steer callers to ProxyConfig.fromUri(uri, user, pass, noProxy) for raw credentials, rather than embedding them in the URI.
  • Semantic shift (non-blocking 2) — changelog now notes that asymmetric per-protocol config from explicit values is only expressible via fromEnvironment.
  • Publish ordering (non-blocking 3)build.yml now publishes lib-util-net before lib-httpx, since lib-httpx now depends on it.

On the verdict: agreed the breaking-change-as-a-minor is a maintainer call, not the bot's — leaving the approval/merge decision to @pditommaso.

…(lib-httpx 2.7.0)

BREAKING (shipped as a minor - see changelog): delete HxProxyConfig and depend on
io.seqera:lib-util-net so the proxy selector / authenticator / no-proxy semantics live in
one place, shared with Wave and Nextflow instead of being duplicated across lib-httpx and
lib-util-net.

HxClient.Builder.withProxyConfig now accepts an io.seqera.util.net.ProxyConfig (its
toProxySelector()/toAuthenticator()/getHttpProxy()/getHttpsProxy() are the same shape the
method already used). Callers that built an HxProxyConfig resolve a ProxyConfig instead via
ProxyConfig.fromUri(...)/fromEnvironment(...). The only affected consumer (Nextflow) is
migrated in lock-step.

Also updates README (version + proxy example/Key Classes now reference ProxyConfig) and
reorders the publish workflow so lib-util-net is published before its new dependent lib-httpx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pditommaso
pditommaso force-pushed the claude/lib-httpx-drop-hxproxyconfig branch from 2cd40af to 8615797 Compare September 6, 2026 19:39
@pditommaso
pditommaso merged commit 1285e91 into claude/lib-util-net-proxy-config Sep 6, 2026
3 checks passed
pditommaso added a commit that referenced this pull request Sep 6, 2026
…0) (#122)

* [release] Add ProxyConfig egress-proxy resolver to lib-util-net (0.2.0)

Add io.seqera.util.net.ProxyConfig: resolve an HTTP/HTTPS forward (egress)
proxy - including an authenticating one - from a proxy URI or from the
HTTP_PROXY/HTTPS_PROXY/NO_PROXY environment variables, exposed as a java.net
ProxySelector and a proxy-scoped Authenticator suitable for a
java.net.http.HttpClient.

Parsing, credential-decoding, no-proxy and Basic-over-CONNECT semantics mirror
Nextflow's nextflow.util.ProxyConfig (the source of truth), so products sharing
this class share the same proxy behaviour. Depends only on the JDK plus the
slf4j-api logging facade; the caller passes the URI or environment map in.

This lets Wave (and, subsequently, Nextflow) drop their own duplicated
resolver implementations.

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

* Make ProxyConfig.parse public for component-level reuse

Expose parse(String) and the Parsed record so callers needing the individual
proxy components (e.g. Nextflow's Launcher, which sets -Dhttp.proxyHost system
properties) can reuse the parsing instead of duplicating it.

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

* Add ProxyConfig.setupFromEnvironment for JVM-global proxy install

Capture the env->proxy setup previously hand-rolled in Nextflow's launcher: set
per-protocol http/https/ftp proxyHost/proxyPort + http.nonProxyHosts system
properties, install the proxy-scoped Authenticator as the JVM default and clear
jdk.http.auth.tunneling.disabledSchemes when credentials are present. Returns the
resolved http/https ProxyConfig for wiring java.net.http clients explicitly.

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

* Expose resolved proxy endpoints on ProxyConfig

Make the Endpoint record public and add getHttpProxy()/getHttpsProxy()/
getNoProxyHosts() so a caller (e.g. Nextflow) can adapt the resolved config to
another representation such as lib-httpx HxProxyConfig without re-parsing.

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

* Add setupFromEnvironment coverage: ALL_PROXY fallback and disabledSchemes cases

Recapture the behaviours previously verified in Nextflow's LauncherTest (now that the
setup logic lives here): ALL_PROXY fallback for the per-protocol system properties, and
the jdk.http.auth.tunneling.disabledSchemes clear/preserve rules.

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

* Address review: lenient env parsing, username-only creds, null-safety, redaction

- fromEnvironment tolerates an unsupported scheme (e.g. socks5://) or malformed value,
  logging and treating it as absent instead of throwing; fromUri still throws
- parse keeps a username-only user-info (e.g. a token proxy) instead of dropping it
- fromEnvironment/setupFromEnvironment return null for a null env map
- warn when a proxy is addressed over https (JDK has no TLS-to-proxy support)
- Parsed.toString redacts the password
- README: move the egress-proxy section under Usage (was nested under Limitations)

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

* Address re-review: redact proxy creds in errors, fix NO_PROXY->nonProxyHosts

B1: redact the user-info before logging/raising an invalid proxy value, so the proxy
    password never reaches the log or an exception message (parseLenient + parse)
B2: map NO_PROXY to the JDK http.nonProxyHosts grammar (exact host + '*' wildcard),
    prepend the default loopback bypass it would otherwise replace, expand a bare host to
    'host|*.host' to match isBypassed, and set ftp.nonProxyHosts too
N1: default the proxy port from the proxy scheme (http->80, https->443) in fromEnvironment,
    matching fromUri
N3: make the public Endpoint record's hasCredentials()/address() public
N4/N5: javadoc notes (ftp is system-property only; IPv6-without-scheme and NO_PROXY-port limits)
N6: @ResourceLock the JVM-global-mutating tests

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

* Redact the password in Endpoint.toString (review follow-up)

Endpoint is public and returned by getHttpProxy()/getHttpsProxy(), so its default record
toString() would render the proxy password if a consumer logged it - the same latent leak
class B1 closed for Parsed. Add a redacting toString override.

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

* [release] Remove HxProxyConfig in favour of lib-util-net ProxyConfig (lib-httpx 2.7.0) (#123)

BREAKING (shipped as a minor - see changelog): delete HxProxyConfig and depend on
io.seqera:lib-util-net so the proxy selector / authenticator / no-proxy semantics live in
one place, shared with Wave and Nextflow instead of being duplicated across lib-httpx and
lib-util-net.

HxClient.Builder.withProxyConfig now accepts an io.seqera.util.net.ProxyConfig (its
toProxySelector()/toAuthenticator()/getHttpProxy()/getHttpsProxy() are the same shape the
method already used). Callers that built an HxProxyConfig resolve a ProxyConfig instead via
ProxyConfig.fromUri(...)/fromEnvironment(...). The only affected consumer (Nextflow) is
migrated in lock-step.

Also updates README (version + proxy example/Key Classes now reference ProxyConfig) and
reorders the publish workflow so lib-util-net is published before its new dependent lib-httpx.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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