Skip to content

fix(deps): cap Authlib below 1.8 to avoid the httpx2 timeout crash - #916

Open
Mighty303 wants to merge 1 commit into
mainfrom
fix/authlib-httpx2-timeout-crash
Open

fix(deps): cap Authlib below 1.8 to avoid the httpx2 timeout crash#916
Mighty303 wants to merge 1 commit into
mainfrom
fix/authlib-httpx2-timeout-crash

Conversation

@Mighty303

Copy link
Copy Markdown
Contributor

Description

Found while checking the resolved dependency set ahead of the next release.

There is no lockfile, so a fresh pip install safety resolves Authlib 1.8.0. 1.8.0 added a shim that prefers httpx2 over httpx whenever httpx2 is importable:

# authlib/integrations/httpx_client/_compat.py
try:
    import httpx2
except ImportError:
    import httpx as httpx2
    deprecate("The httpx module is deprecated; please use httpx2 instead.")

Safety builds its clients with an old-httpx Timeout object (safety/platform/client.py:197, safety/utils/tls_probe.py:166). When authlib routes through httpx2, that object reaches httpcore2, which wants a number:

$ safety auth status
  ...
  File ".../httpcore2/_backends/sync.py", line 204, in connect_tcp
    sock = socket.create_connection(
  File ".../socket.py", line 845, in create_connection
    sock.settimeout(timeout)
TypeError: 'Timeout' object cannot be interpreted as an integer
Trigger httpx2 present anywhere in the environment, plus Authlib ≥ 1.8.0
Effect every network-touching command dies with an unhandled TypeError
User error required none — safety often shares an env with a project's own dependencies
Scope the shim is in 1.8.0 only; 1.6.12 and 1.7.2 are clean (checked both)
Regression? No. 3.8.1 shipped Authlib>=1.2.0 uncapped and is equally exposed

Fix

Cap below 1.8. This keeps the security floor introduced in #908, and also removes the AuthlibDeprecationWarning that 1.8.0 prints to stderr on every invocation.

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactor
  • Other (please describe):

Related Issues

None.

Testing

  • Tests added or updated
  • No tests required

A dependency cap has no meaningful unit test — the behaviour under test is the resolution itself. Verified by building the wheel and installing it into a clean venv with httpx2 deliberately installed, which is the exact condition that triggers the crash:

Authlib   1.7.2      <- capped, no shim
httpx     0.28.1
httpx2    2.12.0     <- present, and now harmless

$ safety --version        # stderr AuthlibDeprecationWarning count: 0
$ safety auth status      # succeeds against the real platform

Same environment on main (Authlib 1.8.0) raises the TypeError above.

Verification:

  • Fresh wheel install + httpx2: safety auth status succeeds; on main it crashes
  • AuthlibDeprecationWarning no longer printed on any invocation
  • Full suite on that same capped environment: 886 passed, 7 skipped, 1 failed
  • The one failure is tests/integration/test_enroll.py::test_enroll_invalid_key_rejected, which fails identically on pristine main (env-dependent, unrelated)

Checklist

  • Code is well-documented
  • Changelog is updated (if needed) — auto-generated by commitizen at bump
  • No sensitive information (e.g., keys, credentials) is included in the code
  • All PR feedback is addressed

Additional Notes

Follow-up worth doing, deliberately not in this PR. The root cause is that safety passes httpx.Timeout(...) rather than a plain number. Changing both call sites to pass the float directly makes safety work under httpx and httpx2, which is what would let this cap be lifted:

-            "timeout": httpx.Timeout(timeout),
+            "timeout": timeout,

I tested that patch under Authlib 1.8.0 with httpx2 installed and a full safety auth login + auth status round-trip succeeded. It is kept out of this PR so the release-unblocking cap stays a one-line review.

Worth pairing that follow-up with a CI cell that installs httpx2, since nothing in the current matrix exercises this combination.

Authlib 1.8.0 added a compatibility shim that prefers httpx2 over httpx
whenever httpx2 is importable. Safety builds its clients with an old-httpx
`httpx.Timeout` object (platform/client.py:197, utils/tls_probe.py:166),
which then reaches httpcore2, which expects a number:

    sock.settimeout(timeout)
    TypeError: 'Timeout' object cannot be interpreted as an integer

Any environment with httpx2 present therefore crashes on every
network-touching command. The user does nothing wrong; safety frequently
shares an environment with a project's own dependencies.

Cap below 1.8. 1.6.12 and 1.7.x carry no shim, so the security floor from
#908 is preserved and the per-invocation AuthlibDeprecationWarning
disappears too.
@Mighty303 Mighty303 self-assigned this Sep 4, 2026
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 72a30ad6-6c1e-41a2-9a98-0f05cd881898

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Mighty303 Mighty303 added the bug Indicates a problem that needs to be resolved. label Sep 4, 2026
@safety-bot

Copy link
Copy Markdown
Contributor

🚀 Artifacts — PR #916 by @Mighty303

Security notice: You are viewing pre-release CI artifacts from PR #916 by @Mighty303. These commands may execute code on your machine. Do NOT run them unless you have reviewed the PR diff and trust the source. The snippets include a confirmation prompt.

Download the wheel file and binaries with gh CLI or from the workflow artifacts.

📦 Install & Run

Pre-requisites

# Install uv if needed
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create and enter artifacts directory
mkdir artifacts && cd artifacts

Quick Test with Python Package

bash -c 'set -euo pipefail; echo; echo "WARNING: You are about to download and execute CI artifacts from PR #916 by @Mighty303. Do NOT proceed unless you have reviewed the PR diff and trust the source."; echo; read -rp "Type I understand to continue: " C; [ "$C" = "I understand" ] || { echo "Aborted."; exit 1; }; gh run download 33907438857 -n dist -R pyupio/safety; uvx safety-*-py3-none-any.whl --version'

Run other Safety commands as follows

uvx safety-*-py3-none-any.whl auth status
uvx safety-*-py3-none-any.whl auth login
uvx safety-*-py3-none-any.whl scan

Note: You need to be logged in to GitHub to access the artifacts.

@Mighty303

Copy link
Copy Markdown
Contributor Author

Extra detail supporting the cap, from checking the sibling repo.

The existing <2.0 cap was never protecting anything: Authlib 2.0 does not exist. The full 1.7+ release list on PyPI is 1.7.0, 1.7.1, 1.7.2, 1.8.0. The httpx2 shim landed in 1.8.0, comfortably inside >=1.6.12,<2.0, so the constraint reads protective while allowing exactly the version that breaks.

For contrast, safety-endpoint is not exposed to this — but by accident rather than design. It is an application with a uv.lock, which happens to pin authlib 1.6.12 and carries no httpx2. Nobody chose that to dodge this bug; the lock simply froze the resolution before 1.8.0 shipped.

That difference is worth stating explicitly, because a lockfile is not an option here. pip install safety reads Requires-Dist from the wheel metadata, which comes from pyproject.toml. A lockfile committed to this repo would make CI reproducible and would never reach an end user:

main       Requires-Dist: authlib<2.0,>=1.6.12    -> resolves to 1.8.0
this PR    Requires-Dist: authlib<1.8,>=1.6.12    -> resolves to 1.7.2
lock files in the built wheel: NONE

The version specifier is the only lever that reaches installers, which is what this PR changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Indicates a problem that needs to be resolved.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants