fix(deps): make hackney an optional dependency (additionally: bump hackney to 4.x to address security advisories)#104
Conversation
hackney <= 4.0.1 is affected by a batch of advisories fixed in 4.0.2+ (e.g. CVE-2026-47075 CRLF injection / HTTP request splitting, CVE-2026-47066 infinite loop, CVE-2026-47070, CVE-2026-47077). There is no 1.x backport, so the previous `~> 1.9` constraint could only resolve to vulnerable releases. Widen the constraint to `~> 1.21 or ~> 4.0 and >= 4.0.2`, mirroring Tesla's own hackney adapter constraint, and update the lock so it resolves to hackney 4.4.5. Tesla is bumped 1.8.0 -> 1.20.0 because older Tesla capped its optional hackney dependency at `~> 1.6`, which blocked 4.x resolution. workos uses hackney only as the default Tesla adapter (never directly), and the test suite runs against Tesla.Mock, so the major bump is absorbed by Tesla's adapter. Full suite passes (113 tests).
Greptile SummaryThis PR updates the optional HTTP adapter dependency path for the Elixir SDK. The main changes are:
Confidence Score: 4/5Merge should wait for the dependency constraint to preserve compatibility with consumers that still resolve the supported 1.x hackney line. The changed dependency declaration is small and localized, and the compatibility issue is directly tied to the version expression in mix.exs. mix.exs
What T-Rex did
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cd57e85968
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, | ||
| "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, | ||
| "h2": {:hex, :h2, "0.10.2", "ea0146b9c8b5f3b5de16045765f5684db38ef1e66f1c60444890948cb1003e47", [:rebar3], [], "hexpm", "497a899f338b42e6a0b292524e635b0ce6f9379fa39395c8e38d06351cd9b9cf"}, | ||
| "hackney": {:hex, :hackney, "4.4.5", "a908f620525bb886a16613532324762e5166287f8c00c9888a762edee11a30c0", [:rebar3], [{:certifi, "~> 2.17.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:h2, "~> 0.10.1", [hex: :h2, repo: "hexpm", optional: false]}, {:idna, "~> 7.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.4", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.2", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:quic, "~> 1.6.5", [hex: :quic, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:webtransport, "~> 0.4.1", [hex: :webtransport, repo: "hexpm", optional: false]}], "hexpm", "6d72bef4e135e94c522c271e11fbb6933efb0006ef235a3933807d0be73b71ec"}, |
There was a problem hiding this comment.
Avoid pulling quic into OTP 25 builds
The CI matrix still includes an OTP 25.3 job (.github/workflows/main.yml:30-31) and that job runs mix do deps.get, deps.compile (.github/workflows/main.yml:57-59), but this lock entry makes quic a non-optional transitive dependency of hackney 4.4.5. quic 1.6.x declares {minimum_otp_vsn, "26"}, so the OTP 25 job and users on that still-supported runtime will fail during dependency compilation even though mix.exs still advertises broad Elixir support. Please either drop OTP 25 support or avoid resolving a hackney version that pulls this OTP 26-only dependency for supported builds.
Useful? React with 👍 / 👎.
Brings in workos#105 (Elixir floor 1.16 / OTP 26, CI matrix through 1.20, split lint.yml, credo 1.7 / dialyxir 1.4). The new OTP 26 floor satisfies hackney 4.x's OTP 26+ requirement, so no further version bump is needed. mix.lock conflict resolved by keeping this branch's hackney 4.4.5 + tesla 1.20.0 while pulling main's credo 1.7.19 / dialyxir 1.4.7 forward. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per customer request, hackney is now declared `optional: true` so it is no longer forced onto downstream consumers. The SDK never wires hackney as the Tesla adapter (Tesla defaults to :httpc), so consumers are free to bring their own HTTP client and configure Tesla accordingly. When hackney is used it must be a patched release (>= 4.0.2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
T-Rex pricing update — T-Rex was free through June 2026. Effective July 1, 2026, T-Rex adds 2 credits on top of the standard 1-credit review (3 total). T-Rex settings |
hackney 4.x no longer depends on :metrics or :unicode_util_compat (those belonged to the hackney 1.x tree). They lingered in mix.lock and tripped `mix deps.unlock --check-unused` in CI. Remove them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 1.x line has no backport for the CRLF/redirect/DoS advisories, so allowing `~> 1.21` would let consumers resolve to a vulnerable hackney. Narrow the constraint to the patched 4.x line only (>= 4.0.2, < 5.0.0). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the `~> 4.0 and` half of the constraint. There is no single `~>` shorthand for ">= 4.0.2, capped below 5.0.0", and hackney is optional and never called directly by the SDK, so an unbounded floor is sufficient — Tesla's own adapter constraint (< 5.0.0) already caps the upper bound. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| # hackney is an optional Tesla adapter (the SDK never wires it up; Tesla | ||
| # defaults to :httpc). Require >= 4.0.2 — the 1.x line has no security backport. | ||
| {:hackney, ">= 4.0.2", optional: true}, |
There was a problem hiding this comment.
Preserve downstream compatibility
The new >= 4.0.2 constraint excludes every 1.x hackney release, so any consumer that still has hackney 1.21.x in its dependency graph now gets a resolver conflict despite this dependency being optional. The lockfile shows Tesla 1.20.0 already accepts ~> 1.21 or >= 4.0.2 and < 5.0.0-0, so matching that constraint keeps the intended compatibility while preferring patched 4.x on a fresh resolve.
| # hackney is an optional Tesla adapter (the SDK never wires it up; Tesla | |
| # defaults to :httpc). Require >= 4.0.2 — the 1.x line has no security backport. | |
| {:hackney, ">= 4.0.2", optional: true}, | |
| # hackney is an optional Tesla adapter (the SDK never wires it up; Tesla | |
| # defaults to :httpc). Allow patched 4.x while preserving compatibility | |
| # with consumers still pinned to the latest 1.x line. | |
| {:hackney, "~> 1.21 or >= 4.0.2 and < 5.0.0-0", optional: true}, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: mix.exs
Line: 70-72
Comment:
**Preserve downstream compatibility**
The new `>= 4.0.2` constraint excludes every `1.x` hackney release, so any consumer that still has `hackney` `1.21.x` in its dependency graph now gets a resolver conflict despite this dependency being optional. The lockfile shows Tesla `1.20.0` already accepts `~> 1.21 or >= 4.0.2 and < 5.0.0-0`, so matching that constraint keeps the intended compatibility while preferring patched `4.x` on a fresh resolve.
```suggestion
# hackney is an optional Tesla adapter (the SDK never wires it up; Tesla
# defaults to :httpc). Allow patched 4.x while preserving compatibility
# with consumers still pinned to the latest 1.x line.
{:hackney, "~> 1.21 or >= 4.0.2 and < 5.0.0-0", optional: true},
```
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
thanks! |
Summary
hackneyreleases<= 4.0.1are affected by a batch of security advisories fixed in hackney 4.0.2+:There is no 1.x backport, so the previous
{:hackney, "~> 1.9"}constraint could only ever resolve to vulnerable releases (the lockfile sat at1.20.1).Changes
Make
hackneyoptional and require a patched release:optional: true(per customer request) means hackney is no longer forced onto downstream consumers — they're free to bring their own HTTP client. This is safe because the SDK never wires hackney as the Tesla adapter; Tesla falls back to its built-in default (:httpc) unless the consumer configures otherwise.~>shorthand for "≥ 4.0.2 but < 5.0.0", and an unbounded floor is sufficient here — Tesla's own adapter constraint caps the upper bound at< 5.0.0, so the lock resolves to hackney 4.4.5.mix.locknow resolvesteslato 1.20.0 (up from 1.8.0): older Tesla capped its optional hackney dependency at~> 1.6, which blocked 4.x resolution. Recent Tesla's hackney adapter supports the 4.x API.Pruned orphaned lock entries (
:metrics,:unicode_util_compat) left over from the hackney 1.x tree, which otherwise tripmix deps.unlock --check-unused.Merged
main(feat: raise Elixir floor to 1.16, OTP to 26, and test through 1.20 #105), which raised the Elixir floor to 1.16 / OTP 26 and expanded the CI matrix through Elixir 1.20. hackney 4.x pulls inquic(HTTP/3), which requires OTP 26+ — the new floor satisfies that.main.{:hackney, ">= 4.0.2"}to their own deps (and be on OTP 26+), or configure Tesla with a different adapter.Why this is low-risk
:httpc). Consumers who want hackney opt in explicitly.Tesla.Mock, so hackney isn't exercised in tests.Verification
MIX_ENV=prod mix compile --force --warnings-as-errors— clean compile with hackney 4.4.5 + tesla 1.20.0.mix test— 113 passed.mix hex.audit— no retired packages.