Skip to content

fix(docker): keep C toolchain headers out of the runtime image - #43182

Open
bikash-barnwal wants to merge 1 commit into
apache:masterfrom
bikash-barnwal:fix/docker-lean-drop-build-deps
Open

fix(docker): keep C toolchain headers out of the runtime image#43182
bikash-barnwal wants to merge 1 commit into
apache:masterfrom
bikash-barnwal:fix/docker-lean-drop-build-deps

Conversation

@bikash-barnwal

Copy link
Copy Markdown

SUMMARY

The lean runtime image shipped a full set of C development packages. python-common — the shared ancestor of lean, dev, ci and showtime — installed libsasl2-dev, libpq-dev, libldap2-dev and libecpg-dev; apt-mark showmanual inside the built lean image confirms those four are the only manually installed offenders, with libc6-dev, libc-dev-bin, libcrypt-dev, linux-libc-dev, libssl-dev and libldap-dev arriving as their auto-deps. pip-install.sh already purges build-essential, but never touched these.

Each -dev package is replaced with its runtime shared library in python-common, and the headers move to the dev stage, which is where native extensions are actually compiled:

Package Verdict Action
libsasl2-dev build-only (headers for python-ldap) libsasl2-2; -dev moved to dev
libpq-dev build-only (the postgres extra is psycopg2-binary, which bundles libpq) libpq5; -dev moved to dev
libldap2-dev build-only (headers for python-ldap, development.txt only) libldap2; -dev moved to dev
libecpg-dev build-only (no Python driver links ECPG) libecpg6; not re-added
libc6-dev, libc-dev-bin, libcrypt-dev, linux-libc-dev, libssl-dev, libldap-dev build-only, transitive auto-deps of the above dropped automatically
libsasl2-modules-gssapi-mit runtime-required (Kerberos/GSSAPI SASL plugin) kept
curl runtime-required (healthcheck) kept

Four packages from the report — libpython3.11-dev, python3.11-dev, zlib1g-dev, libexpat1-dev — are not present in a current master lean build. The base image builds CPython from source, so Debian's python3.11-dev isn't in the tree at all; those entries most likely come from an older base image or a Chromium/Playwright-enabled build. No action taken rather than a speculative one.

On the npm side: devlop is a genuine production dependency (22 dependents in package-lock.jsonreact-markdown, micromark, mdast-util-*), and preact-devtools does not exist in the lock file at all, almost certainly a scanner mis-attribution of the preact/devtools submodule path. Worth noting for the reporter: node_modules is never copied into a final image — python-common takes only superset/static/assets, service-worker.js and superset/translations from the node stage — so those names can reach an SBOM through bundled JS, not as installed packages.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

--target lean, built locally on amd64:

before after
-dev/dev-bin packages 10 0
total packages 126 114
image size 1.21 GB 1.14 GB

No gcc, cc, make or ld in either. libpq5, libldap2, libsasl2-2, libsasl2-modules-gssapi-mit, libecpg6, libssl3t64 and zlib1g are all still installed.

TESTING INSTRUCTIONS

docker build --target lean -t superset-lean .
docker run --rm superset-lean bash -lc "dpkg -l | grep -E '\-dev|dev-bin'"   # no output
docker run --rm superset-lean bash -lc "superset version"

Verified locally (Docker 29.6.1, builds used --build-arg DEV_MODE=true to skip webpack, which touches no apt layer):

  • lean runtime: import superset, flask, sqlalchemy and import ssl, zlib, sqlite3 all fine; superset version prints, exercising the full app import path.
  • ci target builds; psycopg2 2.9.12 and duckdb 1.5.5 import, and a real duckdb:///:memory: SQLAlchemy query returns.
  • dev target builds; ldap 3.4.7, MySQLdb, psycopg2 and superset all import — so python-ldap and mysqlclient still compile against the headers in their new location.

Not verified: linux/arm64 (only the local amd64 platform was built); a full DEV_MODE=false frontend build, so the emitted static/assets were not scanned for devlop/preact strings — that conclusion rests on lock-file dependency flags and the COPY --from=superset-node scope. The showtime target wasn't built, but it is lean + .[duckdb], a strict subset of the ci target that was.

One honest side effect: installing libssl-dev used to incidentally upgrade libssl3t64 from the base image's 3.5.4 to 3.5.6. Without it the image keeps the pinned base image's 3.5.4. That is the ordinary consequence of not pulling in extra packages and resolves whenever PY_VER is bumped, but a scanner diffing before/after will see that one version move backwards.

ADDITIONAL INFORMATION

🤖 Generated with Claude Code

