diff --git a/Dockerfile b/Dockerfile index 3fd7935..d080262 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,24 +12,27 @@ ARG MILLPOND_VERSION=0.0.0.dev0 ENV SETUPTOOLS_SCM_PRETEND_VERSION=$MILLPOND_VERSION RUN uv sync --frozen --no-dev --extra msk-iam -# Install DuckDB CLI from the upstream GitHub release. duckdb-cli is a single +# Install DuckDB CLI from the PostHog GitHub release. duckdb-cli is a single # static binary, so we avoid `uv tool install` here: that path installs a full # Python venv just to PATH a self-contained C++ binary, and its default install # location (/root/.local, mode 700 on python:3.12-slim) is unreachable by the -# non-root `millpond` runtime user. Pin the version from pyproject.toml so the -# CLI tracks the duckdb Python package. +# non-root `millpond` runtime user. # # TARGETARCH is set by buildx for each platform in the build matrix # (linux/amd64 → amd64, linux/arm64 → arm64). DuckDB names its release # assets with the same suffix, so this drops in directly. -j on unzip # extracts only the `duckdb` binary; the release zip also ships a LICENSE # we don't want polluting /usr/local/bin. +# PostHog build of the same DuckDB version: carries the CVE-2026-111497 fix for +# the vendored Brotli decoder (upstream 1.5.5 still ships the pre-fix decoder, so +# a crafted brotli stream can corrupt its parquet reads). Keep in step with the +# wheel URLs in pyproject.toml's [tool.uv.sources]. +ARG DUCKDB_RELEASE=v1.5.5-posthog.6 ARG TARGETARCH RUN test -n "$TARGETARCH" \ && case "$TARGETARCH" in amd64|arm64) ;; *) echo "unsupported TARGETARCH: $TARGETARCH" >&2; exit 1 ;; esac \ - && V=$(python -c "import tomllib; d=tomllib.load(open('pyproject.toml','rb'))['project']['dependencies']; print(next(x.split('==')[1] for x in d if x.startswith('duckdb==')))") \ && apt-get update && apt-get install -y --no-install-recommends curl unzip \ - && curl -fsSL "https://github.com/duckdb/duckdb/releases/download/v${V}/duckdb_cli-linux-${TARGETARCH}.zip" -o /tmp/duckdb.zip \ + && curl -fsSL "https://github.com/PostHog/duckdb/releases/download/${DUCKDB_RELEASE}/duckdb_cli-linux-${TARGETARCH}.zip" -o /tmp/duckdb.zip \ && unzip -j -d /usr/local/bin /tmp/duckdb.zip duckdb \ && chmod 0755 /usr/local/bin/duckdb \ && rm /tmp/duckdb.zip \ diff --git a/pyproject.toml b/pyproject.toml index 0f2d655..fcd1f21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -157,3 +157,21 @@ constraint-dependencies = [ "pygments>=2.20.0", "requests>=2.33.0", ] + +[[tool.uv.index]] +name = "pypi" +url = "https://pypi.org/simple" +default = true + +[tool.uv.sources] +# DuckDB's vendored Brotli decoder is affected by CVE-2026-111497 (malformed +# streams corrupt the decoder's own state; the fix makes DecodeBlockTypeAndLength +# return an error instead of conflating it with needs-more-input). Upstream PyPI +# duckdb 1.5.5 still ships the vulnerable decoder, so take the PostHog build of +# the same version for the platforms this image ships. macOS/Windows developers +# keep resolving duckdb from PyPI via the fallback entry below. +duckdb = [ + { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_x86_64.whl", marker = "sys_platform == 'linux' and platform_machine == 'x86_64'" }, + { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_aarch64.whl", marker = "sys_platform == 'linux' and platform_machine == 'aarch64'" }, + { index = "pypi", marker = "(platform_machine != 'aarch64' and platform_machine not in 'x86_64,aarch64') or sys_platform != 'linux'" }, +] diff --git a/uv.lock b/uv.lock index fbebfaf..7d8c71b 100644 --- a/uv.lock +++ b/uv.lock @@ -1,14 +1,21 @@ version = 1 -revision = 5 +revision = 3 requires-python = ">=3.12" +resolution-markers = [ + "platform_machine == 'x86_64' and platform_machine not in 'x86_64,aarch64' and sys_platform == 'linux'", + "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and platform_machine not in 'x86_64,aarch64') or sys_platform != 'linux'", + "platform_machine != 'aarch64' and platform_machine != 'x86_64' and platform_machine in 'x86_64,aarch64' and sys_platform == 'linux'", + "platform_machine == 'x86_64' and platform_machine in 'x86_64,aarch64' and sys_platform == 'linux'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", +] [options] exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. exclude-newer-span = "P7D" [options.exclude-newer-package] -certifi = { timestamp = "0001-01-01T00:00:00Z", span = "P1D" } pyhoglake = "2026-10-23T04:00:00Z" +certifi = { timestamp = "0001-01-01T00:00:00Z", span = "P1D" } [manifest] constraints = [ @@ -215,6 +222,10 @@ wheels = [ name = "duckdb" version = "1.5.5" source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "(platform_machine != 'aarch64' and platform_machine != 'x86_64' and platform_machine not in 'x86_64,aarch64') or sys_platform != 'linux'", + "platform_machine != 'aarch64' and platform_machine != 'x86_64' and platform_machine in 'x86_64,aarch64' and sys_platform == 'linux'", +] sdist = { url = "https://files.pythonhosted.org/packages/7d/19/e57151753576373c6696a12022648546cca6038e8833fda2908ee2342d9b/duckdb-1.5.5.tar.gz", hash = "sha256:72f33ee57ca7595b23957671a2cc7f7fe2be0ecc2d68f63abedcfcaa3a5c1238", size = 18066741, upload-time = "2026-07-22T10:55:17.819Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d6/40/2e05d324400fdaa5656c9f48d6298da421cb034d85e509fa0e6e325cf04b/duckdb-1.5.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d4dd65f8941a604b947e0b9b4b4f7165988e29a23ec0b69b4038520956d9933e", size = 32753858, upload-time = "2026-07-22T10:54:05.514Z" }, @@ -240,6 +251,51 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/2c/95d9216b79e9273689d7ebce125a54503ed0c9bd7da931f0265888e99779/duckdb-1.5.5-cp314-cp314-win_arm64.whl", hash = "sha256:63e48d4b74b15aeacd688976432a7225163df8c226eddeb8536bba2d4d4ff433", size = 14470180, upload-time = "2026-07-22T10:55:14.445Z" }, ] +[[package]] +name = "duckdb" +version = "1.5.5" +source = { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_aarch64.whl" } +resolution-markers = [ + "platform_machine == 'aarch64' and sys_platform == 'linux'", +] +wheels = [ + { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_aarch64.whl", hash = "sha256:ae78b58ec49b4f5e9c25d37c37d787b47a5eb9bf2656a74b6634edadc8158df9" }, +] + +[package.metadata] +requires-dist = [ + { name = "adbc-driver-manager", marker = "extra == 'all'" }, + { name = "fsspec", marker = "extra == 'all'" }, + { name = "ipython", marker = "extra == 'all'" }, + { name = "numpy", marker = "extra == 'all'" }, + { name = "pandas", marker = "extra == 'all'" }, + { name = "pyarrow", marker = "extra == 'all'" }, +] +provides-extras = ["all"] + +[[package]] +name = "duckdb" +version = "1.5.5" +source = { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_x86_64.whl" } +resolution-markers = [ + "platform_machine == 'x86_64' and platform_machine not in 'x86_64,aarch64' and sys_platform == 'linux'", + "platform_machine == 'x86_64' and platform_machine in 'x86_64,aarch64' and sys_platform == 'linux'", +] +wheels = [ + { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_x86_64.whl", hash = "sha256:514a61748d384336147768adec6efaa9e2d128b458e24f9bcca178b7cd1c8bc3" }, +] + +[package.metadata] +requires-dist = [ + { name = "adbc-driver-manager", marker = "extra == 'all'" }, + { name = "fsspec", marker = "extra == 'all'" }, + { name = "ipython", marker = "extra == 'all'" }, + { name = "numpy", marker = "extra == 'all'" }, + { name = "pandas", marker = "extra == 'all'" }, + { name = "pyarrow", marker = "extra == 'all'" }, +] +provides-extras = ["all"] + [[package]] name = "googleapis-common-protos" version = "1.75.0" @@ -321,7 +377,9 @@ name = "millpond" source = { editable = "." } dependencies = [ { name = "confluent-kafka" }, - { name = "duckdb" }, + { name = "duckdb", version = "1.5.5", source = { registry = "https://pypi.org/simple" }, marker = "(platform_machine != 'aarch64' and platform_machine != 'x86_64') or sys_platform != 'linux'" }, + { name = "duckdb", version = "1.5.5", source = { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_aarch64.whl" }, marker = "platform_machine == 'aarch64' and sys_platform == 'linux'" }, + { name = "duckdb", version = "1.5.5", source = { url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_x86_64.whl" }, marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "opentelemetry-exporter-otlp-proto-http" }, { name = "opentelemetry-instrumentation-logging" }, { name = "opentelemetry-sdk" }, @@ -350,7 +408,10 @@ dev = [ requires-dist = [ { name = "aws-msk-iam-sasl-signer-python", marker = "extra == 'msk-iam'", specifier = ">=1.0.0" }, { name = "confluent-kafka", specifier = ">=2.6" }, - { name = "duckdb", specifier = "==1.5.5" }, + { name = "duckdb", marker = "(platform_machine != 'aarch64' and platform_machine not in 'x86_64,aarch64') or sys_platform != 'linux'", specifier = "==1.5.5", index = "https://pypi.org/simple" }, + { name = "duckdb", marker = "platform_machine == 'aarch64' and sys_platform == 'linux'", url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_aarch64.whl" }, + { name = "duckdb", marker = "platform_machine != 'aarch64' and platform_machine != 'x86_64' and platform_machine in 'x86_64,aarch64' and sys_platform == 'linux'", specifier = "==1.5.5" }, + { name = "duckdb", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'", url = "https://github.com/PostHog/duckdb/releases/download/v1.5.5-posthog.6/duckdb-1.5.5-cp312-cp312-linux_x86_64.whl" }, { name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.30" }, { name = "opentelemetry-instrumentation-logging", specifier = ">=0.50b0,<0.64" }, { name = "opentelemetry-sdk", specifier = ">=1.30" },