Skip to content

build: drop psycopg-binary from extra_proxy and use the image libpq - #42909

Open
devin-ai-integration[bot] wants to merge 8 commits into
mainfrom
litellm_psycopg_no_binary_wheel
Open

devin-ai-integration[bot] wants to merge 8 commits into
mainfrom
litellm_psycopg_no_binary_wheel

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • psycopg-binary ships its own libcrypto/libssl inside every proxy image
  • That bundled OpenSSL is never the FIPS validated system one
  • The FIPS image plan (LIT-5289) needs the bundle gone from all images

How it solves it:

  • extra_proxy now depends on psycopg only, no binary wheel
  • Wolfi runtime stages install libpq-18, psycopg picks its pure Python driver over it
  • The one caller, the boot-time partition check on LiteLLM_SpendLogs, keeps working unchanged
  • Integration tests pin the locked extra, the runtime apk list and both boot outcomes
  • When psycopg imports but finds no libpq (a bare pip install outside the images), the skipped partition check warning now names the libpq load error instead of claiming psycopg is missing
  • The CircleCI database integration shard installs libpq5 first, since the machine image has no system libpq for the pure Python driver the new tests select

User Flow

Before: an operator scanning the proxy image for bundled crypto finds a second OpenSSL and cannot claim FIPS

  1. They pull ghcr.io/berriai/litellm:main-latest and run find / -name 'libcrypto*'
  2. Two copies come back: /usr/lib/libcrypto.so.3 and /app/.venv/.../psycopg_binary.libs/libcrypto-<hash>.so.3
  3. Their scanner flags the second copy as an unmanaged OpenSSL build, so the image fails their crypto inventory

After: the same scan finds only the distro OpenSSL, and the proxy still boots the same way

  1. They pull the image built from this PR and run the same find / -name 'libcrypto*'
  2. Only /usr/lib/libcrypto.so.3 comes back, and /usr/lib/libpq.so.5 is present for psycopg
  3. They start the proxy against their Postgres and GET /health/readiness returns {"status":"healthy","db":"connected"}
  4. Against a partitioned LiteLLM_SpendLogs, --use_prisma_db_push still refuses with the same partition guidance as before

Linear ticket

Resolves LIT-8433

Pre-Submission checklist

  • I have added meaningful tests
  • The handful of test files covering my change pass locally, e.g. uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*, make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more
  • My PR passes all required CI/CD checks (e.g., lint, schema.d.ts sync check, etc.)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Screenshots / Proof of Fix

Setup: the extra_proxy export of each leg, and the runtime stage of Dockerfile reproduced in a cgr.dev/chainguard/wolfi-base container (same digest as the Dockerfile) with the locked psycopg==3.3.3, pointed at a local Postgres holding a partitioned LiteLLM_SpendLogs

Before (09ebb28)

  1. uv export --frozen --no-hashes --no-dev --no-emit-project --extra extra_proxy | grep ^psycopg
    psycopg==3.3.3
    psycopg-binary==3.3.3
    
  2. pip install psycopg-binary==3.3.3 && find .venv -name 'libcrypto*' && strings <it> | grep -m1 '^OpenSSL '
    psycopg_binary.libs/libcrypto-2a5143d4.so.3
    OpenSSL 3.5.4 30 Sep 2025
    
    (the 3.3.3 wheel bundles OpenSSL 3.5.4; the 1.1.1k build the ticket names came from older wheels, either way it is a second OpenSSL the distro does not manage)
  3. The runtime stage apk add list has no libpq, so dropping the wheel alone would leave psycopg with no driver

After (36627a6)

  1. uv export --frozen --no-hashes --no-dev --no-emit-project --extra extra_proxy | grep ^psycopg
    psycopg==3.3.3
    
  2. In the Wolfi container: apk add bash openssl tzdata nodejs python-3.13 libsndfile libevent libpq-18 && pip install psycopg==3.3.3 && find /v -name 'libcrypto*' -o -name 'libssl*' | wc -l && ls /usr/lib/libpq.so*
    0
    /usr/lib/libpq.so.5
    /usr/lib/libpq.so.5.18
    
  3. Same container, the exact catalog query the proxy runs at boot:
    impl python libpq 180006
    partitioned (1,)
    
  4. Real proxy from this tip on PSYCOPG_IMPL=python, unpartitioned database: curl -s http://127.0.0.1:4384/health/readiness
    {"status":"healthy","db":"connected"}
    
    and the proxy log carries no psycopg is not installed warning
  5. Real proxy from this tip on PSYCOPG_IMPL=python, partitioned database, --use_prisma_db_push: exits non-zero with LiteLLM_SpendLogs is a partitioned table and pg_partitioned_table still lists the table afterwards

Audit (deterministic tests/integration, no providers, no mocks)

Rig: real Postgres and Redis, two-worker proxy per leg, scripted upstream from tests/integration/_support/upstream.py. Base leg 09ebb28473e6e9e09c80ce2f822b88d8bc24f2e4 on port 4383 (db litaudit_psycopg_base), head leg 36627a61a366cbb1ad56624b98f815a50e5c131f on port 4384 (db litaudit_psycopg_head), run ids base run_3 (merge base unchanged), head run_9 and run_10. uv run --no-sync python tests/integration/run.py database --seed 4106601 --order-seed 7

