From 9e598008b5ae9ca4bbef418026f4340c38aa55bb Mon Sep 17 00:00:00 2001 From: rtemperini <29879569+rtemperini@users.noreply.github.com> Date: Thu, 22 Oct 2026 14:23:43 +0200 Subject: [PATCH 1/3] fix(security): update runtime certificate trust in v0.10.x Signed-off-by: rtemperini <29879569+rtemperini@users.noreply.github.com> --- .devcontainer/devcontainer.json | 4 +- .github/workflows/image-scan.yaml | 16 +++ .github/workflows/tag.yaml | 2 +- Makefile | 4 +- docker/skills-init/Dockerfile | 2 +- go/Dockerfile | 2 +- go/Dockerfile.full | 8 +- python/Dockerfile | 13 +- python/Dockerfile.full | 5 +- python/packages/kagent-adk/pyproject.toml | 2 +- python/packages/kagent-core/pyproject.toml | 1 + python/pyproject.toml | 1 + python/samples/crewai/poem_flow/Dockerfile | 5 +- .../samples/crewai/research-crew/Dockerfile | 5 +- python/samples/langgraph/currency/Dockerfile | 5 +- .../samples/langgraph/hitl-tools/Dockerfile | 5 +- python/samples/langgraph/kebab/Dockerfile | 5 +- python/samples/openai/basic_agent/Dockerfile | 4 +- python/uv.lock | 124 +++++++++--------- scripts/check_python_image_trust.py | 96 ++++++++++++++ ui/Dockerfile | 10 +- 21 files changed, 228 insertions(+), 91 deletions(-) create mode 100644 scripts/check_python_image_trust.py diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3bbb647d6b..2b74027dcb 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,8 +4,8 @@ "dockerfile": "Dockerfile", "args": { "TOOLS_GO_VERSION": "1.26.10", - "TOOLS_NODE_VERSION": "24.13.0", - "TOOLS_UV_VERSION": "0.10.4", + "TOOLS_NODE_VERSION": "24.22.1", + "TOOLS_UV_VERSION": "0.13.5", "TOOLS_K9S_VERSION": "0.50.4", "TOOLS_KIND_VERSION": "0.27.0", "TOOLS_ISTIO_VERSION": "1.26.0", diff --git a/.github/workflows/image-scan.yaml b/.github/workflows/image-scan.yaml index 097b02c917..15357a258c 100644 --- a/.github/workflows/image-scan.yaml +++ b/.github/workflows/image-scan.yaml @@ -30,6 +30,12 @@ jobs: fail-fast: false matrix: include: + - build_target: kagent-adk + image_name: kagent-adk + tag_suffix: "" + - build_target: kagent-adk-full + image_name: kagent-adk + tag_suffix: "-full" - build_target: controller image_name: controller tag_suffix: "" @@ -71,6 +77,8 @@ jobs: env: DOCKER_BUILDER: "docker buildx build" DOCKER_BUILD_ARGS: >- + --pull + --no-cache --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-${{ matrix.build_target }} --cache-from=type=gha --cache-to=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-${{ matrix.build_target }},mode=max @@ -80,6 +88,14 @@ jobs: export VERSION=${{ steps.vars.outputs.version }} make build-${{ matrix.build_target }} working-directory: ./ + - name: Check Python certificate trust + if: startsWith(matrix.build_target, 'kagent-adk') + env: + IMAGE: localhost:5001/kagent-dev/kagent/${{ matrix.image_name }}:${{ steps.vars.outputs.version }}${{ matrix.tag_suffix }} + run: | + docker run --rm --entrypoint /.kagent/.venv/bin/python \ + -v "$PWD/scripts/check_python_image_trust.py:/tmp/check_python_image_trust.py:ro" \ + "$IMAGE" /tmp/check_python_image_trust.py - name: Image vulnerability scanner uses: aquasecurity/trivy-action@v0.36.0 with: diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index a7b0727eb2..d2400546e3 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -52,7 +52,7 @@ jobs: use: 'true' - name: 'Build Images' env: - DOCKER_BUILD_ARGS: "--push --platform linux/amd64,linux/arm64" + DOCKER_BUILD_ARGS: "--pull --no-cache --push --platform linux/amd64,linux/arm64" DOCKER_BUILDER: "docker buildx build" DOCKER_REGISTRY: "ghcr.io" # prod for releases, local for dev run: | diff --git a/Makefile b/Makefile index f51baa5ac3..24dce3bfce 100644 --- a/Makefile +++ b/Makefile @@ -96,8 +96,8 @@ LDFLAGS := -X github.com/$(DOCKER_REPO)/go/core/internal/version.Version=$(VERSI -X github.com/$(DOCKER_REPO)/go/core/internal/version.BuildDate=$(BUILD_DATE) #tools versions -TOOLS_UV_VERSION ?= 0.10.4 -TOOLS_NODE_VERSION ?= 24 +TOOLS_UV_VERSION ?= 0.13.5 +TOOLS_NODE_VERSION ?= 24.22.1 TOOLS_PYTHON_VERSION ?= 3.13 # build args diff --git a/docker/skills-init/Dockerfile b/docker/skills-init/Dockerfile index 31feebac3a..2962b9ec0c 100644 --- a/docker/skills-init/Dockerfile +++ b/docker/skills-init/Dockerfile @@ -31,7 +31,7 @@ ARG PYTHON_GID=1001 # git is invoked by skills-init via exec.Command with an argv vector — never # through a shell — so the only attack surface here is git itself. OCI fetch # uses the in-process go-containerregistry library, so krane and jq are gone. -RUN apk upgrade --no-cache && apk add --no-cache git openssh-client ca-certificates +RUN apk upgrade --no-cache && apk add --no-cache git openssh-client "ca-certificates>=20261020-r0" COPY --from=builder /skills-init /usr/local/bin/skills-init diff --git a/go/Dockerfile b/go/Dockerfile index 5042c40728..772a544819 100644 --- a/go/Dockerfile +++ b/go/Dockerfile @@ -32,7 +32,7 @@ RUN --mount=type=cache,target=/root/go/pkg/mod,rw \ ### STAGE 2: final image # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/static:nonroot +FROM gcr.io/distroless/static-debian13:nonroot@sha256:d62067879de890a1def9da0e7766b7d20810a5e5555cef8506b752437d7a3e88 ARG TARGETPLATFORM WORKDIR / diff --git a/go/Dockerfile.full b/go/Dockerfile.full index 16507c6ff4..48feff5402 100644 --- a/go/Dockerfile.full +++ b/go/Dockerfile.full @@ -23,12 +23,12 @@ RUN --mount=type=cache,target=/root/go/pkg/mod,rw \ CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -ldflags "$LDFLAGS" -o /app "$BUILD_PACKAGE" # sandbox-runtime produces architecture-independent JavaScript; build it natively to avoid QEMU. -FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest AS srt-builder +FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest@sha256:bc76fa39ddd1482dd56a761b3331e03ba8f0e093ebb525618a56d014b480da88 AS srt-builder ARG TOOLS_PYTHON_VERSION=3.13 RUN --mount=type=cache,target=/var/cache/apk,rw \ apk add --no-cache \ - bash git ca-certificates nodejs npm node-gyp bubblewrap python-${TOOLS_PYTHON_VERSION} libstdc++ + bash git "ca-certificates>=20260909-r3" nodejs npm node-gyp bubblewrap python-${TOOLS_PYTHON_VERSION} libstdc++ # Keep the pinned sandbox-runtime revision, but replace its vulnerable locked package versions. # Both lodash-es and shell-quote are direct dependencies of sandbox-runtime, so pinning them @@ -42,12 +42,12 @@ RUN --mount=type=cache,target=/root/.npm \ npm run build && \ npm prune --omit=dev -FROM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest +FROM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest@sha256:bc76fa39ddd1482dd56a761b3331e03ba8f0e093ebb525618a56d014b480da88 ARG TOOLS_PYTHON_VERSION=3.13 RUN --mount=type=cache,target=/var/cache/apk,rw \ apk add --no-cache \ - bash ca-certificates curl nodejs bubblewrap socat python-${TOOLS_PYTHON_VERSION} ripgrep libstdc++ + bash "ca-certificates>=20260909-r3" curl nodejs bubblewrap socat python-${TOOLS_PYTHON_VERSION} ripgrep libstdc++ RUN addgroup -g 1001 goagent && \ adduser -u 1001 -G goagent -s /bin/bash -D goagent diff --git a/python/Dockerfile b/python/Dockerfile index 0f37cb5819..0271770969 100644 --- a/python/Dockerfile +++ b/python/Dockerfile @@ -1,18 +1,19 @@ ### STAGE 1: uv binary -ARG UV_VERSION=0.12.3 +ARG UV_VERSION=0.13.5 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv-bin ### STAGE 2: builder # Build the uv-managed standalone Python interpreter and the project venv on a full base # (debian-slim, digest-pinnable). Nothing from this stage ships except /python and the venv. -# Digest = multi-arch index resolved via `docker buildx imagetools inspect debian:12-slim`. -FROM debian:13-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd AS builder +# Digest = multi-arch index resolved via `docker buildx imagetools inspect debian:13-slim`. +FROM debian:13-slim@sha256:62bd423aeee912639ca8ee681c2b762cb3e25137e0a92b20be455898a9f034ad AS builder ARG TOOLS_PYTHON_VERSION=3.13 ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 ENV PYTHONOPTIMIZE=2 ENV PYTHONUNBUFFERED=1 +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt # uv configuration: install a managed standalone Python under /python and a copy-mode venv # (no editable installs) so the final image is self-contained with no source tree dependency. @@ -82,15 +83,19 @@ RUN mkdir -p /staging/config # version-numbered tags (only :nonroot/:latest/:debug), so a digest is the only way to pin tighter # than "Debian 12". Tag kept for readability; bump the digest via dependency tooling. # Digest = multi-arch index resolved via `docker buildx imagetools inspect gcr.io/distroless/cc-debian12:nonroot`. -FROM gcr.io/distroless/cc-debian12:nonroot@sha256:fccdbb0a547c14e23fcf4ce8ad62ca5d43b4faae8d22cd292f490fef9946c96e +FROM gcr.io/distroless/cc-debian12:nonroot@sha256:9dac0a79194e45a7da0158a9c6da57b217585af0786db3845d1f0ec1a0dd182f ARG VERSION ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 ENV PYTHONUNBUFFERED=1 +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt ENV PATH="/.kagent/.venv/bin:$PATH" ENV VIRTUAL_ENV=/.kagent/.venv +# Preserve the runtime glibc version while using Debian's updated CA bundle. +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt + # The standalone interpreter and the venv (the venv's python is linked to /python). COPY --from=builder /python /python COPY --from=builder /.kagent/.venv /.kagent/.venv diff --git a/python/Dockerfile.full b/python/Dockerfile.full index 18a178f239..f3d55783a0 100644 --- a/python/Dockerfile.full +++ b/python/Dockerfile.full @@ -6,20 +6,21 @@ # executeCodeBlocks) and for sandboxed BYO agents. ### STAGE 1: uv binary -ARG UV_VERSION=0.12.3 +ARG UV_VERSION=0.13.5 FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv-bin ### STAGE 2: base os + sandbox runtime # node:26-bookworm-slim is a digest-pinnable debian-bookworm base that ships Node 26 (the # sandbox-runtime requires node >= 20; debian's own nodejs package is still on 18). # Digest = multi-arch index resolved via `docker buildx imagetools inspect node:26-bookworm-slim`. -FROM node:26-bookworm-slim@sha256:2d49d876e96237d76de412761cf05dbfe5aee325cc4406a4d41d5824c5bb8beb AS python-os +FROM node:26.12.1-bookworm-slim@sha256:28147155d47dc31abe0a46e0d12b59b2fb3d0a2dcc5dc65fce76a074180b16fe AS python-os ARG TOOLS_PYTHON_VERSION=3.13 ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 ENV PYTHONOPTIMIZE=2 ENV PYTHONUNBUFFERED=1 +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt # Optimize malloc for containerized Python workloads ENV MALLOC_TRIM_THRESHOLD_=262144 diff --git a/python/packages/kagent-adk/pyproject.toml b/python/packages/kagent-adk/pyproject.toml index 5e38e6f57d..058f038bca 100644 --- a/python/packages/kagent-adk/pyproject.toml +++ b/python/packages/kagent-adk/pyproject.toml @@ -35,7 +35,7 @@ dependencies = [ "filelock>=3.20.3", # CVE-2025-68146, CVE-2026-22701: TOCTOU symlink race condition "python-multipart>=0.0.22", # CVE-2026-24486: Arbitrary file write via path traversal "httpx-sse>=0.4.3", # U+2028/U+2029 SSE line terminator fix (0.4.2) + performance regression fix (0.4.3) - "boto3>=1.28.57", + "boto3>=1.43.117", "ollama >=0.3.6", # Ollama SDK "numpy>=2.2.6", ] diff --git a/python/packages/kagent-core/pyproject.toml b/python/packages/kagent-core/pyproject.toml index 004a4769cc..6b49400461 100644 --- a/python/packages/kagent-core/pyproject.toml +++ b/python/packages/kagent-core/pyproject.toml @@ -9,6 +9,7 @@ description = "kagent common library for kagent python packages" readme = "README.md" requires-python = ">=3.11" dependencies = [ + "certifi>=2026.10.19", "a2a-sdk[http-server]>=0.3.26", "opentelemetry-api>=1.38.0,<1.39.0", "opentelemetry-sdk>=1.38.0,<1.39.0", diff --git a/python/pyproject.toml b/python/pyproject.toml index 4bdb894f75..3bfbd19402 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -11,6 +11,7 @@ dev = [ [tool.uv] constraint-dependencies = [ + "uv>=0.13.5", "aiohttp>=3.14.3", "cryptography>=50.0.0", "httplib2>=0.32.0", diff --git a/python/samples/crewai/poem_flow/Dockerfile b/python/samples/crewai/poem_flow/Dockerfile index 64406faeac..042976a017 100644 --- a/python/samples/crewai/poem_flow/Dockerfile +++ b/python/samples/crewai/poem_flow/Dockerfile @@ -3,7 +3,10 @@ ARG DOCKER_REGISTRY=ghcr.io ARG VERSION=latest # substrate's gVisor (ateom) checkpoint/restore segfaults processes linked against trixie's newer glibc # use bookworm to align with the kagent-adk runtime image -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM python:3.13.17-slim-bookworm@sha256:e32be0e55814a08977501ca863271d9bd02443710db8f2afaf8372e2c4508530 +COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /usr/local/bin/ + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/samples/crewai/research-crew/Dockerfile b/python/samples/crewai/research-crew/Dockerfile index 271eead58f..fd5855a22f 100644 --- a/python/samples/crewai/research-crew/Dockerfile +++ b/python/samples/crewai/research-crew/Dockerfile @@ -3,7 +3,10 @@ ARG DOCKER_REGISTRY=ghcr.io ARG VERSION=latest # substrate's gVisor (ateom) checkpoint/restore segfaults processes linked against trixie's newer glibc # use bookworm to align with the kagent-adk runtime image -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM python:3.13.17-slim-bookworm@sha256:e32be0e55814a08977501ca863271d9bd02443710db8f2afaf8372e2c4508530 +COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /usr/local/bin/ + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/samples/langgraph/currency/Dockerfile b/python/samples/langgraph/currency/Dockerfile index 27b98160ec..2f91e9d895 100644 --- a/python/samples/langgraph/currency/Dockerfile +++ b/python/samples/langgraph/currency/Dockerfile @@ -3,7 +3,10 @@ ARG DOCKER_REGISTRY=ghcr.io ARG VERSION=latest # substrate's gVisor (ateom) checkpoint/restore segfaults processes linked against trixie's newer glibc # use bookworm to align with the kagent-adk runtime image -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM python:3.13.17-slim-bookworm@sha256:e32be0e55814a08977501ca863271d9bd02443710db8f2afaf8372e2c4508530 +COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /usr/local/bin/ + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/samples/langgraph/hitl-tools/Dockerfile b/python/samples/langgraph/hitl-tools/Dockerfile index d783b11f46..92fe0bee34 100644 --- a/python/samples/langgraph/hitl-tools/Dockerfile +++ b/python/samples/langgraph/hitl-tools/Dockerfile @@ -3,7 +3,10 @@ ARG DOCKER_REGISTRY=ghcr.io ARG VERSION=latest # substrate's gVisor (ateom) checkpoint/restore segfaults processes linked against trixie's newer glibc # use bookworm to align with the kagent-adk runtime image -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM python:3.13.17-slim-bookworm@sha256:e32be0e55814a08977501ca863271d9bd02443710db8f2afaf8372e2c4508530 +COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /usr/local/bin/ + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/samples/langgraph/kebab/Dockerfile b/python/samples/langgraph/kebab/Dockerfile index 5eecc34f62..725ac57363 100644 --- a/python/samples/langgraph/kebab/Dockerfile +++ b/python/samples/langgraph/kebab/Dockerfile @@ -3,7 +3,10 @@ ARG DOCKER_REGISTRY=ghcr.io ARG VERSION=latest # substrate's gVisor (ateom) checkpoint/restore segfaults processes linked against trixie's newer glibc # use bookworm to align with the kagent-adk runtime image -FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim +FROM python:3.13.17-slim-bookworm@sha256:e32be0e55814a08977501ca863271d9bd02443710db8f2afaf8372e2c4508530 +COPY --from=ghcr.io/astral-sh/uv:0.13.5 /uv /uvx /usr/local/bin/ + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/samples/openai/basic_agent/Dockerfile b/python/samples/openai/basic_agent/Dockerfile index 4f9216593b..af81b7e60f 100644 --- a/python/samples/openai/basic_agent/Dockerfile +++ b/python/samples/openai/basic_agent/Dockerfile @@ -1,5 +1,7 @@ ### STAGE 1: base image -FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim +FROM ghcr.io/astral-sh/uv:0.13.5-python3.13-trixie-slim + +ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt WORKDIR /app diff --git a/python/uv.lock b/python/uv.lock index 5da30a49b0..d7c5ce9e41 100644 --- a/python/uv.lock +++ b/python/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 3 +revision = 5 requires-python = ">=3.11, <3.14" resolution-markers = [ "python_full_version >= '3.13'", @@ -39,6 +39,7 @@ constraints = [ { name = "python-dotenv", specifier = ">=1.2.2" }, { name = "requests", specifier = ">=2.34.2" }, { name = "sqlparse", specifier = ">=0.6.0" }, + { name = "uv", specifier = ">=0.13.5" }, { name = "wheel", specifier = ">=0.46.2" }, ] @@ -518,30 +519,30 @@ wheels = [ [[package]] name = "boto3" -version = "1.43.36" +version = "1.43.117" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/9f/897287e955db0f50b12fd69ef45956e4fd2c7ddb48c736872f7ea2314443/boto3-1.43.36.tar.gz", hash = "sha256:587d7ee92a12e440ad12b0e7f11f3358f0c4d65b19f64726efc94aaf194aff28", size = 112690, upload-time = "2026-06-23T02:47:14.561Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/a7/61f0295f79dfdcebb5aa01f86c614fac7e1294faabbd66259d3609c50539/boto3-1.43.117.tar.gz", hash = "sha256:f3d314908d866b577ee6b74ed432c21e565c4c4dbd640ef3fd5e0da30fa13a98", size = 112677, upload-time = "2026-10-21T19:30:03.849Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/f1/274303f52483ecf199eae6f8d9b6f5951670397ee4d72c06cfd4eb644612/boto3-1.43.36-py3-none-any.whl", hash = "sha256:42942dde254673abcbc9e6e60017c88341a4f49d99d24e1f2e290fb38138c26f", size = 140031, upload-time = "2026-06-23T02:47:13.178Z" }, + { url = "https://files.pythonhosted.org/packages/f3/3b/22b05a545fb95983733d84681364c6b0a36afb0710d832f77732d1fc4c0b/boto3-1.43.117-py3-none-any.whl", hash = "sha256:a5b6cd7e67653987fcf0e212187c16f7b58af2ae192e368f7212ddab7c05b25d", size = 140043, upload-time = "2026-10-21T19:30:02.114Z" }, ] [[package]] name = "botocore" -version = "1.43.36" +version = "1.43.117" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/37/da9e7f6ca73ac73afd7f0bb7f238aa5daba35c081e98d7f48a7c399599c0/botocore-1.43.36.tar.gz", hash = "sha256:4cae47d1b2d426316b85a0087d9e69e048f13bc003b5177d74639fe9dfd28205", size = 15625488, upload-time = "2026-06-23T02:47:03.192Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/a0/d0a5c44ad6a01f195681ddcb4ce203f06c712811daf1d15f8f8785e8a9f8/botocore-1.43.117.tar.gz", hash = "sha256:71993702832cc37c2495048b9945f2929d306fccb3fb767e9964e437e637fa6c", size = 16366888, upload-time = "2026-10-21T19:29:59.274Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/19/934f81592527a3f7f9b943c893e334c721a4644948642bc33885d584e9ec/botocore-1.43.36-py3-none-any.whl", hash = "sha256:3c65fdc39ed01d8dfde1e961b34038aed03c459f8ddf80717a12ac006475e49d", size = 15313630, upload-time = "2026-06-23T02:46:59.327Z" }, + { url = "https://files.pythonhosted.org/packages/10/94/050e35c9febf6dd2fce4a76be587ae4a323964865700467d9d7b082f7133/botocore-1.43.117-py3-none-any.whl", hash = "sha256:5920ef9b3002e1361846549078549d9154a6e0004c22853c01ce7b279d05d495", size = 16061765, upload-time = "2026-10-21T19:29:56.001Z" }, ] [[package]] @@ -560,11 +561,11 @@ wheels = [ [[package]] name = "certifi" -version = "2025.8.3" +version = "2026.10.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/1436c50cc46699de0230fbaacc1d1de7bfec413176099949e9d5112e88f2/certifi-2026.10.19.tar.gz", hash = "sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae", size = 137598, upload-time = "2026-10-20T02:24:16.604Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, + { url = "https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl", hash = "sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b", size = 136464, upload-time = "2026-10-20T02:24:15.072Z" }, ] [[package]] @@ -1157,11 +1158,11 @@ resolution-markers = [ "python_full_version < '3.13'", ] dependencies = [ - { name = "google-auth", marker = "python_full_version < '3.13'" }, - { name = "googleapis-common-protos", marker = "python_full_version < '3.13'" }, - { name = "proto-plus", marker = "python_full_version < '3.13'" }, - { name = "protobuf", marker = "python_full_version < '3.13'" }, - { name = "requests", marker = "python_full_version < '3.13'" }, + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dc/21/e9d043e88222317afdbdb567165fdbc3b0aad90064c7e0c9eb0ad9955ad8/google_api_core-2.25.1.tar.gz", hash = "sha256:d2aaa0b13c78c61cb3f4282c464c046e45fbd75755683c9c525e6e8f7ed0a5e8", size = 165443, upload-time = "2025-06-12T20:52:20.439Z" } wheels = [ @@ -1170,8 +1171,8 @@ wheels = [ [package.optional-dependencies] grpc = [ - { name = "grpcio", marker = "python_full_version < '3.13'" }, - { name = "grpcio-status", marker = "python_full_version < '3.13'" }, + { name = "grpcio" }, + { name = "grpcio-status" }, ] [[package]] @@ -1182,11 +1183,11 @@ resolution-markers = [ "python_full_version >= '3.13'", ] dependencies = [ - { name = "google-auth", marker = "python_full_version >= '3.13'" }, - { name = "googleapis-common-protos", marker = "python_full_version >= '3.13'" }, - { name = "proto-plus", marker = "python_full_version >= '3.13'" }, - { name = "protobuf", marker = "python_full_version >= '3.13'" }, - { name = "requests", marker = "python_full_version >= '3.13'" }, + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/7c/9be3903e3d45415e8ca493c75f8990a0f6f579d168015d44c379350d0ab0/google_api_core-2.34.0.tar.gz", hash = "sha256:98a779fe72de956eb1c9c2f47ff4c4432a668ece1a002ec38bed07ec2698ae59", size = 187953, upload-time = "2026-08-06T06:23:58.128Z" } wheels = [ @@ -1195,8 +1196,8 @@ wheels = [ [package.optional-dependencies] grpc = [ - { name = "grpcio", marker = "python_full_version >= '3.13'" }, - { name = "grpcio-status", marker = "python_full_version >= '3.13'" }, + { name = "grpcio" }, + { name = "grpcio-status" }, ] [[package]] @@ -1557,12 +1558,12 @@ resolution-markers = [ "python_full_version < '3.13'", ] dependencies = [ - { name = "google-api-core", version = "2.25.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" }, - { name = "google-auth", marker = "python_full_version < '3.13'" }, - { name = "google-cloud-core", marker = "python_full_version < '3.13'" }, - { name = "google-crc32c", marker = "python_full_version < '3.13'" }, - { name = "google-resumable-media", marker = "python_full_version < '3.13'" }, - { name = "requests", marker = "python_full_version < '3.13'" }, + { name = "google-api-core", version = "2.25.1", source = { registry = "https://pypi.org/simple" } }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/36/76/4d965702e96bb67976e755bed9828fa50306dca003dbee08b67f41dd265e/google_cloud_storage-2.19.0.tar.gz", hash = "sha256:cd05e9e7191ba6cb68934d8eb76054d9be4562aa89dbc4236feee4d7d51342b2", size = 5535488, upload-time = "2024-12-05T01:35:06.49Z" } wheels = [ @@ -1577,12 +1578,12 @@ resolution-markers = [ "python_full_version >= '3.13'", ] dependencies = [ - { name = "google-api-core", version = "2.34.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" }, - { name = "google-auth", marker = "python_full_version >= '3.13'" }, - { name = "google-cloud-core", marker = "python_full_version >= '3.13'" }, - { name = "google-crc32c", marker = "python_full_version >= '3.13'" }, - { name = "google-resumable-media", marker = "python_full_version >= '3.13'" }, - { name = "requests", marker = "python_full_version >= '3.13'" }, + { name = "google-api-core", version = "2.34.0", source = { registry = "https://pypi.org/simple" } }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/7e/73bb7512df1d1aad6ce3f9aed847cd40e0cd400ba4a85d86ab8eb412e9cc/google_cloud_storage-3.13.1.tar.gz", hash = "sha256:a80bf8cac2794808aa61c50c5f769ecbbe2d10331bacd0d69d30e59b14b346b2", size = 17341051, upload-time = "2026-08-06T06:24:42.229Z" } wheels = [ @@ -1700,7 +1701,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fc/2e/d4fcb2978f826358b673f779f78fa8a32ee37df11920dc2bb5589cbeecef/greenlet-3.2.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822", size = 270219, upload-time = "2025-06-05T16:10:10.414Z" }, { url = "https://files.pythonhosted.org/packages/16/24/929f853e0202130e4fe163bc1d05a671ce8dcd604f790e14896adac43a52/greenlet-3.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83", size = 630383, upload-time = "2025-06-05T16:38:51.785Z" }, { url = "https://files.pythonhosted.org/packages/d1/b2/0320715eb61ae70c25ceca2f1d5ae620477d246692d9cc284c13242ec31c/greenlet-3.2.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf", size = 642422, upload-time = "2025-06-05T16:41:35.259Z" }, - { url = "https://files.pythonhosted.org/packages/bd/49/445fd1a210f4747fedf77615d941444349c6a3a4a1135bba9701337cd966/greenlet-3.2.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b", size = 638375, upload-time = "2025-06-05T16:48:18.235Z" }, { url = "https://files.pythonhosted.org/packages/7e/c8/ca19760cf6eae75fa8dc32b487e963d863b3ee04a7637da77b616703bc37/greenlet-3.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147", size = 637627, upload-time = "2025-06-05T16:13:02.858Z" }, { url = "https://files.pythonhosted.org/packages/65/89/77acf9e3da38e9bcfca881e43b02ed467c1dedc387021fc4d9bd9928afb8/greenlet-3.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5", size = 585502, upload-time = "2025-06-05T16:12:49.642Z" }, { url = "https://files.pythonhosted.org/packages/97/c6/ae244d7c95b23b7130136e07a9cc5aadd60d59b5951180dc7dc7e8edaba7/greenlet-3.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc", size = 1114498, upload-time = "2025-06-05T16:36:46.598Z" }, @@ -1709,7 +1709,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/94/ad0d435f7c48debe960c53b8f60fb41c2026b1d0fa4a99a1cb17c3461e09/greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d", size = 271992, upload-time = "2025-06-05T16:11:23.467Z" }, { url = "https://files.pythonhosted.org/packages/93/5d/7c27cf4d003d6e77749d299c7c8f5fd50b4f251647b5c2e97e1f20da0ab5/greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b", size = 638820, upload-time = "2025-06-05T16:38:52.882Z" }, { url = "https://files.pythonhosted.org/packages/c6/7e/807e1e9be07a125bb4c169144937910bf59b9d2f6d931578e57f0bce0ae2/greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d", size = 653046, upload-time = "2025-06-05T16:41:36.343Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ab/158c1a4ea1068bdbc78dba5a3de57e4c7aeb4e7fa034320ea94c688bfb61/greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264", size = 647701, upload-time = "2025-06-05T16:48:19.604Z" }, { url = "https://files.pythonhosted.org/packages/cc/0d/93729068259b550d6a0288da4ff72b86ed05626eaf1eb7c0d3466a2571de/greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688", size = 649747, upload-time = "2025-06-05T16:13:04.628Z" }, { url = "https://files.pythonhosted.org/packages/f6/f6/c82ac1851c60851302d8581680573245c8fc300253fc1ff741ae74a6c24d/greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb", size = 605461, upload-time = "2025-06-05T16:12:50.792Z" }, { url = "https://files.pythonhosted.org/packages/98/82/d022cf25ca39cf1200650fc58c52af32c90f80479c25d1cbf57980ec3065/greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c", size = 1121190, upload-time = "2025-06-05T16:36:48.59Z" }, @@ -1718,7 +1717,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/cf/f5c0b23309070ae93de75c90d29300751a5aacefc0a3ed1b1d8edb28f08b/greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad", size = 270732, upload-time = "2025-06-05T16:10:08.26Z" }, { url = "https://files.pythonhosted.org/packages/48/ae/91a957ba60482d3fecf9be49bc3948f341d706b52ddb9d83a70d42abd498/greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef", size = 639033, upload-time = "2025-06-05T16:38:53.983Z" }, { url = "https://files.pythonhosted.org/packages/6f/df/20ffa66dd5a7a7beffa6451bdb7400d66251374ab40b99981478c69a67a8/greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3", size = 652999, upload-time = "2025-06-05T16:41:37.89Z" }, - { url = "https://files.pythonhosted.org/packages/51/b4/ebb2c8cb41e521f1d72bf0465f2f9a2fd803f674a88db228887e6847077e/greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95", size = 647368, upload-time = "2025-06-05T16:48:21.467Z" }, { url = "https://files.pythonhosted.org/packages/8e/6a/1e1b5aa10dced4ae876a322155705257748108b7fd2e4fae3f2a091fe81a/greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb", size = 650037, upload-time = "2025-06-05T16:13:06.402Z" }, { url = "https://files.pythonhosted.org/packages/26/f2/ad51331a157c7015c675702e2d5230c243695c788f8f75feba1af32b3617/greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b", size = 608402, upload-time = "2025-06-05T16:12:51.91Z" }, { url = "https://files.pythonhosted.org/packages/26/bc/862bd2083e6b3aff23300900a956f4ea9a4059de337f5c8734346b9b34fc/greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0", size = 1119577, upload-time = "2025-06-05T16:36:49.787Z" }, @@ -2252,7 +2250,7 @@ requires-dist = [ { name = "aiofiles", specifier = ">=24.1.0" }, { name = "anthropic", extras = ["vertex"], specifier = ">=0.120.0" }, { name = "anyio", specifier = ">=4.14.2" }, - { name = "boto3", specifier = ">=1.28.57" }, + { name = "boto3", specifier = ">=1.43.117" }, { name = "fastapi", specifier = ">=0.115.1" }, { name = "filelock", specifier = ">=3.20.3" }, { name = "google-adk", specifier = ">=1.38.0,<2" }, @@ -2286,6 +2284,7 @@ version = "0.1.0" source = { editable = "packages/kagent-core" } dependencies = [ { name = "a2a-sdk", extra = ["http-server"] }, + { name = "certifi" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-grpc" }, { name = "opentelemetry-exporter-otlp-proto-http" }, @@ -2301,6 +2300,7 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "a2a-sdk", extras = ["http-server"], specifier = ">=0.3.26" }, + { name = "certifi", specifier = ">=2026.10.19" }, { name = "opentelemetry-api", specifier = ">=1.38.0,<1.39.0" }, { name = "opentelemetry-exporter-otlp-proto-grpc", specifier = ">=1.38.0,<1.39.0" }, { name = "opentelemetry-exporter-otlp-proto-http", specifier = ">=1.38.0,<1.39.0" }, @@ -5141,28 +5141,28 @@ wheels = [ [[package]] name = "uv" -version = "0.9.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/6a/ef4ea19097ecdfd7df6e608f93874536af045c68fd70aa628c667815c458/uv-0.9.26.tar.gz", hash = "sha256:8b7017a01cc48847a7ae26733383a2456dd060fc50d21d58de5ee14f6b6984d7", size = 3790483, upload-time = "2026-01-15T20:51:33.582Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/e1/5c0b17833d5e3b51a897957348ff8d937a3cdfc5eea5c4a7075d8d7b9870/uv-0.9.26-py3-none-linux_armv6l.whl", hash = "sha256:7dba609e32b7bd13ef81788d580970c6ff3a8874d942755b442cffa8f25dba57", size = 22638031, upload-time = "2026-01-15T20:51:44.187Z" }, - { url = "https://files.pythonhosted.org/packages/a5/8b/68ac5825a615a8697e324f52ac0b92feb47a0ec36a63759c5f2931f0c3a0/uv-0.9.26-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b815e3b26eeed00e00f831343daba7a9d99c1506883c189453bb4d215f54faac", size = 21507805, upload-time = "2026-01-15T20:50:42.574Z" }, - { url = "https://files.pythonhosted.org/packages/0d/a2/664a338aefe009f6e38e47455ee2f64a21da7ad431dbcaf8b45d8b1a2b7a/uv-0.9.26-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1b012e6c4dfe767f818cbb6f47d02c207c9b0c82fee69a5de6d26ffb26a3ef3c", size = 20249791, upload-time = "2026-01-15T20:50:49.835Z" }, - { url = "https://files.pythonhosted.org/packages/ba/3d/b8186a7dec1346ca4630c674b760517d28bffa813a01965f4b57596bacf3/uv-0.9.26-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:ea296b700d7c4c27acdfd23ffaef2b0ecdd0aa1b58d942c62ee87df3b30f06ac", size = 22039108, upload-time = "2026-01-15T20:51:00.675Z" }, - { url = "https://files.pythonhosted.org/packages/aa/a9/687fd587e7a3c2c826afe72214fb24b7f07b0d8b0b0300e6a53b554180ea/uv-0.9.26-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:1ba860d2988efc27e9c19f8537a2f9fa499a8b7ebe4afbe2d3d323d72f9aee61", size = 22174763, upload-time = "2026-01-15T20:50:46.471Z" }, - { url = "https://files.pythonhosted.org/packages/38/69/7fa03ee7d59e562fca1426436f15a8c107447d41b34e0899e25ee69abfad/uv-0.9.26-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8610bdfc282a681a0a40b90495a478599aa3484c12503ef79ef42cd271fd80fe", size = 22189861, upload-time = "2026-01-15T20:51:15.618Z" }, - { url = "https://files.pythonhosted.org/packages/10/2d/4be446a2ec09f3c428632b00a138750af47c76b0b9f987e9a5b52fef0405/uv-0.9.26-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4bf700bd071bd595084b9ee0a8d77c6a0a10ca3773d3771346a2599f306bd9c", size = 23005589, upload-time = "2026-01-15T20:50:57.185Z" }, - { url = "https://files.pythonhosted.org/packages/c3/16/860990b812136695a63a8da9fb5f819c3cf18ea37dcf5852e0e1b795ca0d/uv-0.9.26-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:89a7beea1c692f76a6f8da13beff3cbb43f7123609e48e03517cc0db5c5de87c", size = 24713505, upload-time = "2026-01-15T20:51:04.366Z" }, - { url = "https://files.pythonhosted.org/packages/01/43/5d7f360d551e62d8f8bf6624b8fca9895cea49ebe5fce8891232d7ed2321/uv-0.9.26-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:182f5c086c7d03ad447e522b70fa29a0302a70bcfefad4b8cd08496828a0e179", size = 24342500, upload-time = "2026-01-15T20:51:47.863Z" }, - { url = "https://files.pythonhosted.org/packages/9b/9c/2bae010a189e7d8e5dc555edcfd053b11ce96fad2301b919ba0d9dd23659/uv-0.9.26-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d8c62a501f13425b4b0ce1dd4c6b82f3ce5a5179e2549c55f4bb27cc0eb8ef8", size = 23222578, upload-time = "2026-01-15T20:51:36.85Z" }, - { url = "https://files.pythonhosted.org/packages/38/16/a07593a040fe6403c36f3b0a99b309f295cbfe19a1074dbadb671d5d4ef7/uv-0.9.26-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e89798bd3df7dcc4b2b4ac4e2fc11d6b3ff4fe7d764aa3012d664c635e2922", size = 23250201, upload-time = "2026-01-15T20:51:19.117Z" }, - { url = "https://files.pythonhosted.org/packages/23/a0/45893e15ad3ab842db27c1eb3b8605b9b4023baa5d414e67cfa559a0bff0/uv-0.9.26-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:60a66f1783ec4efc87b7e1f9bd66e8fd2de3e3b30d122b31cb1487f63a3ea8b7", size = 22229160, upload-time = "2026-01-15T20:51:22.931Z" }, - { url = "https://files.pythonhosted.org/packages/fc/c0/20a597a5c253702a223b5e745cf8c16cd5dd053080f896bb10717b3bedec/uv-0.9.26-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:63c6a1f1187facba1fb45a2fa45396980631a3427ac11b0e3d9aa3ebcf2c73cf", size = 23090730, upload-time = "2026-01-15T20:51:26.611Z" }, - { url = "https://files.pythonhosted.org/packages/40/c9/744537867d9ab593fea108638b57cca1165a0889cfd989981c942b6de9a5/uv-0.9.26-py3-none-musllinux_1_1_i686.whl", hash = "sha256:c6d8650fbc980ccb348b168266143a9bd4deebc86437537caaf8ff2a39b6ea50", size = 22436632, upload-time = "2026-01-15T20:51:12.045Z" }, - { url = "https://files.pythonhosted.org/packages/6b/e2/be683e30262f2cf02dcb41b6c32910a6939517d50ec45f502614d239feb7/uv-0.9.26-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:25278f9298aa4dade38241a93d036739b0c87278dcfad1ec1f57e803536bfc49", size = 23480064, upload-time = "2026-01-15T20:50:53.333Z" }, - { url = "https://files.pythonhosted.org/packages/50/3e/4a7e6bc5db2beac9c4966f212805f1903d37d233f2e160737f0b24780ada/uv-0.9.26-py3-none-win32.whl", hash = "sha256:10d075e0193e3a0e6c54f830731c4cb965d6f4e11956e84a7bed7ed61d42aa27", size = 21000052, upload-time = "2026-01-15T20:51:40.753Z" }, - { url = "https://files.pythonhosted.org/packages/07/5d/eb80c6eff2a9f7d5cf35ec84fda323b74aa0054145db28baf72d35a7a301/uv-0.9.26-py3-none-win_amd64.whl", hash = "sha256:0315fc321f5644b12118f9928086513363ed9b29d74d99f1539fda1b6b5478ab", size = 23684930, upload-time = "2026-01-15T20:51:08.448Z" }, - { url = "https://files.pythonhosted.org/packages/ed/9d/3b2631931649b1783f5024796ca8ad2b42a01a829b9ce1202d973cc7bce5/uv-0.9.26-py3-none-win_arm64.whl", hash = "sha256:344ff38749b6cd7b7dfdfb382536f168cafe917ae3a5aa78b7a63746ba2a905b", size = 22158123, upload-time = "2026-01-15T20:51:30.939Z" }, +version = "0.13.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/f0/7565e80415f841c3500ed69d86516c7676e3b24470a218ab61b1f43071a2/uv-0.13.5.tar.gz", hash = "sha256:979409b8c9a78df140ffb19c53f511b7a73526da8d1d5e36558833055e371c6c", size = 7513309, upload-time = "2026-10-22T01:32:33.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/ff/e30478710f53cf388c892e27e90662aa2acac7a7998bdb18023c595213c1/uv-0.13.5-py3-none-linux_armv6l.whl", hash = "sha256:8d092d07d2389909027c2ed4965ade1bd46bbcecceb26686ff40927684f8c457", size = 18325046, upload-time = "2026-10-22T01:31:37.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/2a/dcae794203261e49564bb9ff7c4b64a093f69ac73476cc8ce54c1deed3a1/uv-0.13.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:337a14829bb499e114989df4f908f134ff37f1fb6c33497541cfb05b28080e39", size = 17335724, upload-time = "2026-10-22T01:31:40.889Z" }, + { url = "https://files.pythonhosted.org/packages/d2/26/9ac45211123244ea68be852775093af487a64debc13621a2de239f8ebe73/uv-0.13.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a42c85fa8156e1e5e2cecdbc77bb818ea1dcf5f78b8e2a8f84c7fe4f16f0702e", size = 14470685, upload-time = "2026-10-22T01:31:43.897Z" }, + { url = "https://files.pythonhosted.org/packages/e8/2e/5bf9acf9d11fb790420e258a875e13bba36bc890858350642aca185efe0e/uv-0.13.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:2386c2dc9b59fc1d39b1c500e4319d71d3268232eb3b38e29cd6775d6269e8d4", size = 17784583, upload-time = "2026-10-22T01:31:46.95Z" }, + { url = "https://files.pythonhosted.org/packages/f3/70/b02fdcbae77346e3ec1310e7de9dde541252e709f6641db3fbd32cd4da79/uv-0.13.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:4f62680fe58c5a83fd539e38f1956c2b577b1f5939c9020aa4c7f0addda2f4ad", size = 17866408, upload-time = "2026-10-22T01:31:50.352Z" }, + { url = "https://files.pythonhosted.org/packages/fd/b9/6663095851e0943e05e47318d7600e567bc172a1e7a26b21b8e6608e8491/uv-0.13.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e03f5717bdaaf5ab4e2df361d2395e36b515946f56ef4bed88801aeb9959fb0", size = 17753574, upload-time = "2026-10-22T01:31:53.502Z" }, + { url = "https://files.pythonhosted.org/packages/e5/84/1bb89a94486b813bbeaa1b8b491e69a25fa864626711944127b186f903de/uv-0.13.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f867c5ec24c563afaae730a13e46cdf74a1a0b64c134286ff99762a96e2abf40", size = 18502087, upload-time = "2026-10-22T01:31:56.748Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a1/b0b0c7247f3bb0f307eae8a28679ecd0d4b0e2757fcf6c87dea6f679a099/uv-0.13.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3fd5db55c20feb672ea457361aba29ab68b9ae69a14d98ad6c138b5f86dcca4", size = 19927049, upload-time = "2026-10-22T01:31:59.831Z" }, + { url = "https://files.pythonhosted.org/packages/b4/44/6bf11de78ce18869849a14178534b900dbe4e310270b2f60df6503c03137/uv-0.13.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e01481ae5212e45ee7c85fad5fc67f06b0ee0329a7c3c289dc529da884b03881", size = 19662743, upload-time = "2026-10-22T01:32:03.258Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ad/3c2a81d66d1839063662e5b6c0002ec31f8ee987dbc5295747627ca6160a/uv-0.13.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa8d26e08e34c29c0c4e820cf3181757086d547240b4f4d31ff1d8bd810ca946", size = 17211825, upload-time = "2026-10-22T01:32:06.393Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/d83d019c63c1ccc6ff17df2bfe76270412f9766e7e71aa4d4ccbf018683f/uv-0.13.5-py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:91e58e304b63b6c91bac5561459ab0c3ea24f17bc01ea9359d69fed72142978f", size = 16654136, upload-time = "2026-10-22T01:32:10.086Z" }, + { url = "https://files.pythonhosted.org/packages/b8/5a/d42f9d93b322ad36647eb3bf516cc528847c240f630f6df213b6221c5262/uv-0.13.5-py3-none-manylinux_2_31_riscv64.musllinux_1_1_riscv64.whl", hash = "sha256:309a74d3c488bfaa3ba7bff759da73193d8781729c0a01274f4940fd32bb5712", size = 17921105, upload-time = "2026-10-22T01:32:13.174Z" }, + { url = "https://files.pythonhosted.org/packages/97/79/c5c2c39c78cf7a1dd6e041b3f7aa2cc4258d351d42dea06f6fee0bde5daa/uv-0.13.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:469cca66de1b17c75b9b9de806a64cffb57cba5e42b1e30d0bba6fa72a146f58", size = 18103266, upload-time = "2026-10-22T01:32:16.302Z" }, + { url = "https://files.pythonhosted.org/packages/01/2f/e5c70a05013077e5ecadb804418ddbab33f7279f96d052f79f565369b2a7/uv-0.13.5-py3-none-musllinux_1_1_i686.whl", hash = "sha256:2386e8dbfe110ff2f8ec8bd344dd18bf39eb9eb54e1edeeb87c3b85c34229cd3", size = 17842061, upload-time = "2026-10-22T01:32:19.208Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b0/7dba2cb636d7f58e0d74e948ad1afc6b7923e84e82de025e9951a68055db/uv-0.13.5-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:d162669e3a7811c584b03690eaa11e796ad1d309aa8229d5dfe3cbcd68a90400", size = 18963145, upload-time = "2026-10-22T01:32:22.362Z" }, + { url = "https://files.pythonhosted.org/packages/00/7c/e38b312abaae1bd59ff5886126f48e9e223fbb9a8edf9e236ede976f67cb/uv-0.13.5-py3-none-win32.whl", hash = "sha256:f4e55a6e2a1089fe74ed50fbdf2df0f6f336ee148ad232b05932db5deee8007e", size = 16240919, upload-time = "2026-10-22T01:32:25.329Z" }, + { url = "https://files.pythonhosted.org/packages/32/ea/771744a784b16aa21d195cb5d5d5a2878d72fa00fc26f11ea3f9646994fe/uv-0.13.5-py3-none-win_amd64.whl", hash = "sha256:1fb29fc46ba12033e2ef95a95ac79d649e71bbb1358419bbbcbd19d86026ef2f", size = 15358650, upload-time = "2026-10-22T01:32:28.22Z" }, + { url = "https://files.pythonhosted.org/packages/52/67/1f31243f75ece410f2db1afdfc9a9f9722fdee2385e4a347c3ca1dee6d13/uv-0.13.5-py3-none-win_arm64.whl", hash = "sha256:0548460d46c8667488b1f089e936f29f0edfb1cc753f9152ffbd8bc84a46aa20", size = 15533668, upload-time = "2026-10-22T01:32:31.335Z" }, ] [[package]] diff --git a/scripts/check_python_image_trust.py b/scripts/check_python_image_trust.py new file mode 100644 index 0000000000..8cadd79a59 --- /dev/null +++ b/scripts/check_python_image_trust.py @@ -0,0 +1,96 @@ +"""Check the active Python image trust stores against the eMudhra compromise.""" + +import hashlib +import os +import re +import ssl +import sys +import sysconfig +import unittest +import zipfile +from importlib import import_module +from importlib.util import find_spec +from pathlib import Path + +import botocore.httpsession +import certifi +import grpc + +# These roots authenticate the compromised intermediates, including cross-signs. +# https://emudhra.we-have-a-problem.com/roots.json +BLOCKED_ROOTS = { + "7dd78d5f4f13459a83dff9abbba62edbaf6f2d102bf257fd712f4d9f2746ed8d", + "f2edaaff3d9b701fb4d14c9f285f8c0bad90fc3bcc1fa07d47f4718edaba34a5", + "d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4", + "86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b", +} + + +def bundle_fingerprints(bundle): + return { + hashlib.sha256(ssl.PEM_cert_to_DER_cert(pem)).hexdigest() + for pem in re.findall( + r"-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----", + bundle, + re.DOTALL, + ) + } + + +class ImageTrustTest(unittest.TestCase): + def assert_safe_bundle(self, path): + roots = bundle_fingerprints(Path(path).read_text()) + self.assertTrue(roots, f"Empty CA bundle: {path}") + self.assertFalse(roots & BLOCKED_ROOTS, f"Compromised CA trust in {path}") + + def test_system_roots(self): + paths = ssl.get_default_verify_paths() + roots = { + hashlib.sha256(root).hexdigest() + for root in ssl.create_default_context().get_ca_certs(binary_form=True) + } + # OpenSSL loads hashed-directory certificates lazily during verification. + if paths.capath: + for path in Path(paths.capath).iterdir(): + if path.is_file(): + roots.update(bundle_fingerprints(path.read_text())) + self.assertTrue(roots, "The Python default trust store is empty") + self.assertFalse(roots & BLOCKED_ROOTS) + + def test_library_bundles(self): + paths = [ + certifi.where(), + botocore.httpsession.get_cert_path(True), + Path(botocore.httpsession.__file__).with_name("cacert.pem"), + ] + if find_spec("httplib2") is not None: + paths.append(import_module("httplib2.certs").where()) + for path in paths: + with self.subTest(bundle=path): + self.assert_safe_bundle(path) + + def test_grpc_roots(self): + # Python gRPC's roots callback precedes its system-store fallback. + path = os.environ.get("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH") + self.assertTrue(path, "gRPC must use the updated system CA bundle") + self.assert_safe_bundle(path) + self.assertIsNotNone(grpc.ssl_channel_credentials()) + + def test_managed_python(self): + self.assertGreaterEqual(sys.version_info[:3], (3, 13, 17)) + + def test_ensurepip_bundles(self): + bundled = Path(sysconfig.get_path("stdlib")) / "ensurepip" / "_bundled" + for wheel in bundled.glob("pip-*.whl"): + with self.subTest(wheel=wheel), zipfile.ZipFile(wheel) as archive: + roots = bundle_fingerprints( + archive.read("pip/_vendor/certifi/cacert.pem").decode() + ) + self.assertTrue(roots) + self.assertFalse( + roots & BLOCKED_ROOTS, f"Compromised CA trust in {wheel}" + ) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/ui/Dockerfile b/ui/Dockerfile index 256b2e86d4..3fb2d05fdc 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -1,8 +1,8 @@ ### STAGE 1: Dependencies and Build ARG BASE_IMAGE_REGISTRY=cgr.dev -ARG TOOLS_NODE_VERSION=24 +ARG TOOLS_NODE_VERSION=24.22.1 ARG BUILDPLATFORM -FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest AS deps +FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest@sha256:bc76fa39ddd1482dd56a761b3331e03ba8f0e093ebb525618a56d014b480da88 AS deps ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 # This is used to print the build platform in the logs @@ -10,7 +10,7 @@ ARG BUILDPLATFORM ARG TOOLS_NODE_VERSION RUN echo "Installing on $BUILDPLATFORM" \ - && apk add --no-cache curl bash openssl unzip ca-certificates nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" node-gyp \ + && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" node-gyp \ && update-ca-certificates ENV DO_NOT_TRACK=1 @@ -40,7 +40,7 @@ RUN --mount=type=cache,target=/root/.npm,rw \ && mkdir -p /app/ui/public ### STAGE 3: Runtime -FROM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest AS final +FROM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest@sha256:bc76fa39ddd1482dd56a761b3331e03ba8f0e093ebb525618a56d014b480da88 AS final ENV LANG=C.UTF-8 ENV LC_ALL=C.UTF-8 ENV NODE_ENV=production @@ -49,7 +49,7 @@ ARG BUILDPLATFORM ARG TOOLS_NODE_VERSION RUN echo "Installing on $BUILDPLATFORM" \ - && apk add --no-cache curl bash openssl unzip ca-certificates nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" \ + && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" \ && update-ca-certificates RUN mkdir -p /app/ui/public /tmp/nginx/client_temp /tmp/nginx/proxy_temp /tmp/nginx/fastcgi_temp /tmp/nginx/uwsgi_temp /tmp/nginx/scgi_temp \ From 4b7e9b55a78daa5445ee35a49c8f19ffb3511b11 Mon Sep 17 00:00:00 2001 From: rtemperini <29879569+rtemperini@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:32:28 +0200 Subject: [PATCH 2/3] chore: keep certificate trust fix focused Signed-off-by: rtemperini <29879569+rtemperini@users.noreply.github.com> --- .github/workflows/image-scan.yaml | 16 ----- .github/workflows/tag.yaml | 2 +- scripts/check_python_image_trust.py | 96 ----------------------------- 3 files changed, 1 insertion(+), 113 deletions(-) delete mode 100644 scripts/check_python_image_trust.py diff --git a/.github/workflows/image-scan.yaml b/.github/workflows/image-scan.yaml index 15357a258c..097b02c917 100644 --- a/.github/workflows/image-scan.yaml +++ b/.github/workflows/image-scan.yaml @@ -30,12 +30,6 @@ jobs: fail-fast: false matrix: include: - - build_target: kagent-adk - image_name: kagent-adk - tag_suffix: "" - - build_target: kagent-adk-full - image_name: kagent-adk - tag_suffix: "-full" - build_target: controller image_name: controller tag_suffix: "" @@ -77,8 +71,6 @@ jobs: env: DOCKER_BUILDER: "docker buildx build" DOCKER_BUILD_ARGS: >- - --pull - --no-cache --cache-from=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-${{ matrix.build_target }} --cache-from=type=gha --cache-to=type=gha,scope=${{ env.CACHE_KEY_PREFIX }}-${{ matrix.build_target }},mode=max @@ -88,14 +80,6 @@ jobs: export VERSION=${{ steps.vars.outputs.version }} make build-${{ matrix.build_target }} working-directory: ./ - - name: Check Python certificate trust - if: startsWith(matrix.build_target, 'kagent-adk') - env: - IMAGE: localhost:5001/kagent-dev/kagent/${{ matrix.image_name }}:${{ steps.vars.outputs.version }}${{ matrix.tag_suffix }} - run: | - docker run --rm --entrypoint /.kagent/.venv/bin/python \ - -v "$PWD/scripts/check_python_image_trust.py:/tmp/check_python_image_trust.py:ro" \ - "$IMAGE" /tmp/check_python_image_trust.py - name: Image vulnerability scanner uses: aquasecurity/trivy-action@v0.36.0 with: diff --git a/.github/workflows/tag.yaml b/.github/workflows/tag.yaml index d2400546e3..a7b0727eb2 100644 --- a/.github/workflows/tag.yaml +++ b/.github/workflows/tag.yaml @@ -52,7 +52,7 @@ jobs: use: 'true' - name: 'Build Images' env: - DOCKER_BUILD_ARGS: "--pull --no-cache --push --platform linux/amd64,linux/arm64" + DOCKER_BUILD_ARGS: "--push --platform linux/amd64,linux/arm64" DOCKER_BUILDER: "docker buildx build" DOCKER_REGISTRY: "ghcr.io" # prod for releases, local for dev run: | diff --git a/scripts/check_python_image_trust.py b/scripts/check_python_image_trust.py deleted file mode 100644 index 8cadd79a59..0000000000 --- a/scripts/check_python_image_trust.py +++ /dev/null @@ -1,96 +0,0 @@ -"""Check the active Python image trust stores against the eMudhra compromise.""" - -import hashlib -import os -import re -import ssl -import sys -import sysconfig -import unittest -import zipfile -from importlib import import_module -from importlib.util import find_spec -from pathlib import Path - -import botocore.httpsession -import certifi -import grpc - -# These roots authenticate the compromised intermediates, including cross-signs. -# https://emudhra.we-have-a-problem.com/roots.json -BLOCKED_ROOTS = { - "7dd78d5f4f13459a83dff9abbba62edbaf6f2d102bf257fd712f4d9f2746ed8d", - "f2edaaff3d9b701fb4d14c9f285f8c0bad90fc3bcc1fa07d47f4718edaba34a5", - "d7a7a0fb5d7e2731d771e9484ebcdef71d5f0c3e0a2948782bc83ee0ea699ef4", - "86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b", -} - - -def bundle_fingerprints(bundle): - return { - hashlib.sha256(ssl.PEM_cert_to_DER_cert(pem)).hexdigest() - for pem in re.findall( - r"-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----", - bundle, - re.DOTALL, - ) - } - - -class ImageTrustTest(unittest.TestCase): - def assert_safe_bundle(self, path): - roots = bundle_fingerprints(Path(path).read_text()) - self.assertTrue(roots, f"Empty CA bundle: {path}") - self.assertFalse(roots & BLOCKED_ROOTS, f"Compromised CA trust in {path}") - - def test_system_roots(self): - paths = ssl.get_default_verify_paths() - roots = { - hashlib.sha256(root).hexdigest() - for root in ssl.create_default_context().get_ca_certs(binary_form=True) - } - # OpenSSL loads hashed-directory certificates lazily during verification. - if paths.capath: - for path in Path(paths.capath).iterdir(): - if path.is_file(): - roots.update(bundle_fingerprints(path.read_text())) - self.assertTrue(roots, "The Python default trust store is empty") - self.assertFalse(roots & BLOCKED_ROOTS) - - def test_library_bundles(self): - paths = [ - certifi.where(), - botocore.httpsession.get_cert_path(True), - Path(botocore.httpsession.__file__).with_name("cacert.pem"), - ] - if find_spec("httplib2") is not None: - paths.append(import_module("httplib2.certs").where()) - for path in paths: - with self.subTest(bundle=path): - self.assert_safe_bundle(path) - - def test_grpc_roots(self): - # Python gRPC's roots callback precedes its system-store fallback. - path = os.environ.get("GRPC_DEFAULT_SSL_ROOTS_FILE_PATH") - self.assertTrue(path, "gRPC must use the updated system CA bundle") - self.assert_safe_bundle(path) - self.assertIsNotNone(grpc.ssl_channel_credentials()) - - def test_managed_python(self): - self.assertGreaterEqual(sys.version_info[:3], (3, 13, 17)) - - def test_ensurepip_bundles(self): - bundled = Path(sysconfig.get_path("stdlib")) / "ensurepip" / "_bundled" - for wheel in bundled.glob("pip-*.whl"): - with self.subTest(wheel=wheel), zipfile.ZipFile(wheel) as archive: - roots = bundle_fingerprints( - archive.read("pip/_vendor/certifi/cacert.pem").decode() - ) - self.assertTrue(roots) - self.assertFalse( - roots & BLOCKED_ROOTS, f"Compromised CA trust in {wheel}" - ) - - -if __name__ == "__main__": - unittest.main(verbosity=2) From 8017024875067a3035fb5dd69c4d910d44523ee6 Mon Sep 17 00:00:00 2001 From: rtemperini <29879569+rtemperini@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:59:39 +0100 Subject: [PATCH 3/3] fix(security): enforce patched runtime version floors Signed-off-by: rtemperini <29879569+rtemperini@users.noreply.github.com> --- Makefile | 2 +- python/Dockerfile | 2 +- python/Dockerfile.full | 4 ++-- ui/Dockerfile | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 24dce3bfce..e450de6798 100644 --- a/Makefile +++ b/Makefile @@ -97,7 +97,7 @@ LDFLAGS := -X github.com/$(DOCKER_REPO)/go/core/internal/version.Version=$(VERSI #tools versions TOOLS_UV_VERSION ?= 0.13.5 -TOOLS_NODE_VERSION ?= 24.22.1 +TOOLS_NODE_VERSION ?= 24 TOOLS_PYTHON_VERSION ?= 3.13 # build args diff --git a/python/Dockerfile b/python/Dockerfile index 0271770969..2791bdeac2 100644 --- a/python/Dockerfile +++ b/python/Dockerfile @@ -28,7 +28,7 @@ ENV UV_PYTHON_INSTALL_DIR=/python ENV UV_PYTHON_PREFERENCE=only-managed RUN apt-get update \ - && apt-get install -y --no-install-recommends ca-certificates \ + && apt-get satisfy -y --no-install-recommends 'ca-certificates (>= 20250419+deb13u1)' \ && rm -rf /var/lib/apt/lists/* COPY --from=uv-bin /uv /uvx /usr/local/bin/ diff --git a/python/Dockerfile.full b/python/Dockerfile.full index f3d55783a0..c548dbd82f 100644 --- a/python/Dockerfile.full +++ b/python/Dockerfile.full @@ -40,8 +40,8 @@ ENV UV_PYTHON_PREFERENCE=only-managed # node/npm come from the base image; add the remaining runtime tooling. RUN apt-get update \ - && apt-get install -y --no-install-recommends \ - curl openssl bash git ca-certificates \ + && apt-get satisfy -y --no-install-recommends \ + curl openssl bash git 'ca-certificates (>= 20250419~deb12u2)' \ bubblewrap socat ripgrep \ && rm -rf /var/lib/apt/lists/* diff --git a/ui/Dockerfile b/ui/Dockerfile index 3fb2d05fdc..49e5dfab9c 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -1,6 +1,6 @@ ### STAGE 1: Dependencies and Build ARG BASE_IMAGE_REGISTRY=cgr.dev -ARG TOOLS_NODE_VERSION=24.22.1 +ARG TOOLS_NODE_VERSION=24 ARG BUILDPLATFORM FROM --platform=$BUILDPLATFORM $BASE_IMAGE_REGISTRY/chainguard/wolfi-base:latest@sha256:bc76fa39ddd1482dd56a761b3331e03ba8f0e093ebb525618a56d014b480da88 AS deps ENV LANG=C.UTF-8 @@ -10,7 +10,7 @@ ARG BUILDPLATFORM ARG TOOLS_NODE_VERSION RUN echo "Installing on $BUILDPLATFORM" \ - && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" node-gyp \ + && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs-${TOOLS_NODE_VERSION}>=24.22.1" node-gyp \ && update-ca-certificates ENV DO_NOT_TRACK=1 @@ -49,7 +49,7 @@ ARG BUILDPLATFORM ARG TOOLS_NODE_VERSION RUN echo "Installing on $BUILDPLATFORM" \ - && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs~${TOOLS_NODE_VERSION}" \ + && apk add --no-cache curl bash openssl unzip "ca-certificates>=20260909-r3" nginx supervisor "nodejs-${TOOLS_NODE_VERSION}>=24.22.1" \ && update-ca-certificates RUN mkdir -p /app/ui/public /tmp/nginx/client_temp /tmp/nginx/proxy_temp /tmp/nginx/fastcgi_temp /tmp/nginx/uwsgi_temp /tmp/nginx/scgi_temp \