From 5bc03b161bd307e30f973506f1a95e0a98f8473d Mon Sep 17 00:00:00 2001 From: aki Date: Tue, 11 Aug 2026 18:53:38 +0900 Subject: [PATCH] fix: switch Ruby tag source to Registry v2 API to avoid Docker Hub 403 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docker Hub の hub.docker.com/v2/repositories/.../tags/ は匿名リクエストだと offset 1000 (11ページ目) 以降で 403 を返すようになり、50ページの while ループが 確実に失敗するようになった (--retry では回避不可能な決定的なエラーのため)。 そもそも1737件全タグを50ページかけて取得する必要はなく、Registry v2 API (registry.hub.docker.com/v2/library/ruby/tags/list) を使えば匿名トークンで 全タグを1リクエストで取得できる。ページングを丸ごと削除し、取得件数が 異常に少ない場合は上流障害の見逃しを防ぐため明示的にエラーにする。 --- .github/workflows/add_ruby_versions.yml | 55 +++++++++++++++---------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/.github/workflows/add_ruby_versions.yml b/.github/workflows/add_ruby_versions.yml index 775d540..b2bde45 100644 --- a/.github/workflows/add_ruby_versions.yml +++ b/.github/workflows/add_ruby_versions.yml @@ -28,29 +28,42 @@ jobs: - name: Fetch all bare-semver tags from Docker Hub library/ruby id: fetch - env: - MAX_PAGES: 50 run: | set -euo pipefail - tmp_all="$(mktemp)" - url="https://hub.docker.com/v2/repositories/library/ruby/tags/?page_size=100" - page=0 - while [[ -n "${url}" && "${url}" != "null" ]]; do - page=$((page + 1)) - if (( page > MAX_PAGES )); then - echo "::error::Exceeded MAX_PAGES=${MAX_PAGES}" - exit 1 - fi - echo "Fetching page ${page}: ${url}" - resp="$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors \ - -H 'Accept: application/json' "${url}")" - echo "${resp}" | jq -r '.results[].name' >> "${tmp_all}" - url="$(echo "${resp}" | jq -r '.next')" - done - - grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' "${tmp_all}" \ + + # Registry v2 API は全タグ (現状 1737 件) を 1 レスポンスで返すためページング不要。 + # 旧実装が使っていた hub.docker.com/v2/repositories/.../tags/ は匿名リクエストだと + # offset 1000 (= 11 ページ目) 以降が 403 になり、リトライでは回避できない。 + # {"message":"pagination offset too large for anonymous requests; sign in to page further"} + token="$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors \ + 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/ruby:pull' \ + | jq -r '.token')" + + if [[ -z "${token}" || "${token}" == "null" ]]; then + echo "::error::Failed to obtain Docker registry token" + exit 1 + fi + + resp="$(curl -fsSL --retry 5 --retry-delay 5 --retry-all-errors \ + -H "Authorization: Bearer ${token}" \ + -H 'Accept: application/json' \ + 'https://registry.hub.docker.com/v2/library/ruby/tags/list')" + + # 並び順は問わない (後続の Python 側で semver として並べ直す) ので dedup のみ。 + echo "${resp}" | jq -r '.tags[]' \ + | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \ | sort -u > upstream_versions.txt - echo "Found $(wc -l < upstream_versions.txt) bare-semver Ruby tags upstream" + + count="$(wc -l < upstream_versions.txt)" + echo "Found ${count} bare-semver Ruby tags upstream" + + # 差分ロジックは「上流に無いものは追加しない」方向にしか働かないため、 + # 取得が失敗して空・極少になっても PR が作られず「新バージョンなし」と誤認される。 + # 上流障害を静かに見逃さないよう明示的に落とす (正常時は 130 件前後)。 + if (( count < 50 )); then + echo "::error::Suspiciously few tags (${count}); aborting to avoid a bogus diff" + exit 1 + fi - name: Compute new versions (skip back-fill of gaps) and update ruby_versions.json id: diff @@ -144,7 +157,7 @@ jobs: cat /tmp/pr_body_versions.txt echo echo "## 参照元" - echo "- Docker Hub Tags API: https://hub.docker.com/v2/repositories/library/ruby/tags/?page_size=100" + echo "- Docker Registry Tags API: https://registry.hub.docker.com/v2/library/ruby/tags/list" echo "- Docker Hub UI: https://hub.docker.com/_/ruby/tags" echo echo "## 抽出ロジック"