ai.robots.txt/.github/workflows/main.yml
Özden und Julia 4021a10239 Pass commit messages to bash via env, not template interpolation
`git commit -m "${{ github.event.head_commit.message }}"` splices arbitrary text
straight into a double-quoted bash string. A message containing a double quote
closes the string early and the remainder is re-parsed as shell words.

This is what broke main after #248 merged. That PR's title contained
"Unclear at this time." (with quotes), so the merge commit message did too, and
the line bash actually ran was:

    git commit -m "Fill "Unclear at this time." from primary operator docs ..."

which git received as:

    -m "Fill Unclear"  at  this  "time. from primary operator docs ..."

Hence `error: pathspec 'at' did not match any file(s) known to git`, a failed
run, and the revert in 80c19fc. The data in that PR was fine — robots.py
--convert exits 0 against it and code/tests.py passes 13/13.

The same interpolation is also a script-injection vector, which is the more
important reason to change it: a PR title is attacker-controlled, and

    chore: tidy"; <any command>; echo "

executes that command on the runner with the workflow's token. `inputs.message`
has the same shape in the `if [ -n ... ]` test and its own `git commit -m`, so
all three are moved.

Passing through `env:` and quoting the shell variable is GitHub's documented
recommendation for untrusted values. The variable is expanded by bash after
parsing, so quotes, newlines and `$(...)` stay literal text.

Verified: code/tests.py 13/13 · python code/robots.py --convert exits 0 and
leaves robots.txt, table-of-bot-metrics.md and every server-config output
byte-identical · reproduced both the parse failure and the injection locally
against the old form, and confirmed the env form commits the same message
verbatim, quotes included.
2026-08-04 09:09:10 +02:00

51 lines
1.5 KiB
YAML

on:
workflow_call:
inputs:
message:
type: string
required: true
description: The message to commit
push:
paths:
- 'robots.json'
- '.github/workflows/**'
- 'code/**'
branches:
- "main"
jobs:
ai-robots-txt:
runs-on: ubuntu-latest
name: ai-robots-txt
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- env:
INPUT_MESSAGE: ${{ inputs.message }}
HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
run: |
pip install beautifulsoup4
git config --global user.name "ai.robots.txt"
git config --global user.email "ai.robots.txt@users.noreply.github.com"
git log -1
git status
echo "Updating robots.txt and table-of-bot-metrics.md if necessary ..."
python code/robots.py --convert
echo "... done."
git --no-pager diff
git add -A
if [ -z "$(git diff --staged)" ]; then
# To have the action run successfully, if no changes are staged, we
# manually skip the later commits because they fail with exit code 1
# and this would then display as a failure for the Action.
echo "No staged changes to commit. Skipping commit and push."
exit 0
fi
if [ -n "$INPUT_MESSAGE" ]; then
git commit -m "$INPUT_MESSAGE"
else
git commit -m "$HEAD_COMMIT_MESSAGE"
fi
git push
shell: bash