continuo-python-runtime 0.4.0__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/ci.yml +5 -5
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/dco.yml +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/images.yml +53 -20
- continuo_python_runtime-0.5.0/.github/workflows/publish-pypi.yml +99 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/release.yml +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/security.yml +4 -4
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.gitignore +1 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/CHANGELOG.md +46 -0
- continuo_python_runtime-0.5.0/CLAUDE.md +37 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/CONTRIBUTING.md +2 -2
- continuo_python_runtime-0.5.0/Dockerfile.postgres +56 -0
- continuo_python_runtime-0.5.0/Dockerfile.trino +56 -0
- continuo_python_runtime-0.4.0/README.md → continuo_python_runtime-0.5.0/PKG-INFO +78 -25
- continuo_python_runtime-0.4.0/PKG-INFO → continuo_python_runtime-0.5.0/README.md +58 -45
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/README.md +1 -1
- {continuo_python_runtime-0.4.0/adapters/postgres/continuo_python_runtime_postgres → continuo_python_runtime-0.5.0/adapters/postgres/continuo_postgres_adapter}/adapter.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/pyproject.toml +14 -10
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/test_adapter_postgres_validation.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/test_adapter_runtime_postgres.py +2 -2
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/test_integration_postgres_validation.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/test_integration_runtime_postgres.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/README.md +2 -2
- {continuo_python_runtime-0.4.0/adapters/trino/continuo_python_runtime_trino → continuo_python_runtime-0.5.0/adapters/trino/continuo_trino_adapter}/adapter.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/pyproject.toml +14 -10
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/tests/test_adapter_runtime_trino.py +2 -2
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/tests/test_adapter_trino_validation.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/tests/test_integration_runtime_trino.py +2 -2
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/tests/test_integration_trino_validation.py +1 -1
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/validation/runner.py +21 -7
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/pyproject.toml +2 -2
- continuo_python_runtime-0.5.0/image-requirements-postgres.txt +2 -0
- continuo_python_runtime-0.5.0/image-requirements-trino.txt +2 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/pyproject.toml +17 -8
- continuo_python_runtime-0.5.0/scripts/check_version_bumps.py +65 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/template/Dockerfile +1 -1
- continuo_python_runtime-0.5.0/template/Dockerfile.pip +23 -0
- continuo_python_runtime-0.5.0/template/README.md +82 -0
- continuo_python_runtime-0.5.0/template/requirements.lock +225 -0
- continuo_python_runtime-0.5.0/tests/test_adapter_naming.py +41 -0
- continuo_python_runtime-0.5.0/tests/test_image_requirements_sync.py +36 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_validation_runner.py +87 -7
- continuo_python_runtime-0.5.0/uv.lock +827 -0
- continuo_python_runtime-0.4.0/.github/workflows/publish-pypi.yml +0 -74
- continuo_python_runtime-0.4.0/Dockerfile.postgres +0 -22
- continuo_python_runtime-0.4.0/Dockerfile.trino +0 -22
- continuo_python_runtime-0.4.0/docs/superpowers/plans/2026-07-31-python-runtime.md +0 -1307
- continuo_python_runtime-0.4.0/docs/superpowers/plans/2026-08-07-step-3b-config-three-part-hash.md +0 -852
- continuo_python_runtime-0.4.0/docs/superpowers/specs/2026-07-31-python-runtime-design.md +0 -273
- continuo_python_runtime-0.4.0/template/README.md +0 -36
- continuo_python_runtime-0.4.0/uv.lock +0 -666
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.dockerignore +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/CODEOWNERS +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/dependabot.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.gitleaks.toml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/CODE_OF_CONDUCT.md +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/DCO +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/LICENSE +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/NOTICE +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/SECURITY.md +0 -0
- {continuo_python_runtime-0.4.0/adapters/postgres/continuo_python_runtime_postgres → continuo_python_runtime-0.5.0/adapters/postgres/continuo_postgres_adapter}/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/postgres/tests/conftest.py +0 -0
- {continuo_python_runtime-0.4.0/adapters/trino/continuo_python_runtime_trino → continuo_python_runtime-0.5.0/adapters/trino/continuo_trino_adapter}/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/adapters/trino/tests/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/cli.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/closure.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/conform.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/context.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/contract/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/contract/loader.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/contract/merge.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/contract/model.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/contract/paths.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/csv_loader.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/csv_readers/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/csv_readers/https.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/csv_readers/s3.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/csv_source.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/errors.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/harness.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/hashing.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/lint.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/types.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/validation/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/continuo_python_runtime/validation/s3.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/LICENSE +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/NOTICE +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/README.md +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/config.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/port.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/result.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/sql.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/continuo_engine_contract/types.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/test_config.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/test_contract_types.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/test_port.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/test_result.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/contract/tests/test_sql.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/docs/boundary-contract.md +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/scripts/security-scan.sh +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/template/.github/workflows/release.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/template/contracts/example.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/template/contracts/example_csv.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/template/scripts/example.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/conftest.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/contract/__init__.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/contract/test_loader.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/contract/test_merge.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/contract/test_model.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/smoke/node_smoke/contracts/smoke.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/smoke/node_smoke/scripts/smoke.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/smoke/postgres-stack/docker-compose.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/smoke/trino-stack/catalog/iceberg.properties +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/smoke/trino-stack/docker-compose.yml +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_cli.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_closure.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_conform.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_context.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_contract_loader.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_contract_pin_consistency.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_csv_loader.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_csv_readers_https.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_csv_readers_integration.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_csv_source.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_errors.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_harness.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_hashing.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_image_smoke_validation.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_lint.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_no_legacy_names.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_package.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_template.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_types.py +0 -0
- {continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/tests/test_validation_s3.py +0 -0
|
@@ -6,7 +6,7 @@ jobs:
|
|
|
6
6
|
test:
|
|
7
7
|
runs-on: ubuntu-latest
|
|
8
8
|
steps:
|
|
9
|
-
- uses: actions/checkout@
|
|
9
|
+
- uses: actions/checkout@v7
|
|
10
10
|
- uses: astral-sh/setup-uv@v7
|
|
11
11
|
- name: Sync
|
|
12
12
|
run: uv sync --all-packages --all-groups
|
|
@@ -19,9 +19,9 @@ jobs:
|
|
|
19
19
|
- name: Types (contract)
|
|
20
20
|
run: uv run mypy contract/continuo_engine_contract
|
|
21
21
|
- name: Types (postgres adapter)
|
|
22
|
-
run: uv run --package continuo-
|
|
22
|
+
run: uv run --package continuo-postgres-adapter mypy adapters/postgres/continuo_postgres_adapter
|
|
23
23
|
- name: Types (trino adapter)
|
|
24
|
-
run: uv run --package continuo-
|
|
24
|
+
run: uv run --package continuo-trino-adapter mypy adapters/trino/continuo_trino_adapter
|
|
25
25
|
# `-m "not image"` deselects tests/test_image_smoke_validation.py, which
|
|
26
26
|
# needs a built engine image and the env naming it. Those tests run in
|
|
27
27
|
# images.yml's smoke jobs, where an image actually exists. `and not
|
|
@@ -41,7 +41,7 @@ jobs:
|
|
|
41
41
|
integration-postgres:
|
|
42
42
|
runs-on: ubuntu-latest
|
|
43
43
|
steps:
|
|
44
|
-
- uses: actions/checkout@
|
|
44
|
+
- uses: actions/checkout@v7
|
|
45
45
|
- uses: astral-sh/setup-uv@v7
|
|
46
46
|
- run: uv sync --all-packages --all-groups
|
|
47
47
|
- name: Start postgres stack
|
|
@@ -55,7 +55,7 @@ jobs:
|
|
|
55
55
|
integration-trino:
|
|
56
56
|
runs-on: ubuntu-latest
|
|
57
57
|
steps:
|
|
58
|
-
- uses: actions/checkout@
|
|
58
|
+
- uses: actions/checkout@v7
|
|
59
59
|
- uses: astral-sh/setup-uv@v7
|
|
60
60
|
- run: uv sync --all-packages --all-groups
|
|
61
61
|
- name: Start trino stack
|
{continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/images.yml
RENAMED
|
@@ -20,12 +20,15 @@ jobs:
|
|
|
20
20
|
engine: [postgres, trino]
|
|
21
21
|
runs-on: ubuntu-latest
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v7
|
|
24
|
+
- uses: astral-sh/setup-uv@v7
|
|
25
|
+
- name: Build wheels into a wheelhouse
|
|
26
|
+
run: uv build --all-packages -o wheelhouse
|
|
24
27
|
- name: Build ${{ matrix.engine }} image
|
|
25
|
-
run: docker build -f Dockerfile.${{ matrix.engine }} -t cpr-smoke-${{ matrix.engine }} .
|
|
28
|
+
run: docker build -f Dockerfile.${{ matrix.engine }} --build-arg WHEEL_SOURCE=wheelhouse -t cpr-smoke-${{ matrix.engine }} .
|
|
26
29
|
- name: Save image
|
|
27
30
|
run: docker save cpr-smoke-${{ matrix.engine }} -o /tmp/cpr-smoke-${{ matrix.engine }}.tar
|
|
28
|
-
- uses: actions/upload-artifact@
|
|
31
|
+
- uses: actions/upload-artifact@v7
|
|
29
32
|
with:
|
|
30
33
|
name: cpr-smoke-${{ matrix.engine }}-image
|
|
31
34
|
path: /tmp/cpr-smoke-${{ matrix.engine }}.tar
|
|
@@ -49,8 +52,8 @@ jobs:
|
|
|
49
52
|
--health-timeout 5s
|
|
50
53
|
--health-retries 10
|
|
51
54
|
steps:
|
|
52
|
-
- uses: actions/checkout@
|
|
53
|
-
- uses: actions/download-artifact@
|
|
55
|
+
- uses: actions/checkout@v7
|
|
56
|
+
- uses: actions/download-artifact@v8
|
|
54
57
|
with:
|
|
55
58
|
name: cpr-smoke-postgres-image
|
|
56
59
|
path: /tmp
|
|
@@ -104,8 +107,8 @@ jobs:
|
|
|
104
107
|
needs: build
|
|
105
108
|
runs-on: ubuntu-latest
|
|
106
109
|
steps:
|
|
107
|
-
- uses: actions/checkout@
|
|
108
|
-
- uses: actions/download-artifact@
|
|
110
|
+
- uses: actions/checkout@v7
|
|
111
|
+
- uses: actions/download-artifact@v8
|
|
109
112
|
with:
|
|
110
113
|
name: cpr-smoke-trino-image
|
|
111
114
|
path: /tmp
|
|
@@ -153,21 +156,31 @@ jobs:
|
|
|
153
156
|
if: always()
|
|
154
157
|
run: docker compose -f tests/smoke/trino-stack/docker-compose.yml down -v
|
|
155
158
|
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
159
|
+
# Runs on this same tag push, after the smoke jobs above pass. It builds both
|
|
160
|
+
# engine images for linux/amd64 and linux/arm64 installing the pinned
|
|
161
|
+
# versions FROM PyPI (WHEEL_SOURCE=pypi, the Dockerfile default), then
|
|
162
|
+
# pushes them to ghcr.io/<owner>/continuo-python-runtime-<engine>:<tag>. The
|
|
163
|
+
# engine belongs in the image NAME, not the tag: Continuo's Helm chart pins
|
|
164
|
+
# an image as `<name>:vX.Y.Z@sha256:<digest>`, so the tag must be the bare
|
|
160
165
|
# version. Both platforms are required: domain repos build their own images
|
|
161
166
|
# FROM these, and Continuo's e2e runs them in a kind cluster on aarch64
|
|
162
|
-
# developer machines as well as on amd64 CI runners, so a single-arch
|
|
163
|
-
# is unusable off amd64. The smoke jobs above stay single-arch —
|
|
164
|
-
# `docker save` tarball, which has no multi-platform
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
167
|
+
# developer machines as well as on amd64 CI runners, so a single-arch
|
|
168
|
+
# publish is unusable off amd64. The smoke jobs above stay single-arch —
|
|
169
|
+
# they load a `docker save` tarball, which has no multi-platform
|
|
170
|
+
# equivalent.
|
|
171
|
+
#
|
|
172
|
+
# publish-pypi.yml runs in parallel on this same tag push, not before this
|
|
173
|
+
# job: there is no cross-workflow `needs:`, so this job cannot wait on that
|
|
174
|
+
# workflow directly. Instead the wait-until-installable step below polls
|
|
175
|
+
# PyPI until the pinned versions this tag just published are actually
|
|
176
|
+
# installable, which is what orders this build after publish-pypi.yml
|
|
177
|
+
# completes without a cross-workflow dependency.
|
|
178
|
+
# -test tags publish to TestPyPI only (see publish-pypi.yml), so this job
|
|
179
|
+
# skips them: there is no real-PyPI installable version to build an image
|
|
180
|
+
# from for those.
|
|
168
181
|
publish:
|
|
169
|
-
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-test')
|
|
170
182
|
needs: [smoke-postgres, smoke-trino]
|
|
183
|
+
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-test')
|
|
171
184
|
strategy:
|
|
172
185
|
matrix:
|
|
173
186
|
engine: [postgres, trino]
|
|
@@ -176,8 +189,8 @@ jobs:
|
|
|
176
189
|
contents: read
|
|
177
190
|
packages: write
|
|
178
191
|
steps:
|
|
179
|
-
- uses: actions/checkout@
|
|
180
|
-
- uses: docker/setup-qemu-action@
|
|
192
|
+
- uses: actions/checkout@v7
|
|
193
|
+
- uses: docker/setup-qemu-action@v4
|
|
181
194
|
- uses: docker/setup-buildx-action@v4
|
|
182
195
|
- name: Log in to ghcr.io
|
|
183
196
|
uses: docker/login-action@v4
|
|
@@ -185,6 +198,26 @@ jobs:
|
|
|
185
198
|
registry: ghcr.io
|
|
186
199
|
username: ${{ github.actor }}
|
|
187
200
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
201
|
+
# The pinned distributions declare Requires-Python >= 3.14, so the
|
|
202
|
+
# availability probe must resolve them under a 3.14 interpreter — the
|
|
203
|
+
# runner's default python is older and pip would reject them even after
|
|
204
|
+
# they are published, spinning out every retry. (The image build itself
|
|
205
|
+
# installs inside python:3.14-slim, so it is unaffected; this is only for
|
|
206
|
+
# the host-side probe below.)
|
|
207
|
+
- uses: actions/setup-python@v7
|
|
208
|
+
with:
|
|
209
|
+
python-version: '3.14'
|
|
210
|
+
- name: Wait until the pinned versions are installable from PyPI
|
|
211
|
+
run: |
|
|
212
|
+
set -eu
|
|
213
|
+
req="image-requirements-${{ matrix.engine }}.txt"
|
|
214
|
+
for i in $(seq 1 30); do
|
|
215
|
+
if python -m pip download --dest /tmp/probe -r "$req" >/tmp/probe.log 2>&1; then
|
|
216
|
+
echo "installable"; exit 0
|
|
217
|
+
fi
|
|
218
|
+
echo "attempt $i: not yet on index; sleeping"; sleep 20
|
|
219
|
+
done
|
|
220
|
+
echo "pinned versions never became installable"; cat /tmp/probe.log; exit 1
|
|
188
221
|
- name: Build and push ${{ matrix.engine }} image
|
|
189
222
|
uses: docker/build-push-action@v7
|
|
190
223
|
with:
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
name: publish-pypi
|
|
2
|
+
|
|
3
|
+
# Publishes all four PyPI distributions this repo owns — continuo-python-runtime
|
|
4
|
+
# (the harness), continuo-engine-contract (the port, result-block format, and
|
|
5
|
+
# shared guards), and the two engine adapters (continuo-postgres-adapter,
|
|
6
|
+
# continuo-trino-adapter) — via PyPI Trusted Publishing (OIDC, no stored
|
|
7
|
+
# token). They publish together on a single v* tag, each at its own
|
|
8
|
+
# pyproject version, so a tag that only bumps the runtime still carries an
|
|
9
|
+
# unchanged adapter version along for the ride; skip-existing (below) makes
|
|
10
|
+
# that a no-op rather than a duplicate-upload failure. A release-time guard
|
|
11
|
+
# (scripts/check_version_bumps.py) refuses a tag that changed a package's
|
|
12
|
+
# source without bumping its version, so skip-existing can never silently
|
|
13
|
+
# ship stale adapter code under an unchanged version number.
|
|
14
|
+
#
|
|
15
|
+
# Tag glob note: `v*` is the repository's single release pattern — the same tag
|
|
16
|
+
# that images.yml builds and pushes both engine images from, so one tag ships
|
|
17
|
+
# the whole release. GitHub Actions tag globs anchor at character 1, so `v*`
|
|
18
|
+
# claims every tag beginning with "v"; no other pattern may be introduced.
|
|
19
|
+
# Tag `v<ver>-test<n>` publishes to TestPyPI; `v<ver>` publishes to real PyPI.
|
|
20
|
+
# The GitHub environment name is what the PyPI "pending publisher" is
|
|
21
|
+
# registered against — all four project names need one on each index.
|
|
22
|
+
#
|
|
23
|
+
# All four distributions are built into a single `dist/` and uploaded in one
|
|
24
|
+
# publish call, so there is no ordering constraint between them. The runtime
|
|
25
|
+
# wheel declares continuo-engine-contract as a dependency and resolves it from
|
|
26
|
+
# the index at install time ([tool.uv.sources] is dev-only and is not embedded
|
|
27
|
+
# in the wheel).
|
|
28
|
+
on:
|
|
29
|
+
push:
|
|
30
|
+
tags:
|
|
31
|
+
- "v*"
|
|
32
|
+
|
|
33
|
+
permissions: {}
|
|
34
|
+
|
|
35
|
+
jobs:
|
|
36
|
+
publish-packages:
|
|
37
|
+
if: startsWith(github.ref_name, 'v')
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
environment: ${{ contains(github.ref_name, '-test') && 'testpypi' || 'pypi' }}
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write # OIDC token for Trusted Publishing
|
|
42
|
+
contents: read # actions/checkout needs read access to the repo
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v7
|
|
45
|
+
with:
|
|
46
|
+
fetch-depth: 0
|
|
47
|
+
- uses: astral-sh/setup-uv@v7
|
|
48
|
+
- name: Refuse a tag that changed a package without bumping its version
|
|
49
|
+
run: python scripts/check_version_bumps.py
|
|
50
|
+
- name: Test before publishing
|
|
51
|
+
# Gate all four published projects, including both adapter suites — an
|
|
52
|
+
# adapter regression must block its own immutable PyPI upload, and
|
|
53
|
+
# images.yml runs in parallel so its smoke failure cannot. Each suite is
|
|
54
|
+
# a SEPARATE pytest invocation: every workspace member's tests/ is its
|
|
55
|
+
# own `tests` package (with __init__.py + conftest.py), so running two
|
|
56
|
+
# of them in one process collides on the `tests.conftest` module name
|
|
57
|
+
# (see the [tool.pytest.ini_options] note in pyproject.toml). `not image
|
|
58
|
+
# and not integration` deselects the tests needing a built engine image
|
|
59
|
+
# or a live warehouse (images.yml / the smoke jobs cover those). The
|
|
60
|
+
# step's default `set -e` fails the gate if any invocation fails.
|
|
61
|
+
run: |
|
|
62
|
+
uv sync --all-packages --all-groups
|
|
63
|
+
uv run pytest tests contract/tests -m "not image and not integration" -q
|
|
64
|
+
uv run pytest adapters/postgres/tests -m "not image and not integration" -q
|
|
65
|
+
uv run pytest adapters/trino/tests -m "not image and not integration" -q
|
|
66
|
+
- name: Build the contract sdist + wheel
|
|
67
|
+
run: uv build --package continuo-engine-contract -o dist
|
|
68
|
+
- name: Build the runtime sdist + wheel
|
|
69
|
+
run: uv build -o dist
|
|
70
|
+
- name: Build the postgres adapter sdist + wheel
|
|
71
|
+
run: uv build --package continuo-postgres-adapter -o dist
|
|
72
|
+
- name: Build the trino adapter sdist + wheel
|
|
73
|
+
run: uv build --package continuo-trino-adapter -o dist
|
|
74
|
+
# Adapters change rarely, so most v* tags carry an unchanged adapter
|
|
75
|
+
# version alongside a bumped runtime/contract version. Without
|
|
76
|
+
# skip-existing, re-uploading that unchanged version 400s and fails the
|
|
77
|
+
# whole publish. Trade-off: a changed package published without a
|
|
78
|
+
# version bump is then silently skipped too — the
|
|
79
|
+
# check_version_bumps.py guard above is what catches that case, before
|
|
80
|
+
# this job's build/publish steps ever run.
|
|
81
|
+
- name: Publish to TestPyPI
|
|
82
|
+
if: contains(github.ref_name, '-test')
|
|
83
|
+
# Pinned to a commit SHA. release/v1 is a moving branch, and this job
|
|
84
|
+
# holds id-token: write for PyPI Trusted Publishing — a compromised
|
|
85
|
+
# revision could mint a token and publish under this project's name.
|
|
86
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
87
|
+
with:
|
|
88
|
+
repository-url: https://test.pypi.org/legacy/
|
|
89
|
+
packages-dir: dist
|
|
90
|
+
skip-existing: true
|
|
91
|
+
- name: Publish to PyPI
|
|
92
|
+
if: ${{ !contains(github.ref_name, '-test') }}
|
|
93
|
+
# Pinned to a commit SHA. release/v1 is a moving branch, and this job
|
|
94
|
+
# holds id-token: write for PyPI Trusted Publishing — a compromised
|
|
95
|
+
# revision could mint a token and publish under this project's name.
|
|
96
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
97
|
+
with:
|
|
98
|
+
packages-dir: dist
|
|
99
|
+
skip-existing: true
|
{continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/release.yml
RENAMED
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
# other source of the repo's files. Its absence went unnoticed through
|
|
54
54
|
# review because this job only triggers on push:tags, never on
|
|
55
55
|
# pull_request, so no PR's CI ever actually executes it.
|
|
56
|
-
- uses: actions/checkout@
|
|
56
|
+
- uses: actions/checkout@v7
|
|
57
57
|
|
|
58
58
|
- name: Wait for publish-pypi.yml and images.yml to finish on this commit
|
|
59
59
|
run: |
|
{continuo_python_runtime-0.4.0 → continuo_python_runtime-0.5.0}/.github/workflows/security.yml
RENAMED
|
@@ -47,7 +47,7 @@ jobs:
|
|
|
47
47
|
# range (below), and this repository is small enough (a few hundred KB,
|
|
48
48
|
# well under a second to scan) that fetch-depth: 0 costs nothing on every
|
|
49
49
|
# trigger rather than only on the schedule.
|
|
50
|
-
- uses: actions/checkout@
|
|
50
|
+
- uses: actions/checkout@v7
|
|
51
51
|
with:
|
|
52
52
|
fetch-depth: 0
|
|
53
53
|
|
|
@@ -96,7 +96,7 @@ jobs:
|
|
|
96
96
|
- name: Upload SARIF to code scanning
|
|
97
97
|
if: always()
|
|
98
98
|
continue-on-error: true
|
|
99
|
-
uses: github/codeql-action/upload-sarif@
|
|
99
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
100
100
|
with:
|
|
101
101
|
sarif_file: sarif/
|
|
102
102
|
category: gitleaks
|
|
@@ -106,7 +106,7 @@ jobs:
|
|
|
106
106
|
runs-on: ubuntu-latest
|
|
107
107
|
timeout-minutes: 20
|
|
108
108
|
steps:
|
|
109
|
-
- uses: actions/checkout@
|
|
109
|
+
- uses: actions/checkout@v7
|
|
110
110
|
|
|
111
111
|
# Advisory: reports HIGH/CRITICAL and always exits 0. Base-image and
|
|
112
112
|
# transitive CVEs are often unfixable upstream, so gating on them would
|
|
@@ -124,7 +124,7 @@ jobs:
|
|
|
124
124
|
- name: Upload SARIF to code scanning
|
|
125
125
|
if: always()
|
|
126
126
|
continue-on-error: true
|
|
127
|
-
uses: github/codeql-action/upload-sarif@
|
|
127
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
128
128
|
with:
|
|
129
129
|
sarif_file: sarif/
|
|
130
130
|
category: trivy-fs
|
|
@@ -5,6 +5,52 @@ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2026-09-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `check_binds` validation op: EXPLAINs a dbt test's compiled SQL against the
|
|
13
|
+
candidate schema and creates nothing, so a test that names a dropped or
|
|
14
|
+
renamed column fails. Reads the SQL from `CANDIDATE_SQL_URI`, like
|
|
15
|
+
`build_from_sql`.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- `continuo-postgres-adapter` and `continuo-trino-adapter` 0.2.0 → 0.2.1.
|
|
20
|
+
|
|
21
|
+
## [0.4.1] - 2026-08-25
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Bring-your-own engine adapters: `continuo-postgres-adapter` and
|
|
26
|
+
`continuo-trino-adapter` are separate installable packages, so an install
|
|
27
|
+
can supply its own engine adapter independently of the runtime.
|
|
28
|
+
- `scripts/check_version_bumps.py`: fails a release when a package's source
|
|
29
|
+
changed since the last tag but its version did not.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Deterministic python-node container builds: pinned per-engine
|
|
34
|
+
image-requirements and hashed template Dockerfiles.
|
|
35
|
+
- `continuo-engine-contract` 0.7.2 → 0.7.3.
|
|
36
|
+
|
|
37
|
+
## [0.4.0] - 2026-08-21
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- `python-csv` node kind: a contract-only CSV loader (no user script) that
|
|
42
|
+
materializes the declared table from the contract's CSV URI, with a
|
|
43
|
+
validation header check.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- `continuo-engine-contract` 0.7.1 → 0.7.2.
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- `release.yml`'s github-release job now checks out the repository; without the
|
|
52
|
+
checkout it could not read the tag's files.
|
|
53
|
+
|
|
8
54
|
## [0.3.1] - 2026-08-21
|
|
9
55
|
|
|
10
56
|
### Added
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# continuo-python-runtime
|
|
2
|
+
|
|
3
|
+
The validation/execution runtime that continuo's executor runs as a Kubernetes
|
|
4
|
+
Job. Python 3.12, uv workspace: the runtime (`continuo_python_runtime`), the
|
|
5
|
+
engine contract (`contract/`), and the engine adapters (`adapters/postgres`,
|
|
6
|
+
`adapters/trino`).
|
|
7
|
+
|
|
8
|
+
## CHANGELOG is not optional
|
|
9
|
+
|
|
10
|
+
Every user-facing change keeps `CHANGELOG.md` current. Two steps, both required:
|
|
11
|
+
|
|
12
|
+
- **On every PR** that changes behavior, the CLI/op surface, a package version,
|
|
13
|
+
or a container: add a bullet under `## [Unreleased]` (Keep a Changelog style —
|
|
14
|
+
Added / Changed / Fixed / Removed). No entry, no merge.
|
|
15
|
+
- **On every release**: rename `## [Unreleased]` to `## [X.Y.Z] - YYYY-MM-DD`,
|
|
16
|
+
add a fresh empty `## [Unreleased]` above it, and tag. `release.yml` reads the
|
|
17
|
+
section matching the pushed tag for the GitHub Release notes, so a release with
|
|
18
|
+
no matching section ships with generic auto-notes and the changelog silently
|
|
19
|
+
loses that version.
|
|
20
|
+
|
|
21
|
+
If the changelog is missing a shipped version, backfill it from that tag's
|
|
22
|
+
merged PRs before adding anything new.
|
|
23
|
+
|
|
24
|
+
## Releasing
|
|
25
|
+
|
|
26
|
+
A release is one `chore(release):` commit that bumps versions and updates the
|
|
27
|
+
changelog, then a `vX.Y.Z` tag on it. Bump the version of every package whose
|
|
28
|
+
source changed since the last tag — `scripts/check_version_bumps.py` fails the
|
|
29
|
+
PyPI publish otherwise. The tag builds and publishes the `-postgres` / `-trino`
|
|
30
|
+
images and the PyPI packages. See `CONTRIBUTING.md` for the full steps.
|
|
31
|
+
|
|
32
|
+
## Conventions
|
|
33
|
+
|
|
34
|
+
- Standard `logging` for diagnostics, never `print` — except the CLI's
|
|
35
|
+
sentinel-framed result blocks, which own stdout.
|
|
36
|
+
- In-repo packages are pinned exactly, not with ranges (see `pyproject.toml`).
|
|
37
|
+
- Commits are signed off (`git commit -s`); CI enforces the DCO.
|
|
@@ -57,8 +57,8 @@ uv run ruff check .
|
|
|
57
57
|
uv run ruff check contract
|
|
58
58
|
uv run mypy continuo_python_runtime
|
|
59
59
|
uv run mypy contract/continuo_engine_contract
|
|
60
|
-
uv run --package continuo-
|
|
61
|
-
uv run --package continuo-
|
|
60
|
+
uv run --package continuo-postgres-adapter mypy adapters/postgres/continuo_postgres_adapter
|
|
61
|
+
uv run --package continuo-trino-adapter mypy adapters/trino/continuo_trino_adapter
|
|
62
62
|
uv run pytest --cov=continuo_python_runtime -m "not image and not integration" -v
|
|
63
63
|
uv run pytest tests/test_csv_readers_integration.py tests/test_validation_runner.py -m integration -v
|
|
64
64
|
uv run pytest contract/tests -v
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
FROM python:3.14-slim
|
|
2
|
+
# One dual-role image per engine — the python-node runtime harness (default
|
|
3
|
+
# command `run`) and the blue/green validation runner (`validation-op`). It
|
|
4
|
+
# installs the PUBLISHED, versioned libraries, never the repo source:
|
|
5
|
+
# WHEEL_SOURCE=pypi (release) installs the pins from PyPI. PyPI versions
|
|
6
|
+
# are immutable and the image is consumed
|
|
7
|
+
# digest-pinned, so no hash lock is needed here.
|
|
8
|
+
# WHEEL_SOURCE=wheelhouse (CI/PR) installs the same pins from ./wheelhouse
|
|
9
|
+
# (built by CI) so an unreleased change is testable.
|
|
10
|
+
# The wheelhouse holds only this repo's own first-party wheels (built via
|
|
11
|
+
# `uv build --all-packages`); third-party dependencies always resolve from
|
|
12
|
+
# PyPI in both branches, so the wheelhouse branch never passes --no-index to
|
|
13
|
+
# the requirements install below.
|
|
14
|
+
# The pinned versions live in image-requirements-postgres.txt, kept equal to the
|
|
15
|
+
# repo's pyproject versions by tests/test_image_requirements_sync.py.
|
|
16
|
+
#
|
|
17
|
+
# The wheelhouse branch installs its three first-party wheels (contract,
|
|
18
|
+
# runtime, adapter) by exact local file first, with --no-index --no-deps: a
|
|
19
|
+
# plain `--find-links=/tmp/wheelhouse -r req.txt` is not enough, because pip
|
|
20
|
+
# does not prefer a find-links wheel over an index match at the same
|
|
21
|
+
# name+version, and continuo-python-runtime / continuo-engine-contract are
|
|
22
|
+
# already published on PyPI under the version this repo's HEAD currently
|
|
23
|
+
# carries (a routine dependency bump lands between releases without a version
|
|
24
|
+
# bump). Left unpinned-by-file, pip silently installs the last PyPI release's
|
|
25
|
+
# transitive pins instead of the wheel this build just produced, defeating
|
|
26
|
+
# the point of testing an unreleased change. Installing the exact local files
|
|
27
|
+
# first (no index contacted at all for this step) is unambiguous; the second
|
|
28
|
+
# install then only has PyPI-only third-party deps left to resolve, and finds
|
|
29
|
+
# the three first-party packages already satisfied.
|
|
30
|
+
ARG WHEEL_SOURCE=pypi
|
|
31
|
+
COPY image-requirements-postgres.txt /tmp/req.txt
|
|
32
|
+
# Optional COPY: the bracket glob matches ./wheelhouse when it exists (the CI/PR
|
|
33
|
+
# WHEEL_SOURCE=wheelhouse path builds it) and no-ops when it is absent, so a
|
|
34
|
+
# release build or a plain `docker build -f Dockerfile.postgres .` needs no
|
|
35
|
+
# pre-created directory. Only the wheelhouse branch below reads its contents.
|
|
36
|
+
COPY wheelhous[e] /tmp/wheelhouse
|
|
37
|
+
RUN set -eu; \
|
|
38
|
+
if [ "$WHEEL_SOURCE" = "wheelhouse" ]; then \
|
|
39
|
+
pip install --no-cache-dir --no-index --no-deps \
|
|
40
|
+
/tmp/wheelhouse/continuo_engine_contract-*.whl \
|
|
41
|
+
/tmp/wheelhouse/continuo_python_runtime-*.whl \
|
|
42
|
+
/tmp/wheelhouse/continuo_postgres_adapter-*.whl; \
|
|
43
|
+
pip install --no-cache-dir -r /tmp/req.txt; \
|
|
44
|
+
else \
|
|
45
|
+
pip install --no-cache-dir -r /tmp/req.txt; \
|
|
46
|
+
fi; \
|
|
47
|
+
rm -rf /tmp/req.txt /tmp/wheelhouse
|
|
48
|
+
# PYTHONPATH is belt-and-braces: the harness also inserts APP_ROOT and the
|
|
49
|
+
# node script's own directory at the front of sys.path before executing it.
|
|
50
|
+
ENV CONTRACT_DIR=/app/contracts APP_ROOT=/app PYTHONPATH=/app
|
|
51
|
+
WORKDIR /app
|
|
52
|
+
# uid 65532 matches continuo's executor securityContext expectation.
|
|
53
|
+
RUN useradd --uid 65532 --no-create-home --shell /usr/sbin/nologin nonroot
|
|
54
|
+
USER 65532:65532
|
|
55
|
+
ENTRYPOINT ["continuo-runtime"]
|
|
56
|
+
CMD ["run"]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
FROM python:3.14-slim
|
|
2
|
+
# One dual-role image per engine — the python-node runtime harness (default
|
|
3
|
+
# command `run`) and the blue/green validation runner (`validation-op`). It
|
|
4
|
+
# installs the PUBLISHED, versioned libraries, never the repo source:
|
|
5
|
+
# WHEEL_SOURCE=pypi (release) installs the pins from PyPI. PyPI versions
|
|
6
|
+
# are immutable and the image is consumed
|
|
7
|
+
# digest-pinned, so no hash lock is needed here.
|
|
8
|
+
# WHEEL_SOURCE=wheelhouse (CI/PR) installs the same pins from ./wheelhouse
|
|
9
|
+
# (built by CI) so an unreleased change is testable.
|
|
10
|
+
# The wheelhouse holds only this repo's own first-party wheels (built via
|
|
11
|
+
# `uv build --all-packages`); third-party dependencies always resolve from
|
|
12
|
+
# PyPI in both branches, so the wheelhouse branch never passes --no-index to
|
|
13
|
+
# the requirements install below.
|
|
14
|
+
# The pinned versions live in image-requirements-trino.txt, kept equal to the
|
|
15
|
+
# repo's pyproject versions by tests/test_image_requirements_sync.py.
|
|
16
|
+
#
|
|
17
|
+
# The wheelhouse branch installs its three first-party wheels (contract,
|
|
18
|
+
# runtime, adapter) by exact local file first, with --no-index --no-deps: a
|
|
19
|
+
# plain `--find-links=/tmp/wheelhouse -r req.txt` is not enough, because pip
|
|
20
|
+
# does not prefer a find-links wheel over an index match at the same
|
|
21
|
+
# name+version, and continuo-python-runtime / continuo-engine-contract are
|
|
22
|
+
# already published on PyPI under the version this repo's HEAD currently
|
|
23
|
+
# carries (a routine dependency bump lands between releases without a version
|
|
24
|
+
# bump). Left unpinned-by-file, pip silently installs the last PyPI release's
|
|
25
|
+
# transitive pins instead of the wheel this build just produced, defeating
|
|
26
|
+
# the point of testing an unreleased change. Installing the exact local files
|
|
27
|
+
# first (no index contacted at all for this step) is unambiguous; the second
|
|
28
|
+
# install then only has PyPI-only third-party deps left to resolve, and finds
|
|
29
|
+
# the three first-party packages already satisfied.
|
|
30
|
+
ARG WHEEL_SOURCE=pypi
|
|
31
|
+
COPY image-requirements-trino.txt /tmp/req.txt
|
|
32
|
+
# Optional COPY: the bracket glob matches ./wheelhouse when it exists (the CI/PR
|
|
33
|
+
# WHEEL_SOURCE=wheelhouse path builds it) and no-ops when it is absent, so a
|
|
34
|
+
# release build or a plain `docker build -f Dockerfile.trino .` needs no
|
|
35
|
+
# pre-created directory. Only the wheelhouse branch below reads its contents.
|
|
36
|
+
COPY wheelhous[e] /tmp/wheelhouse
|
|
37
|
+
RUN set -eu; \
|
|
38
|
+
if [ "$WHEEL_SOURCE" = "wheelhouse" ]; then \
|
|
39
|
+
pip install --no-cache-dir --no-index --no-deps \
|
|
40
|
+
/tmp/wheelhouse/continuo_engine_contract-*.whl \
|
|
41
|
+
/tmp/wheelhouse/continuo_python_runtime-*.whl \
|
|
42
|
+
/tmp/wheelhouse/continuo_trino_adapter-*.whl; \
|
|
43
|
+
pip install --no-cache-dir -r /tmp/req.txt; \
|
|
44
|
+
else \
|
|
45
|
+
pip install --no-cache-dir -r /tmp/req.txt; \
|
|
46
|
+
fi; \
|
|
47
|
+
rm -rf /tmp/req.txt /tmp/wheelhouse
|
|
48
|
+
# PYTHONPATH is belt-and-braces: the harness also inserts APP_ROOT and the
|
|
49
|
+
# node script's own directory at the front of sys.path before executing it.
|
|
50
|
+
ENV CONTRACT_DIR=/app/contracts APP_ROOT=/app PYTHONPATH=/app
|
|
51
|
+
WORKDIR /app
|
|
52
|
+
# uid 65532 matches continuo's executor securityContext expectation.
|
|
53
|
+
RUN useradd --uid 65532 --no-create-home --shell /usr/sbin/nologin nonroot
|
|
54
|
+
USER 65532:65532
|
|
55
|
+
ENTRYPOINT ["continuo-runtime"]
|
|
56
|
+
CMD ["run"]
|