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 33f15862..b5d2bd3b 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. - The authentication failure throttle no longer locks everyone behind a proxy out together (#1031). It keyed on the TCP peer, which behind a reverse proxy is the proxy for every user, and it counted an expired token as a failure, so ordinary token expiry across users reached the limit and all of them got 429 `auth_throttled`. Two changes: an expired token (`code: token_expired`) is no longer counted — it verified and is only old; and `KPUBDATA_BUILDER_TRUSTED_PROXIES` (addresses or CIDR blocks, unset by default) names the proxies whose `X-Forwarded-For` is read, from the right, so each client behind them has its own allowance. Without the setting the header is still never read. The production compose passes the variable through and sets no value. - A dataset whose terms say `redistribution: allowed` without a confirmed attribution is not published publicly (#1030). The publish gate read only `license.redistribution`. kpubdata's rule is that a term nobody confirmed must not read as permission (kpubdata#785), and the `attribution` text is what shows the terms were read from the provider's page; kpubdata `main` still carries 16 specs that say `allowed` without it (`scripts/unconfirmed_terms_baseline.txt`). The gate now reads the attribution too: `allowed` without it is `unknown`, so a public publish is refused with `redistribution_unknown` and the reason says why. Private publishing and reading are unaffected, as for every other `unknown`. With the pinned kpubdata 0.8.0 nothing changes yet — none of those specs declares its terms in that release. - A credential in a `url` source's endpoint is not written to the spec snapshot (#1029). The endpoint was recorded as given, so a data.go.kr-style URL pasted whole left `?serviceKey=…` in `buildspec.yaml` and in `GET /builds/{run_id}/spec`. The value of a query parameter whose name is a credential name — the same set `params` uses, `key` included — is now ``, and userinfo (`https://user:password@host/`) is redacted whole. **Digest:** a `url` spec whose endpoint carried such a parameter or userinfo hashes differently from now on, and two specs that differ only in that credential share a digest; an endpoint with nothing to redact is recorded byte for byte and keeps its digest. Snapshots already written are not rewritten. diff --git a/tests/unit/test_prod_oidc_plumbing.py b/tests/unit/test_prod_oidc_plumbing.py index 262bdab9..894bf1a9 100644 --- a/tests/unit/test_prod_oidc_plumbing.py +++ b/tests/unit/test_prod_oidc_plumbing.py @@ -35,6 +35,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")