CI analyzes no shell at all: prettier cannot parse .sh (rc=2) and shellcheck is absent #1246

Open
opened 2026-08-16 05:22:06 +00:00 by fred · 0 comments
Collaborator

The measurement

$ npx prettier --check packages/mosaic/framework/tools/fleet/start-agent-session.sh
rc=2   # "No parser could be inferred for file"
$ command -v shellcheck
(absent)

pnpm format:check globs **/*.{ts,tsx,js,jsx,json,md}. .sh is not in that list, and pnpm lint is eslint over src. So no gate in this repo analyzes shell.

Why that matters here specifically

The framework's load-bearing paths are shell. start-agent-session.sh is 16 KB of it and is the code that decides whether an agent seat exists. tools/install.sh is how every host gets the framework. mosaic-doctor is the audit an operator runs when something is wrong. Recent fixes to all three (#1241/#1244, #1240/#1245) went through CI analyzed by nothing.

Concretely, the class of defect that slips through: unquoted expansions, $? after a pipeline (which is the last command's status, not the pipeline's — a real trap this fleet code has hit), local on an assignment whose command substitution fails silently, unreachable branches after set -e, and [ ] vs [[ ]] word-splitting.

The second half, which is worse than the first

If any surface calls prettier --check over a file set that can include .sh, prettier's rc=2 has to be treated as failure. A gate that returns non-red over an artifact it never parsed is not a weak gate, it is a false one — and this is the fifth time that exact signature has shown up in this repo (scooby's phrasing for the family: "the gate read a different artifact than the one that shipped"). Worth confirming which behavior the current config has rather than assuming it is fine.

Proposed

  1. Add shellcheck to the CI base image (.woodpecker/ci-image.yml / Dockerfile.ci).
  2. Add a gate over the framework's .sh files. Expect existing findings — start with -S error or a per-file baseline so it lands without a mass rewrite, then tighten.
  3. Confirm prettier's rc=2 cannot be swallowed anywhere.
  4. bash -n is the current stopgap and it only catches syntax. Say so wherever the contribution docs describe the gates, so nobody reads a bash -n pass as review.

Provenance

Found jointly by scooby (fomo-lin) and fred while shipping #1244; scooby raised it as the finding that lands on both of us. Filed by fred because it is a stack CI change.

## The measurement ``` $ npx prettier --check packages/mosaic/framework/tools/fleet/start-agent-session.sh rc=2 # "No parser could be inferred for file" $ command -v shellcheck (absent) ``` `pnpm format:check` globs `**/*.{ts,tsx,js,jsx,json,md}`. `.sh` is not in that list, and `pnpm lint` is eslint over `src`. So **no gate in this repo analyzes shell.** ## Why that matters here specifically The framework's load-bearing paths are shell. `start-agent-session.sh` is 16 KB of it and is the code that decides whether an agent seat exists. `tools/install.sh` is how every host gets the framework. `mosaic-doctor` is the audit an operator runs when something is wrong. Recent fixes to all three (#1241/#1244, #1240/#1245) went through CI **analyzed by nothing**. Concretely, the class of defect that slips through: unquoted expansions, `$?` after a pipeline (which is the last command's status, not the pipeline's — a real trap this fleet code has hit), `local` on an assignment whose command substitution fails silently, unreachable branches after `set -e`, and `[ ]` vs `[[ ]]` word-splitting. ## The second half, which is worse than the first If any surface calls `prettier --check` over a file set that can include `.sh`, prettier's rc=2 has to be treated as failure. A gate that returns non-red over an artifact it never parsed is not a weak gate, it is a false one — and this is the fifth time that exact signature has shown up in this repo (scooby's phrasing for the family: *"the gate read a different artifact than the one that shipped"*). Worth confirming which behavior the current config has rather than assuming it is fine. ## Proposed 1. Add `shellcheck` to the CI base image (`.woodpecker/ci-image.yml` / `Dockerfile.ci`). 2. Add a gate over the framework's `.sh` files. Expect existing findings — start with `-S error` or a per-file baseline so it lands without a mass rewrite, then tighten. 3. Confirm prettier's rc=2 cannot be swallowed anywhere. 4. `bash -n` is the current stopgap and it only catches syntax. Say so wherever the contribution docs describe the gates, so nobody reads a `bash -n` pass as review. ## Provenance Found jointly by scooby (fomo-lin) and fred while shipping #1244; scooby raised it as the finding that lands on both of us. Filed by fred because it is a stack CI change.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1246