Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
FROM python:3.12-slim AS runtime
FROM ghcr.io/astral-sh/uv:0.11.28@sha256:0f36cb9361a3346885ca3677e3767016687b5a170c1a6b88465ec14aefec90aa AS uv

FROM python:3.12.14-slim-bookworm@sha256:782412e85d0f0984994c290652577d4018aff08145c85b262bb63dc0c7522254 AS runtime

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
PYTHONUNBUFFERED=1 \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"

WORKDIR /app

COPY pyproject.toml README.md ./
COPY testql/ ./testql/
COPY --from=uv /uv /uvx /bin/
COPY pyproject.toml uv.lock README.md ./
RUN uv lock --check --no-sources && \
uv sync --frozen --no-dev --extra nlp2env \
--no-editable --no-install-project

RUN pip install --no-cache-dir .
COPY testql/ ./testql/
RUN uv sync --frozen --no-dev --extra nlp2env --no-editable

ENV PYTHONPATH=/app

Expand Down
35 changes: 24 additions & 11 deletions Dockerfile.e2e
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
FROM python:3.12-slim AS runtime
FROM ghcr.io/astral-sh/uv:0.11.28@sha256:0f36cb9361a3346885ca3677e3767016687b5a170c1a6b88465ec14aefec90aa AS uv

FROM python:3.12.14-slim-bookworm@sha256:782412e85d0f0984994c290652577d4018aff08145c85b262bb63dc0c7522254 AS runtime

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
PYTHONUNBUFFERED=1 \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
VIRTUAL_ENV=/app/.venv \
PATH="/app/.venv/bin:$PATH"

WORKDIR /app

COPY pyproject.toml README.md ./
COPY testql/ ./testql/
COPY --from=uv /uv /uvx /bin/
COPY pyproject.toml uv.lock README.md ./
RUN uv lock --check --no-sources && \
uv sync --frozen --no-dev --extra nlp2env \
--no-editable --no-install-project

RUN pip install --no-cache-dir .
COPY testql/ ./testql/
RUN uv sync --frozen --no-dev --extra nlp2env --no-editable

ENV PYTHONPATH=/app

FROM runtime AS e2e

RUN uv sync --frozen --extra dev --extra nlp2env --no-editable

COPY openapi.yaml ./
COPY packages/ ./packages/
RUN uv pip install --python /app/.venv/bin/python \
--no-build-isolation --no-deps \
--editable packages/graphql2testql \
--editable packages/proto2testql \
--editable packages/sql2testql \
--editable packages/desktop2testql

COPY tests/ ./tests/
COPY testql-scenarios/ ./testql-scenarios/
COPY .testql/ ./.testql/

RUN pip install --no-cache-dir --no-deps \
-e packages/graphql2testql \
-e packages/proto2testql \
-e packages/sql2testql \
-e packages/desktop2testql

CMD ["pytest", "-q", "--no-cov"]
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Last updated: 2026-09-01 (1.2.67 source — Docker and binary HTTP evidence)

## 📋 Technical Debt & Code Quality

- [ ] Deliver the portable lockfile and immutable Docker build chain tracked by
- [x] Deliver the portable lockfile and immutable Docker build chain tracked by
tickets `003`-`005` and TestQL issue #10 for external consumers such as Koru.
- [x] Repair Docker build inputs after the package moved from `src/` to
`testql/`, and make the E2E image install the extracted local plugins.
Expand Down
1 change: 1 addition & 0 deletions project/TICKETS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ This file indexes governance tickets without taking ownership of
| **ticket-002** | [`README.md`](./ticket-002/README.md) | [`preprompt.md`](./ticket-002/preprompt.md) | - | [`ai-codex.md`](./ticket-002/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-002/ai-codex-logs.txt) | [`changelog.md`](./ticket-002/changelog.md) |
| **ticket-003** | [`README.md`](./ticket-003/README.md) | [`preprompt.md`](./ticket-003/preprompt.md) | - | [`ai-codex.md`](./ticket-003/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-003/ai-codex-logs.txt) | [`changelog.md`](./ticket-003/changelog.md) |
| **ticket-004** | [`README.md`](./ticket-004/README.md) | [`preprompt.md`](./ticket-004/preprompt.md) | - | [`ai-codex.md`](./ticket-004/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-004/ai-codex-logs.txt) | [`changelog.md`](./ticket-004/changelog.md) |
| **ticket-005** | [`README.md`](./ticket-005/README.md) | [`preprompt.md`](./ticket-005/preprompt.md) | - | [`ai-codex.md`](./ticket-005/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-005/ai-codex-logs.txt) | [`changelog.md`](./ticket-005/changelog.md) |
| **ticket-006** | [`README.md`](./ticket-006/README.md) | [`preprompt.md`](./ticket-006/preprompt.md) | - | [`ai-codex.md`](./ticket-006/ai-codex.md) | [`ai-codex-logs.txt`](./ticket-006/ai-codex-logs.txt) | [`changelog.md`](./ticket-006/changelog.md) |
<!-- AUTO:TICKET_INDEX:END -->
66 changes: 66 additions & 0 deletions project/ticket-005/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Ticket 005: Harden external Docker build

