From 88fecd95b7c3cec4d34f356314c5017f779f78a1 Mon Sep 17 00:00:00 2001 From: Yeongseon Choe Date: Mon, 5 Oct 2026 13:35:44 +0900 Subject: [PATCH] fix(deploy): build the CUBRID-profile image with the auth extra A build argument replaces the Dockerfile's default EXTRAS, so the cubrid variant lost pyjwt and could not start with OIDC configured (#992). Co-Authored-By: Claude Opus 5.5 --- .github/workflows/docker.yml | 6 ++++-- CHANGELOG.md | 1 + tests/unit/test_prod_oidc_plumbing.py | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c3cc3c02..2b07a1ec 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -148,7 +148,9 @@ jobs: # 없었다 — CUBRID 배포는 존재하지 않는 이미지를 pull 하려 했다. # # 기본 이미지와 다른 점은 cubrid extra 하나뿐이다. sqlalchemy-cubrid 는 순수 - # 파이썬이라 C 툴체인 없이 설치된다(Dockerfile 주석 참고). + # 파이썬이라 C 툴체인 없이 설치된다(Dockerfile 주석 참고). build-arg 는 Dockerfile 의 + # 기본값을 통째로 덮어쓰므로 기본 이미지의 extra(publish, auth)를 여기에 다시 적는다 — + # auth 가 빠지면 이 이미지는 OIDC_ISSUER 를 설정한 배포에서 기동하지 못한다(#992). - name: Build and publish the CUBRID-profile image uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: @@ -156,7 +158,7 @@ jobs: push: true platforms: linux/amd64,linux/arm64 build-args: | - EXTRAS=publish cubrid + EXTRAS=publish auth cubrid tags: ghcr.io/kpubdata-lab/kpubdata-builder:cubrid labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha diff --git a/CHANGELOG.md b/CHANGELOG.md index fb7eca38..1dd28f73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixed +- The CUBRID-profile image can run OIDC (#992). `docker.yml` built `ghcr.io/kpubdata-lab/kpubdata-builder:cubrid` with `EXTRAS=publish cubrid`; a build argument replaces the Dockerfile's default (`publish auth`) rather than adding to it, so that image had no `pyjwt` and refused to start with `OIDC_ISSUER` set. It is built with `publish auth cubrid` now, and a test holds that every image variant in the workflow carries the default image's extras. - A run id whose only record is an interrupted submission is not free to another user (#1025). `check_existing_run_access` looked at the manifest and the job registry; a run a restart interrupted has neither, so another user could build under its id, read the first submitter's events while their job ran, and leave their own failure to the first submitter if interrupted in turn. The guard now reads the submission record #996 added: someone else gets 403 `forbidden: not run owner`, and the submitter may use the id again. Today this guards the synchronous `POST /build`; `POST /builds` gets it when #1008 routes that path through the same guard. - The documentation site builds again. `docs/publishing.md` linked the contract document as `../API_CONTRACT.md`, which is outside the docs directory, so `mkdocs build --strict` aborted and the `Deploy docs` workflow has failed on `main`. The link came in with #923. The link now points at the page and at the section it names. - The owner of a run a restart interrupted can read why it ended (#996, API contract 1.78.0, additive). Such a run is failed as `credentials_required` in the event store only (#683); with the job registry empty after the restart and no manifest, `GET /builds/{run_id}` and `GET /builds/{run_id}/events` both answered 404, so a client polling its build was told the run did not exist instead of to submit it again. The submitter of an async run is now recorded next to its events, the status route reads the terminal event back as `failed` with `error` and the new optional `BuildJob.code` `credentials_required`, and the events route admits the owner. Another user gets what a missing run gets, as before. A run submitted before this version has no recorded submitter and still answers 404. diff --git a/tests/unit/test_prod_oidc_plumbing.py b/tests/unit/test_prod_oidc_plumbing.py index 0cc1bc85..36d17ed9 100644 --- a/tests/unit/test_prod_oidc_plumbing.py +++ b/tests/unit/test_prod_oidc_plumbing.py @@ -34,6 +34,28 @@ def test_the_default_image_installs_the_auth_extra() -> None: assert "publish" in match.group(1).split() +def test_every_image_variant_keeps_the_default_images_extras() -> None: + """A build-arg replaces the Dockerfile's default whole, so a variant must repeat it. + + The CUBRID image was built with ``EXTRAS=publish cubrid``: no ``auth``, so the one + image a CUBRID deployment can pull could not start with OIDC configured (#992). + """ + dockerfile = (_ROOT / "Dockerfile").read_text(encoding="utf-8") + default = re.search(r'^ARG EXTRAS="?([^"\n]*)"?$', dockerfile, re.MULTILINE) + assert default + workflow = (_ROOT / ".github" / "workflows" / "docker.yml").read_text(encoding="utf-8") + variants = re.findall(r"^\s*EXTRAS=(.*)$", workflow, re.MULTILINE) + + assert variants + missing = [ + (variant, extra) + for variant in variants + for extra in default.group(1).split() + if extra not in variant.split() + ] + assert missing == [] + + def test_the_auth_extra_is_what_provides_pyjwt() -> None: text = (_ROOT / "pyproject.toml").read_text(encoding="utf-8")