🐛 docker-build: quote the bake metadata heredoc - #7449
Merged
GeigerJ2 merged 1 commit intoJul 16, 2026
Conversation
The `Write metadata output to a json file` step pipes the bake metadata
through an unquoted heredoc:
cat << EOF > bake_metadata.json
${{ steps.build.outputs.metadata }}
EOF
GitHub substitutes the metadata textually, and the shell then expands
what it finds. That metadata embeds the git commit message, so every
backtick in a commit message is treated as command substitution and its
contents are eaten:
in: {"message":"Rename from `zmq_broker_service` to
`broker_service`."} out: {"message":"Rename from to ."}
With enough backticks the substitution runs past a string terminator and
the pretty-printed JSON's real newlines end up inside a string literal,
so the following `github-script` step dies on
SyntaxError: Bad control character in string literal in JSON
This is not hypothetical: the repository's own commit convention is
``<emoji> `Scope`: description``, so conventional commit messages are
exactly the ones that break the build. `Docker Images` has been red on
`main` since aiidateam#7444, and again for aiidateam#7254.
Quote the delimiter so the shell leaves the payload alone. `${{ }}` is
GitHub-side templating and still expands, so only the shell expansion is
suppressed.
📝 WalkthroughWalkthroughThe Docker build workflow now uses a single-quoted heredoc delimiter when writing ChangesDocker metadata generation
Estimated code review effort: 1 (Trivial) | ~2 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7449 +/- ##
==========================================
- Coverage 80.61% 80.60% -0.00%
==========================================
Files 580 580
Lines 46722 46722
==========================================
- Hits 37658 37657 -1
- Misses 9064 9065 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| - name: Write metadata output to a json file | ||
| run: | | ||
| cat << EOF > bake_metadata.json | ||
| cat << 'EOF' > bake_metadata.json |
Collaborator
There was a problem hiding this comment.
huh, TIL, had no idea that such quoting works
Collaborator
Author
There was a problem hiding this comment.
Me neither, agent proposed 😉
danielhollas
added a commit
to aiidalab/aiidalab-docker-stack
that referenced
this pull request
Jul 22, 2026
Same change as was done in aiidateam/aiida-core#7449, see that PR for details. Notably, the metadata's buildx.build.provenance embeds the push event payload, commit messages included, so every backtick in a commit message is treated as command substitution!
agoscinski
pushed a commit
that referenced
this pull request
Jul 25, 2026
(cherry picked from commit c04d915)
agoscinski
pushed a commit
that referenced
this pull request
Jul 25, 2026
(cherry picked from commit c04d915)
agoscinski
pushed a commit
that referenced
this pull request
Jul 25, 2026
(cherry picked from commit c04d915)
agoscinski
pushed a commit
to agoscinski/aiida-core
that referenced
this pull request
Jul 31, 2026
agoscinski
pushed a commit
to agoscinski/aiida-core
that referenced
this pull request
Jul 31, 2026
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
Write metadata output to a json filestep pipes the bake metadata through an unquoted heredoc:GitHub substitutes the metadata textually, and the shell then expands what it finds. The metadata's
buildx.build.provenanceembeds the push event payload, commit messages included, so every backtick in a commit message is treated as command substitution: its contents run on the runner and vanish from the JSON.This is not hypothetical: our own commit convention is
<emoji> `Scope`: description, so conventional commit messages are exactly the ones this mangles. It had been corrupting the recorded metadata silently for a while. #7444 is the example above, and it still produced parseable JSON, so nothing went red and nobody noticed. #7254's message carries 26 backticks, enough for the substitution to run past a string terminator and leave the pretty-printed JSON's real newlines inside a string literal, so the followinggithub-scriptstep died onand
Docker Imageshas been red onmainsince. (The earlier red run on #7444 was an unrelated arm64ports.ubuntu.comtimeout.)Quote the delimiter so the shell leaves the payload alone.
${{ }}is GitHub-side templating and still expands, so only the shell expansion is suppressed. Incidentally this also closes a script-injection path, since commit messages reachingbashis exactly that, though a fork PR can't reach this workflow and anyone who can get a commit ontomaincan already run code in CI, so the practical gain is mostly that the metadata is no longer silently corrupted.Reproducing the mangling outside CI
The payload has to be inlined textually the way GitHub does it, before
bashsees the script (passing it via a shell variable hides the bug, since that is the expansion the fix suppresses):Swapping in
<< 'EOF'preserves the message byte for byte.