- **ID**: ticket-005
- **Owner**: unresolved:human
- **Status**: IN_PROGRESS
- **Workflow state**: PUBLICATION
- **Created**: 2026-09-01

## Goal and scope

Harden both TestQL Docker build paths consumed by external repositories. Pin
the uv tool and Python runtime stages by immutable manifest digest, verify the
portable graph in no-sources mode, and install the project exclusively from the
committed lock in frozen, non-editable mode.

The E2E image also installs its declared `dev` extra from that lock and creates
distribution metadata for the four local plugins without invoking a second
dependency resolver or isolated build environment.

## Acceptance criteria

- [x] AC-01: The user's autonomous sequential-completion request is recorded as
`SESSION_EXECUTION_AUTHORIZATION`.
- [x] AC-02: Every uv/Python Docker stage is selected by an immutable sha256
digest.
- [x] AC-03: Production first checks the portable graph with `uv lock --check
--no-sources`, then installs through `uv sync --frozen --no-editable` with
the required `nlp2env` extra.
- [x] AC-04: E2E dependencies come from the same lock and local plugin sources
require no package resolver.
- [x] AC-05: Both images build; production CLI, package tests, Compose,
governance and Docker checks pass.
- [ ] AC-06: Exact-head protected publication closes TestQL issue #10 and
provides an immutable revision for Koru.

## Authorization

The user's request to continue and close all tasks sequentially authorizes this
bounded TestQL issue #10 implementation and protected publication. It does not
authorize secrets, self-approval, direct merge or unrelated changes.

## Resolved prerequisite

The no-cache runtime image builds and runs TestQL 1.2.67, but the first E2E run
reported `1650 passed, 53 skipped, 10 failed`: local plugin imports worked via
`PYTHONPATH`, while entry-point discovery correctly failed because the packages
were not installed distributions. Ticket 006 locked `setuptools` and `wheel` in
the dev graph and proved resolver-free local metadata installation, so this
ticket resumes on merged revision `2528dcfcfe95b1b786016bf9956900f6f1797843`.

## Validation evidence

- No-cache production image `sha256:a78e6ba5e881b196eac6a12839fc93aca299664413260127433d6f68c2cf1fd1`
reports TestQL 1.2.67, uv 0.11.28 and `nlp2env` 0.1.6.
- No-cache E2E image `sha256:a68a4fbe88dfc505771f9aebb2f2e3ae09c83e37651aa9208d31ac74a26f4744`
installed all four plugins without build isolation or dependency resolution.
- Its `testql.plugins` catalog resolves `graphql`, `proto` and `sql` to the
expected local distributions.
- Full container suite: `1701 passed, 12 skipped, 1 warning` in 17.82 seconds;
all 1713 previously collected cases completed without failure.
- Both Docker build checks and all three root Compose configurations pass.

## Participants

- Human participant: unresolved; no user-* file was created by this script.
- Agent participant: [ai-codex.md](ai-codex.md)
8 changes: 8 additions & 0 deletions project/ticket-005/ai-codex-logs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
2026-09-01T22:29:28Z SESSION_EXECUTION_AUTHORIZATION recorded for TestQL issue #10 and semcod/koru#64.
2026-09-01T22:34:00Z EDIT base=ab9e899b916a1933c6219fc05cf39949d557141c workstream=governance dockerfiles=2.
2026-09-01T22:36:00Z BUILD rejected reason="uv 0.11.28 forbids sync --frozen with --no-sources" remediation="no-sources lock check followed by frozen sync".
2026-09-01T22:39:00Z BUILD runtime=pass cli=1.2.67 uv=0.11.28 nlp2env=0.1.6 e2e_image=pass.
2026-09-01T22:40:00Z BLOCKED e2e="1650 passed, 53 skipped, 10 failed" reason="plugin entry-point metadata absent" prerequisite="lock setuptools and wheel in dev extra".
2026-09-01T23:07:26Z RESUME prerequisite=ticket-006 main=2528dcfcfe95b1b786016bf9956900f6f1797843 status=IN_PROGRESS workflow=EDIT.
2026-09-01T23:10:41Z VALIDATION runtime_image=sha256:a78e6ba5e881b196eac6a12839fc93aca299664413260127433d6f68c2cf1fd1 cli=1.2.67 uv=0.11.28 nlp2env=0.1.6.
2026-09-01T23:10:41Z VALIDATION e2e_image=sha256:a68a4fbe88dfc505771f9aebb2f2e3ae09c83e37651aa9208d31ac74a26f4744 entrypoints=graphql,proto,sql tests="1701 passed, 12 skipped, 1 warning" workflow=PUBLICATION.
40 changes: 40 additions & 0 deletions project/ticket-005/ai-codex.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
participant-id: agent:codex
participant: codex
role: agent
ticket: ticket-005
---
# Participant: codex (AI agent)

## Understanding

TestQL's externally consumed Dockerfile still used a mutable Python tag and
resolved dependencies with pip. The E2E image repeated both behaviors and then
invoked four additional editable package builds. The merged portable lock and
published plugin sources allow both paths to be resolver-free.

## Execution plan

1. Pin uv 0.11.28 and Python 3.12.14 stages by manifest digest.
2. Check the portable graph in no-sources mode, then replace pip resolution
with frozen/non-editable uv sync.
3. Install E2E plugin metadata without build isolation or dependency resolution.
4. Build and execute both images, then run governance and Compose checks.
5. Publish through exact-head Validator review and close issue #10.

## Actual changes

- Recorded the user's session execution authorization and implemented the two
bounded Docker build paths on the exact merged `ticket-004` base.
- Split portable-lock validation from frozen installation because uv 0.11.28
correctly rejects simultaneous `sync --frozen --no-sources`: frozen performs
no source resolution, while the preceding no-sources check binds the graph.
- Resumed after ticket 006 locked the dev build backend, and installed all four
local plugin distributions with `--no-build-isolation --no-deps`.
- Built both images from scratch on immutable base digests. Production reports
TestQL 1.2.67, uv 0.11.28 and `nlp2env` 0.1.6; the E2E image exposes all
required plugin entry points and passes 1701 tests with 12 skips.

## Blockers

- None. Ticket 006 supplied and validated the frozen build-tool prerequisite.
11 changes: 11 additions & 0 deletions project/ticket-005/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Ticket Changelog (ticket-005)

## [0.1.0] - 2026-09-01

- Initial governance scaffold created.
- No human participant identity or content was generated.
- Pinned uv and Python stages by immutable manifest digest.
- Replaced pip resolution with portable-lock validation and frozen uv sync.
- Installed local E2E plugin metadata without build isolation or dependency
resolution and validated the full 1713-case container suite.
- Planned digest-pinned, frozen-lock Docker builds for runtime and E2E.
23 changes: 23 additions & 0 deletions project/ticket-005/intent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"schema": "new-project.intent/v3",
"ticket": "ticket-005",
"summary": "Harden external Docker build",
"workstream": "governance",
"classification": {
"kind": "SERVICE",
"priority": "P1",
"origin": "health"
},
"allowedPaths": [
"project/ticket-005/**",
"TODO.md",
"project/TICKETS.md",
"Dockerfile",
"Dockerfile.e2e"
],
"forbiddenPaths": ["project/ticket-*/user-*.md"],
"stacks": ["docker"],
"dependsOn": ["ticket-003", "ticket-004", "ticket-006"],
"conflictsWith": [],
"integrationTicket": null
}
10 changes: 10 additions & 0 deletions project/ticket-005/preprompt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Ticket preprompt

- **Task ID**: ticket-005
- **Task title**: Harden external Docker build
- **Created**: 2026-09-01T22:29:28Z

Keep executable implementation outside this governance/evidence directory.
Read a human-owned user-*.md file only when one exists.
Use only digest-pinned tool/runtime stages and the committed `uv.lock`; do not
change dependencies, executable source or integration-owned paths.
Loading