Skip to content

fix: unbreak the scheduled binding-update workflow (exit 127) - #97

Merged
cloudsmith-iduffy merged 1 commit into
masterfrom
fix/binding-build-permissions
Jul 30, 2026
Merged

fix: unbreak the scheduled binding-update workflow (exit 127)#97
cloudsmith-iduffy merged 1 commit into
masterfrom
fix/binding-build-permissions

Conversation

@cloudsmith-iduffy

Copy link
Copy Markdown
Contributor

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 run writes into the bind-mounted bindings/<lang>/src directory as the container's root user, 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, not just the file. That unlink failed:

-e:1: warning: Can't remove .../models/helm_upstream.rb: Permission denied, skipping file
ruby: .../models/helm_upstream.rb:308: syntax errors found (SyntaxError)

So the apostrophe fix was silently skipped and the following ruby -c reported the very syntax error it exists to prevent. The uvx ruff check --fix pass at the end of scripts/build.sh would 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 as codegen_run_user in scripts/common.sh.

2. The real error was then masked as exit 127

scripts/build.sh dispatched languages with the classic A && B || C pitfall:

test -z "$language" && {
  for I in $root_dir/bindings/*; do build_language $(basename $I); done
} || {
  build_language $language
}

When a per-language build failed, the for loop returned non-zero, so the || branch ran with an empty $language — producing the confusing tail of the log:

./scripts/build.sh: line 36: .../bindings//build.sh: No such file or directory
Building  bindings ...

and replacing the genuine exit status with 127.

Fix: a plain if/else, so a failing language build propagates its own status.

Verification

  • Reproduced defect 2 in isolation and confirmed the fix makes the real exit status propagate instead of the bogus empty-language branch.
  • Reproduced defect 1's mechanism with a non-writable models directory — byte-identical Can't remove ... Permission denied warning followed by the ruby -c syntax error; passes once the directory is user-writable.
  • Confirmed swaggerapi/swagger-codegen-cli:v2.4.50 generates correctly under --user.
  • mise run build now completes end-to-end (exit 0), Ruby escaping applied to all 20 *_upstream.rb models and verified with ruby -c, ruff autofixes applied.
  • Regenerating produced a zero diff against the committed Ruby bindings, confirming the escaping fix is idempotent. (The only drift was PackageFileUploadRequest in 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

…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>
Copilot AI review requested due to automatic review settings July 30, 2026 21:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 || C construct with an if/else in scripts/build.sh so 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 -v argument parsing and could cause codegen to write to the wrong location. Quote the -v value (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 -v argument parsing and could cause codegen to write to the wrong location. Quote the -v value (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 -v argument parsing and could cause codegen to write to the wrong location. Quote the -v value (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 thread scripts/build.sh
Comment on lines +39 to +43
if test -z "$language"; then
for I in $root_dir/bindings/*; do
build_language $(basename $I)
done
} || {
else
@cloudsmith-iduffy
cloudsmith-iduffy merged commit 4e9e27a into master Jul 30, 2026
10 checks passed
@cloudsmith-iduffy
cloudsmith-iduffy deleted the fix/binding-build-permissions branch July 30, 2026 21:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants