* fix(cli-install): move kbcstorage to [server] extra so wheel installs cleanly
The 0.53.3 wheel served at /cli/wheel/ is unsatisfiable on a clean machine:
analyst runs `uv tool install <wheel-url>` per the published /setup
instructions and the resolver immediately fails with
Because kbcstorage<=0.9.5 depends on urllib3<2.0.0 and
agnes-the-ai-analyst==0.53.3 depends on kbcstorage>=0.9.0 and
urllib3>=2.7.0, we can conclude that agnes-the-ai-analyst==0.53.3
cannot be used.
The `[tool.uv] override-dependencies = ["urllib3>=2.7.0"]` in pyproject.toml
masked the conflict in workspace contexts (Dockerfile + dev install) but
does NOT propagate to the wheel — wheel METADATA is plain PEP 621
Requires-Dist, and a fresh resolver context (uv tool install <wheel-url>)
never sees the override. Every existing test passed because the dev venv
already has kbcstorage 0.9.5 + urllib3 2.7.0 coexisting under workspace
overrides; the break only surfaces on the next analyst's first install.
Fix: kbcstorage moved out of [project] dependencies into
[project.optional-dependencies].server, since it is server-side only
(connectors/keboola/client.py is the sole import site, called from admin
endpoints, server connectors, and integration tests — never from the CLI
install path). Server install picks it up via Dockerfile's
`uv pip install --system --no-cache ".[server]"`. CI installs `.[dev,server]`
so workspace tests still cover the kbcstorage path. Analyst CLI wheel
METADATA now lists `kbcstorage>=0.9.0; extra == 'server'` (gated) and
`uv tool install <wheel>` resolves cleanly.
Verified end-to-end:
- Built wheel locally; inspected METADATA — kbcstorage line is now `; extra == 'server'`.
- `docker run --rm python:3.13-slim` + `uv tool install <wheel>`: agnes 0.53.4 installs, `agnes --version` works, `agnes catalog --help` renders, kbcstorage absent from CLI venv, urllib3 = 2.7.0.
- Same container with `.[server]` install path: kbcstorage present, urllib3 = 2.7.0 (override applies in workspace context).
- Full pytest suite green locally (4157 passed, 25 skipped).
* release: 0.53.4 — analyst CLI install hotfix (urllib3/kbcstorage resolver conflict)
Patch bump shipping the [server] extra split + new clean-install CI lane.
No DB migration; no API change; no operator-facing config change.
Operator side (Dockerfile path) auto-picks `.[server]` so the production
image gains kbcstorage transparently. Analyst onboarding (uv tool install
<wheel>) starts working again.
74 lines
3.2 KiB
Docker
74 lines
3.2 KiB
Docker
FROM python:3.13-slim
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends curl git && rm -rf /var/lib/apt/lists/*
|
|
|
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|
|
|
ARG AGNES_VERSION=dev
|
|
ARG RELEASE_CHANNEL=dev
|
|
ARG AGNES_COMMIT_SHA=unknown
|
|
ARG AGNES_TAG=unknown
|
|
ENV AGNES_VERSION=${AGNES_VERSION}
|
|
ENV RELEASE_CHANNEL=${RELEASE_CHANNEL}
|
|
ENV AGNES_COMMIT_SHA=${AGNES_COMMIT_SHA}
|
|
ENV AGNES_TAG=${AGNES_TAG}
|
|
|
|
WORKDIR /app
|
|
|
|
COPY . .
|
|
|
|
# Bake every host-side artifact at /opt/agnes-host/ — the contract path
|
|
# VM startup uses to extract files via `docker create` + `docker cp`
|
|
# instead of curling from raw.githubusercontent.com/main. Pins host
|
|
# artifacts to AGNES_TAG the same way the app is already pinned —
|
|
# eliminates the split-brain where the immutable image runs against
|
|
# arbitrary main-branch compose files / bash scripts.
|
|
#
|
|
# Includes:
|
|
# - agnes-auto-upgrade.sh — host cron driver (5-min digest poll)
|
|
# - agnes-tls-rotate.sh — host cron driver (daily corp-PKI cert refetch)
|
|
# - tls-fetch.sh — generic URL fetcher (sm:// gs:// https:// file://)
|
|
# - docker-compose.{yml,prod.yml,host-mount.yml,tls.yml} — host runtime
|
|
# - Caddyfile — TLS reverse proxy config
|
|
#
|
|
# Why a copy out of /app instead of pointing at /app directly:
|
|
# /app is owned by uid 999 (USER agnes below); /opt/agnes-host is
|
|
# root-owned, mode 0755 across the board, stable path that won't
|
|
# shift if /app structure refactors. Stable contract for `docker cp`
|
|
# consumers.
|
|
RUN mkdir -p /opt/agnes-host && \
|
|
cp /app/scripts/ops/agnes-auto-upgrade.sh \
|
|
/app/scripts/ops/agnes-tls-rotate.sh \
|
|
/app/scripts/tls-fetch.sh \
|
|
/opt/agnes-host/ && \
|
|
cp /app/docker-compose.yml /app/docker-compose.prod.yml \
|
|
/app/docker-compose.host-mount.yml /app/docker-compose.tls.yml \
|
|
/app/Caddyfile /opt/agnes-host/ && \
|
|
chmod 0755 /opt/agnes-host/agnes-auto-upgrade.sh \
|
|
/opt/agnes-host/agnes-tls-rotate.sh \
|
|
/opt/agnes-host/tls-fetch.sh && \
|
|
chmod 0644 /opt/agnes-host/docker-compose.yml \
|
|
/opt/agnes-host/docker-compose.prod.yml \
|
|
/opt/agnes-host/docker-compose.host-mount.yml \
|
|
/opt/agnes-host/docker-compose.tls.yml \
|
|
/opt/agnes-host/Caddyfile
|
|
|
|
# Build wheel artifact (served at /cli/download)
|
|
RUN uv build --wheel --out-dir /app/dist
|
|
|
|
# Install production dependencies from pyproject.toml. The `[server]` extra
|
|
# pulls in connectors-only deps (kbcstorage) that the CLI wheel deliberately
|
|
# omits — see [project.optional-dependencies].server in pyproject.toml.
|
|
RUN uv pip install --system --no-cache ".[server]"
|
|
|
|
# Run as non-root user for container hardening (C13).
|
|
# uid/gid pinned to 999 so host-side chown in startup-script.sh.tpl can match
|
|
# without parsing /etc/passwd inside the image. Changing this number breaks
|
|
# every existing PD-backed deploy until the operator re-chowns /data.
|
|
RUN useradd --system --uid 999 --create-home --shell /usr/sbin/nologin agnes && \
|
|
mkdir -p /data && chown -R agnes:agnes /data && \
|
|
chown -R agnes:agnes /app
|
|
USER agnes
|
|
|
|
EXPOSE 8000
|
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--proxy-headers", "--forwarded-allow-ips", "*"]
|