The `python-common` stage, which every final image (`lean`, `dev`, `ci`,
`showtime`) is built from, installed `libsasl2-dev`, `libpq-dev`,
`libecpg-dev` and `libldap2-dev`. Those `-dev` packages exist only to
provide C headers and static archives for compiling native Python
extensions, and they transitively pull a full C toolchain into every
final image: `libc6-dev`, `libc-dev-bin`, `libcrypt-dev`, `linux-libc-dev`,
`libssl-dev` and `libldap-dev`. None of them are ever removed, so a
production `lean` image shipped ten development packages it cannot use.

Each `-dev` package is replaced with the runtime shared library it
depends on, so no library that anything actually links against is lost:

  libsasl2-dev  -> libsasl2-2   (Cyrus SASL runtime, also needed by
                                 libsasl2-modules-gssapi-mit)
  libpq-dev     -> libpq5       (PostgreSQL C client library)
  libecpg-dev   -> libecpg6     (ECPG runtime library)
  libldap2-dev  -> libldap2     (OpenLDAP runtime libraries)

All four runtime packages were already present in the image as
dependencies of the `-dev` packages, so this change is a strict
subset removal.

Nothing in `requirements/base.txt` (the `lean` dependency set) links
against these libraries, and the `postgres` extra used by `ci` and
`showtime` is `psycopg2-binary`, which bundles its own libpq. The
headers are only needed to build `python-ldap` and `mysqlclient` from
`requirements/development.txt`, so `libsasl2-dev`, `libldap2-dev` and
`libpq-dev` move to the `dev` stage next to the existing
`default-libmysqlclient-dev`.

`--no-install-recommends` hygiene is unchanged: installs still go
through `docker/apt-install.sh`.

No change is warranted for the `devlop` and `preact-devtools` npm names
in the reported SBOM. `node_modules` is never copied into a final
image - only `superset/static/assets` and `superset/translations` come
from the node stage. `devlop` is a production transitive dependency of
`react-markdown`/`micromark` (22 dependents in `package-lock.json`, none
marked `dev`), and no `preact-devtools` package exists in the lock file
at all; `preact` itself is a production dependency of
`@deck.gl/widgets`. Removing either would break markdown rendering and
deck.gl widgets.

Verified by building the `lean`, `ci` and `dev` targets locally.
`dpkg -l` in the resulting `lean` image lists no `-dev` package and no
compiler, all runtime libraries above are still installed, `superset
version` runs, and `psycopg2`/`duckdb` (`ci`) and
`python-ldap`/`mysqlclient`/`psycopg2` (`dev`) still import.

Fixes apache#43002

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added infra:container Infra container and K8s install:docker Installation - docker container labels Aug 14, 2026
@bito-code-review

bito-code-review Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Code Review Agent Run #23a8b7

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: 52f9ec5..52f9ec5
    • Dockerfile
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Comment thread Dockerfile
libldap2-dev
libpq5 \
libecpg6 \
libldap2

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.

Suggestion: The Debian trixie runtime package is versioned libldap-2.6-0, not libldap2. Since apt-install.sh passes package names directly to apt-get install without fallback, this causes the python-common stage and every descendant image to fail during construction. Replace it with the runtime package name provided by the selected Debian release. [api mismatch]

Severity Level: Critical 🚨
-`python-common` cannot build on Debian trixie.
- ❌ Lean and development images cannot be produced.
- ❌ Docker-based deployment and CI builds fail.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** Dockerfile
**Line:** 207:207
**Comment:**
	*Api Mismatch: The Debian trixie runtime package is versioned `libldap-2.6-0`, not `libldap2`. Since `apt-install.sh` passes package names directly to `apt-get install` without fallback, this causes the `python-common` stage and every descendant image to fail during construction. Replace it with the runtime package name provided by the selected Debian release.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@bito-code-review

Copy link
Copy Markdown
Contributor

The flagged issue is correct. The package libldap2 is not available in Debian trixie; the correct runtime package is libldap-2.6-0. Using the incorrect name causes the apt-get install command to fail, blocking the build.

To resolve this, update the Dockerfile to use the correct package name for the Debian release being used. If you are targeting Debian trixie, replace libldap2 with libldap-2.6-0 in the apt-install.sh command.

I have checked the available PR comments, and there are no other comments to address. Would you like me to implement this fix for you?

Dockerfile

RUN /app/docker/apt-install.sh \
      curl \
      libsasl2-2 \
      libsasl2-modules-gssapi-mit \
      libpq5 \
      libecpg6 \
      libldap-2.6-0

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

Labels

infra:container Infra container and K8s install:docker Installation - docker container size/S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runtime container image contains development packages that may not be required for production deployment

2 participants