cell node base head
locked extra_proxy has psycopg, no psycopg-binary, all six image runtime stages (Dockerfile, database, non_root, backend, gateway, migrations) install libpq tests/integration/database/test_spend_logs_partition_driver.py::test_proxy_image_extra_ships_psycopg_without_the_binary_wheel_and_uses_the_image_libpq FAIL (psycopg-binary in export) PASS
pure Python driver, partitioned LiteLLM_SpendLogs, db push refuses and leaves the table alone tests/integration/database/test_spend_logs_partition_driver.py::test_pure_python_psycopg_detects_partitioned_spend_logs_and_refuses_db_push PASS PASS
pure Python driver, unpartitioned db, proxy boots, /health/readiness db connected tests/integration/database/test_spend_logs_partition_driver.py::test_pure_python_psycopg_lets_an_unpartitioned_proxy_boot_and_serve PASS PASS
existing database group (4 nodes) tests/integration/database/ PASS PASS

Head selection ran twice with identical execution.json (7 collected, 7 passed, 0 skipped, hypothesis seed 4106601, order seed 7). Chaos not run: the change is a boot-time catalog query and packaging metadata, no request path, queue or callback to interrupt

Mutation: with psycopg-binary restored to extra_proxy (the base leg) the packaging cell fails; with libpq-18 removed from the backend, gateway and migrations runtime stages the packaging cell fails with Dockerfile runtime stage installs no libpq for psycopg; with spend_logs_is_partitioned() forced to return False the partitioned cell fails because db push proceeds against the partitioned table instead of refusing; with the skipped-check warning reverted to the old text without the ImportError, tests/unit/litellm_proxy_extras/test_litellm_proxy_extras_utils.py::TestSpendLogsPartitionDetectionMissingPsycopg::test_missing_libpq_warning_names_the_libpq_error fails

Type

🚄 Infrastructure

Caveats (if any)

Medium

  • psycopg[c] is not used: Wolfi has postgresql-18-dev, but the C build adds a compiler step per image for a single boot-time query, so the pure Python driver is the deliberate choice
  • docker/build_from_pip/Dockerfile.build_from_pip installs litellm[proxy,proxy-runtime] without extra_proxy, so it never had psycopg or the bundle; unchanged here

Low

  • Missing libpq outside the images still fails open (partition check skipped with a warning naming the libpq error), the same fail-open the missing psycopg case had before this PR; the images ship libpq so this only affects bare pip installs of extra_proxy on a host without libpq

  • The dev-only utils group still pins psycopg-binary for local pytest without a system libpq; it is never installed into an image

  • PSYCOPG_IMPL is unset in the images; psycopg picks the C extension when present and otherwise the pure Python driver, which is what ships now

Link to Devin session: https://app.devin.ai/sessions/5cae45b6407447e0adfee8a5b8e0283a
Open in Devin Desktop: https://app.devin.ai/desktop/session/5cae45b6407447e0adfee8a5b8e0283a?variant=devin
Requested by: @yucheng-berri

yucheng-berri and others added 4 commits September 24, 2026 07:59
…mage libpq

psycopg-binary bundles its own OpenSSL 1.1.1k, which is EOL and lands in every
proxy image. The only caller, ProxyExtrasDBManager.spend_logs_is_partitioned(),
runs one catalog query at boot, so pure Python psycopg over the Wolfi libpq-18
package is enough. Integration tests pin the locked extra and the runtime apk
list, and boot the proxy on the pure Python driver against a partitioned and an
unpartitioned LiteLLM_SpendLogs

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@greptile-apps

greptile-apps Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no outstanding finding or new actionable issue was identified.

Summary

The PR removes the bundled psycopg binary wheel from extra_proxy, supplies system libpq in proxy runtime images, and adds tests and CI setup for the pure-Python driver. Since the previous review, it extends libpq installation and the Dockerfile test to the backend, gateway, and migrations images.

Reviews (5) · Last reviewed commit: "build: ship libpq in the backend, gatewa..."

Comment thread pyproject.toml
Comment thread tests/integration/database/test_spend_logs_partition_driver.py
@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_psycopg_no_binary_wheel (36627a6) with main (3fa6882)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (4584958) during the generation of this report, so 3fa6882 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

…ck is skipped

psycopg imports fine without libpq and only raises when the pq wrapper
is resolved, so the skipped-check warning now carries the ImportError
text and points at the system libpq the images ship

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

…hon psycopg

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread tests/integration/database/test_spend_logs_partition_driver.py
…sycopg

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@mateo-berri

Copy link
Copy Markdown
Contributor

@greptileai

@mateo-berri

Copy link
Copy Markdown
Contributor

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 36627a6. Configure here.

This branch is waiting to be deployed

1 waiting deployment
e2e-changed — 36627a61 Waiting Sep 24, 2026 by devin-ai-integration[bot] via oauth #946
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.

2 participants