The shellcheck step added earlier reads git ls-files '*.sh' — four files. It does not read inline run: blocks, and a good deal of this repo's bash lives there: release verification in build.yml, emulator setup and teardown in status_check.yml and api37-debug.yml. "shellcheck runs in CI" was true of the files and not of the blocks, and CLAUDE.md said so rather than pretending otherwise.
actionlint closes that half — it runs shellcheck over every run:, plus its own checks on expression syntax, needs: references, matrix keys and action inputs.
Pinned by digest, for two reasons
The first is the one shellcheck is pinned for: a new rule making untouched files fail is a red build whose diff can't explain it.
The second is specific to this tool — actionlint's documented install is bash <(curl -s .../download-actionlint.bash)off a moving branch. Running that in a repo that pins every action by SHA would contradict its own supply-chain posture more than the linter is worth. That's why #70 existed as a ticket instead of being bolted onto the shellcheck commit.
Its one finding is fixed, not suppressed
build.yml parsed ls to pick the release APK (SC2012). The glob was already in the line, so a bash array reads it without the pipe.
Proved it catches a plant
if [ $UNQUOTED = bad ]; then :; fi ← planted in a build.yml run: block
shellcheck reported issue in this script: SC2086:info:4:6:
Removed again afterwards. A linter that can't be shown to catch a plant isn't wired in, it's just running — and SC2086 inside a run: block is invisible to the .sh-file step, which is the whole argument for this change.
CLAUDE.md loses the "does not cover inline run: blocks" caveat, because it no longer does. Both linters verified clean at their pinned digests.
Closes #70.
The shellcheck step added earlier reads `git ls-files '*.sh'` — four files. It does **not** read inline `run:` blocks, and a good deal of this repo's bash lives there: release verification in `build.yml`, emulator setup and teardown in `status_check.yml` and `api37-debug.yml`. *"shellcheck runs in CI"* was true of the files and not of the blocks, and `CLAUDE.md` said so rather than pretending otherwise.
`actionlint` closes that half — it runs shellcheck over every `run:`, plus its own checks on expression syntax, `needs:` references, matrix keys and action inputs.
## Pinned by digest, for two reasons
The first is the one shellcheck is pinned for: a new rule making untouched files fail is a red build whose diff can't explain it.
The second is specific to this tool — actionlint's documented install is `bash <(curl -s .../download-actionlint.bash)` **off a moving branch**. Running that in a repo that pins every action by SHA would contradict its own supply-chain posture more than the linter is worth. That's why #70 existed as a ticket instead of being bolted onto the shellcheck commit.
## Its one finding is fixed, not suppressed
`build.yml` parsed `ls` to pick the release APK (**SC2012**). The glob was already in the line, so a bash array reads it without the pipe.
## Proved it catches a plant
```
if [ $UNQUOTED = bad ]; then :; fi ← planted in a build.yml run: block
shellcheck reported issue in this script: SC2086:info:4:6:
```
Removed again afterwards. **A linter that can't be shown to catch a plant isn't wired in, it's just running** — and SC2086 inside a `run:` block is invisible to the `.sh`-file step, which is the whole argument for this change.
`CLAUDE.md` loses the "does not cover inline `run:` blocks" caveat, because it no longer does. Both linters verified clean at their pinned digests.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #70.
The shellcheck step added earlier reads
git ls-files '*.sh'— four files. It does not read inlinerun:blocks, and a good deal of this repo's bash lives there: release verification inbuild.yml, emulator setup and teardown instatus_check.ymlandapi37-debug.yml. "shellcheck runs in CI" was true of the files and not of the blocks, andCLAUDE.mdsaid so rather than pretending otherwise.actionlintcloses that half — it runs shellcheck over everyrun:, plus its own checks on expression syntax,needs:references, matrix keys and action inputs.Pinned by digest, for two reasons
The first is the one shellcheck is pinned for: a new rule making untouched files fail is a red build whose diff can't explain it.
The second is specific to this tool — actionlint's documented install is
bash <(curl -s .../download-actionlint.bash)off a moving branch. Running that in a repo that pins every action by SHA would contradict its own supply-chain posture more than the linter is worth. That's why #70 existed as a ticket instead of being bolted onto the shellcheck commit.Its one finding is fixed, not suppressed
build.ymlparsedlsto pick the release APK (SC2012). The glob was already in the line, so a bash array reads it without the pipe.Proved it catches a plant
Removed again afterwards. A linter that can't be shown to catch a plant isn't wired in, it's just running — and SC2086 inside a
run:block is invisible to the.sh-file step, which is the whole argument for this change.CLAUDE.mdloses the "does not cover inlinerun:blocks" caveat, because it no longer does. Both linters verified clean at their pinned digests.