fix: unbreak the scheduled binding-update workflow (exit 127) - #97
Merged
Conversation
…failures
The scheduled "Update API bindings" workflow failed with exit code 127.
Two separate defects combined to produce that:
1. Codegen output was root-owned. `docker container run` writes into the
bind-mounted `bindings/<lang>/src` directory as root, so on Linux the
generated files end up owned by root. `scripts/fix-ruby-escaping.sh` uses
`ruby -i` (in-place edit), which must unlink the original file and therefore
needs write permission on the containing directory. That unlink failed with
"Can't remove ...: Permission denied, skipping file", the apostrophe fix was
silently skipped, and the following `ruby -c` reported the expected syntax
error. The same wall would have been hit by the `uvx ruff check --fix` pass.
This never reproduced locally because macOS bind mounts map container-root
writes back to the host user.
Fixed by running the codegen container as the invoking user.
2. The real error was then masked. `scripts/build.sh` dispatched languages via
`test -z "$language" && { for ...; } || { build_language $language; }`. When
a per-language build failed, the loop returned non-zero and the `||` branch
ran with an empty `$language`, invoking `bindings//build.sh` and replacing
the genuine exit status with 127.
Fixed by using a plain if/else so a failing language build propagates.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Fixes the scheduled “Update API bindings” workflow failure by ensuring generated binding files are writable on Linux runners and by correcting control flow so failed per-language builds propagate their real exit status.
Changes:
- Define
codegen_run_user="$(id -u):$(id -g)"and run the codegen container as the invoking user to avoid root-owned bind-mount outputs. - Replace the
A && B || Cconstruct with anif/elseinscripts/build.shso failures don’t fall through into an empty-language branch. - Apply the
--user "${codegen_run_user:?}"change consistently across Ruby/Python/Java binding generators.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| scripts/common.sh | Introduces a shared codegen_run_user to run docker codegen as the host user. |
| scripts/build.sh | Reworks language dispatch to if/else to preserve correct exit status on failures. |
| bindings/ruby/build.sh | Runs swagger-codegen container with --user to avoid root-owned generated Ruby files. |
| bindings/python/build.sh | Runs swagger-codegen container with --user to avoid root-owned generated Python files. |
| bindings/java/build.sh | Runs swagger-codegen container with --user to avoid root-owned generated Java files. |
Comments suppressed due to low confidence (3)
bindings/python/build.sh:31
- The bind-mount argument is currently unquoted, so a path with spaces would break the
-vargument parsing and could cause codegen to write to the wrong location. Quote the-vvalue (and other path-like args) to make the docker invocation robust.
docker container run --rm --user "${codegen_run_user:?}" -v $self_dir:/local "${swagger_codegen_cli_image:?}" generate \
-c /local/src/build.json \
-i $openapi_url \
-l python \
-o /local/src \
bindings/ruby/build.sh:38
- The bind-mount argument is currently unquoted, so a path with spaces would break the
-vargument parsing and could cause codegen to write to the wrong location. Quote the-vvalue (and other path-like args) to make the docker invocation robust.
docker container run --rm --user "${codegen_run_user:?}" -v $self_dir:/local "${swagger_codegen_cli_image:?}" generate \
-c /local/src/build.json \
-i $openapi_url \
-l ruby \
-o /local/src \
bindings/java/build.sh:52
- The bind-mount argument is currently unquoted, so a path with spaces would break the
-vargument parsing and could cause codegen to write to the wrong location. Quote the-vvalue (and other path-like args) to make the docker invocation robust.
docker container run --rm --user "${codegen_run_user:?}" -v $self_dir:/local "${swagger_codegen_cli_image:?}" generate \
--type-mappings Integer=java.math.BigInteger \
-c /local/src/build.json \
-i $openapi_url \
-l java \
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+39
to
+43
| if test -z "$language"; then | ||
| for I in $root_dir/bindings/*; do | ||
| build_language $(basename $I) | ||
| done | ||
| } || { | ||
| else |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The scheduled Update API bindings workflow has been failing at the Generate bindings step with
exit code 127(run 30521202208).Two separate defects combined to produce it.
1. Codegen output was root-owned (the actual failure)
docker container runwrites into the bind-mountedbindings/<lang>/srcdirectory as the container's root user, so on Linux the generated files end up owned by root.scripts/fix-ruby-escaping.shusesruby -i(in-place edit), which must unlink the original file and therefore needs write permission on the containing directory, not just the file. That unlink failed:So the apostrophe fix was silently skipped and the following
ruby -creported the very syntax error it exists to prevent. Theuvx ruff check --fixpass at the end ofscripts/build.shwould have hit the same wall (it rewrote 67 files in a local run).This never reproduced locally because macOS bind mounts map container-root writes back to the host user — it only bites on Linux runners, which is why the first scheduled run surfaced it.
Fix: run the codegen container as the invoking user via
--user "$(id -u):$(id -g)", defined once ascodegen_run_userinscripts/common.sh.2. The real error was then masked as exit 127
scripts/build.shdispatched languages with the classicA && B || Cpitfall:When a per-language build failed, the
forloop returned non-zero, so the||branch ran with an empty$language— producing the confusing tail of the log:and replacing the genuine exit status with
127.Fix: a plain
if/else, so a failing language build propagates its own status.Verification
Can't remove ... Permission deniedwarning followed by theruby -csyntax error; passes once the directory is user-writable.swaggerapi/swagger-codegen-cli:v2.4.50generates correctly under--user.mise run buildnow completes end-to-end (exit 0), Ruby escaping applied to all 20*_upstream.rbmodels and verified withruby -c, ruff autofixes applied.PackageFileUploadRequestin java/python from genuine API movement since v1.1285.0; reverted here so this PR stays scoped to the CI fix — the next scheduled run will pick it up.)prek run --all-files: ruff and zizmor both pass.🤖 Generated with Claude Code