Skip to content

fix(ci): authenticate PlantUML release lookup and fail on unresolved versions - #130

Draft
GordonBeeming wants to merge 1 commit into
mainfrom
claude/build-failure-investigation-3hzi6q
Draft

fix(ci): authenticate PlantUML release lookup and fail on unresolved versions#130
GordonBeeming wants to merge 1 commit into
mainfrom
claude/build-failure-investigation-3hzi6q

Conversation

@GordonBeeming

@GordonBeeming GordonBeeming commented Aug 8, 2026

Copy link
Copy Markdown
Owner

What broke

Build #723 failed in the Build java job:

#27 [linux/amd64 10/24] RUN curl -fsSL "https://github.com/plantuml/plantuml/releases/download//plantuml-.jar" ...
#27 0.291 curl: (22) The requested URL returned error: 404

Note the empty path segments: download//plantuml-.jar. The version was missing, not wrong.

Root cause

It starts one job earlier, in prepare-versions. That job's log has a single unexplained line:

curl: (22) The requested URL returned error: 403

…and the job still reported success.

The 403 came from the anonymous PlantUML release lookup:

PLANTUML_TAG=$(curl -fsSL https://api.github.com/repos/plantuml/plantuml/releases/latest | jq -r '.tag_name')
echo "plantuml_url=.../download/${PLANTUML_TAG}/plantuml-${PLANTUML_TAG#v}.jar" >> $GITHUB_OUTPUT

Two things combined:

  1. Rate limit. Unauthenticated api.github.com allows 60 requests/hour, counted per source IP and shared across every job on that runner. Hosted runners exhaust it routinely, which is why this is intermittent — #722 passed on this exact commit.
  2. The failure was swallowed. curl -fsSL … | jq takes its exit status from jq, not curl, so the step's bash -e never aborted. PLANTUML_TAG became empty and the very next echo built the malformed URL regardless, handing a guaranteed-404 build arg to the java image.

So a transient API hiccup was converted into a hard image-build failure four minutes later, with the real cause buried in a different job's log.

Every other lookup in that step has the same curl | jq shape and the same silent-empty-string failure mode.

Changes

.github/workflows/publish.yml, prepare-versions job only:

  • Authenticate the GitHub API call with the repo GITHUB_TOKEN, raising the limit from 60/hour per IP to 1,000/hour per repo.
  • Add set -euo pipefail and fetch/require helpers so a failed download, or a value that comes back empty or null, fails the step where the lookup happens with a named ::error::, instead of silently emitting a broken URL. Applied to all lookups in the step, not just PlantUML.
  • Replace curl 'https://go.dev/VERSION?m=text' | head -1 with a parameter expansion. head -1 closes the pipe after the first of two lines, which under pipefail would fail the command.

No Dockerfiles changed, so no regeneration is needed.

Trade-off

An unresolvable version now fails the build rather than proceeding. That's deliberate: the alternative is publishing an image built from a broken or silently stale URL. With the call authenticated, a 403 here should be very unlikely.

Testing

⚠️ This PR's own green check does not exercise the change. prepare-versions is gated on if: github.ref == 'refs/heads/main', so on a pull_request event it and every dependent image build are skipped. Run #724 is green with Prepare Versions, Build ${{ matrix.image }} and Build Proxy Image all skipped.

So the step was run directly against the real endpoints instead. Every other lookup resolves correctly under the new set -euo pipefail, confirming no regression from that change:

copilot_version=1.0.78          golang_version=1.26.5
playwright_version=1.62.1       maven_version=3.9.16
dotnet_8_version=8.0.423        gradle_version=9.7.0
dotnet_9_version=9.0.316        jdtls_url=.../jdt-language-server-1.61.0-202608051627.tar.gz
dotnet_10_version=10.0.302      csharp_ls_version=0.26.0

The PlantUML call then hit a real 403, and the new code behaved as intended:

curl: (22) The requested URL returned error: 403
::error::failed to fetch https://api.github.com/repos/plantuml/plantuml/releases/latest
STEP EXIT=1

That is the fix demonstrated end to end: the same 403 that silently produced download//plantuml-.jar in #723 now stops the step with a named error.

Also verified in isolation:

  • tag_name: null → aborts with ::error::could not resolve plantuml_tag
  • Happy path → plantuml-1.2025.4.jar, correctly v-stripped
  • The old code under bash -e reproduces download//plantuml-.jar exactly, confirming the diagnosis
  • A garbage Maven index is caught by require
  • bash -n and a YAML parse both pass

Still unverified: the success path of the authenticated API call, which needs a real GITHUB_TOKEN and network access to api.github.com. That will first be exercised by the next scheduled/main run after merge.

…versions

Build #723 failed the java image with a 404 fetching
.../releases/download//plantuml-.jar. The empty path segments came from
prepare-versions: the anonymous api.github.com call for the PlantUML
latest release was rate-limited (403, 60/hour shared per runner IP), so
PLANTUML_TAG resolved to an empty string and the next echo built a
malformed URL anyway.

The failure was silent because `curl -fsSL ... | jq` takes its exit
status from jq, so the step's `bash -e` never aborted. Every version
lookup in the step shares that shape.

- Send the repo GITHUB_TOKEN on the api.github.com call, raising the
  limit from 60/hour per IP to 1000/hour per repo.
- Add `set -euo pipefail` plus fetch/require helpers so a failed download
  or an empty/null value fails the step at the lookup instead of building
  a broken URL for the image build to trip over.
- Replace `curl | head -1` for the Go version with a parameter expansion;
  under pipefail the early pipe close could fail the command.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Dsw1e9DPk8V5WoPf8MmPo
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e99404e-a0e5-46b3-b4d6-067886c5d365

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants