Skip to content

feat(scripts): add consumer-side handoff queue front-matter validator - #2444

Merged
kyle-sexton merged 1 commit into
mainfrom
cursor/queue-front-matter-check-5aad
Aug 12, 2026
Merged

feat(scripts): add consumer-side handoff queue front-matter validator#2444
kyle-sexton merged 1 commit into
mainfrom
cursor/queue-front-matter-check-5aad

Conversation

@kyle-sexton

@kyle-sexton kyle-sexton commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds scripts/check-queue-front-matter.sh — a repo-agnostic consumer validator for file-based markdown handoff queues outside the repo.

Behavior

  • Validates required keys (id, title, status, created, producer)
  • status must be in unclaimed|claimed|in-progress|blocked|done
  • Optional priority checked when present
  • id must match the filename stem
  • Prints file count vs parseable front-matter count so reconciling by grep '^status:' cannot false-clear malformed items

Decision brief (#1647)

RECOMMENDED: Build now in scripts/ rather than waiting for the work-items custom adapter — live false-all-clear today, cheap script, logic can migrate later.

Not wired to CI (queue is out-of-repo). Invoke at claim time.

Closes #1647.

Related

N/A

Implements scripts/check-queue-front-matter.sh per #1647: validates
required keys, documented status/priority sets, id/filename stem match,
and prints file-count vs parseable-front-matter reconciliation so a
status grep cannot report a false all-clear.

Decision: land in scripts/ now (not wait for work-items adapter).

Closes #1647.

Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ca740b5a4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-queue-front-matter.sh
Comment thread scripts/check-queue-front-matter.sh
Comment thread scripts/check-queue-front-matter.sh
@github-actions github-actions Bot deleted a comment from claude Bot Aug 12, 2026
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 1m 18s —— View job


Security Review

  • Gather context (PR diff, changed files)
  • Review scripts/check-queue-front-matter.sh for security issues
  • Review scripts/check-queue-front-matter.test.sh for security issues
  • Post findings

Scope: This PR adds two new shell scripts only — scripts/check-queue-front-matter.sh (validator) and scripts/check-queue-front-matter.test.sh (unit tests). No workflow files, CI wiring, or existing files are touched, so the GitHub Actions-specific risk categories (pull_request_target/workflow_run misuse, github context script injection in run: blocks, permissions: widening) don't apply here.

No security issues found.

Specifically checked and ruled out:

  • Command/shell injection — all variable expansions are quoted consistently ("$item", "$fm", "$1", "$status", etc.). Untrusted front-matter values (status, priority, id, title, producer) are only ever used as the subject of grep/string comparisons, never interpolated into a command, pattern, or eval'd — e.g. grep -qE "^(${VALID_STATUSES})$" <<<"$status" builds the pattern from the fixed VALID_STATUSES constant, not from queue-file content.
  • Format-string injection — all printf calls use fixed format strings with values passed positionally as %s/%d args (e.g. report_violation), so front-matter content containing % sequences can't alter output behavior.
  • awk injectionfm_value passes the key via -v key="$2" (safe awk variable binding) rather than string-interpolating it into the program text (L50-L58).
  • Path traversal — queue items are discovered via a glob ("$QUEUE_DIR"/*.md) rather than following any attacker-influenced path components from file content; $QUEUE_DIR itself is an operator-supplied CLI arg, not remote/untrusted input.
  • Secrets/credentials handling — none present; the script only reads local markdown files and prints validation results to stdout/stderr.
  • Test script — uses mktemp -d for isolated fixtures and quoted heredocs; no eval, no injection surface.

One minor, non-blocking observation (not flagging as a finding since it requires an attacker who already has write access to the queue directory, at which point they have much larger attack surface): the script follows symlinks when globbing *.md, so a queue directory containing a symlink such as evil.md -> /etc/shadow would have its target's contents fed through awk/grep and potentially echoed back in violation messages. Given this is an explicitly local, non-CI, operator-invoked tool over a directory the operator already controls, this isn't an exploitable trust-boundary crossing in practice.

@kyle-sexton
kyle-sexton merged commit 074880d into main Aug 12, 2026
37 of 38 checks passed
@kyle-sexton
kyle-sexton deleted the cursor/queue-front-matter-check-5aad branch August 12, 2026 12:48
@claude

claude Bot commented Aug 12, 2026

Copy link
Copy Markdown

Claude finished @kyle-sexton's task in 6m 25s —— View job


Review complete

  • Gather context (PR diff, CLAUDE.md, REVIEW.md)
  • Review scripts/check-queue-front-matter.sh
  • Review scripts/check-queue-front-matter.test.sh
  • Post findings

This repo has a .github/workflows/claude-security-review.yml workflow, so per REVIEW.md this lane owns everything except security (correctness, design, error handling, tests, maintainability) — no security findings reported here.

Note: CLAUDE.md and .claude-pr/CLAUDE.md are both empty in this checkout, so there were no repo-specific conventions to check against beyond what's inferable from sibling scripts/check-*.sh files.

Posted 3 inline findings:

  1. scripts/check-queue-front-matter.sh (Important)fm_value() only strips leading whitespace after the colon, not trailing. A value with a trailing space (or \r on a CRLF-terminated file) causes false-positive violations in the status enum check, priority enum check, and the id-vs-filename-stem check — the exact opposite of what this script exists to prevent (a wrong reading of queue state).
  2. scripts/check-queue-front-matter.test.sh (Important) — this test file isn't wired into CI anywhere. scripts/run-plugin-tests.sh only discovers tests under plugins/ and .claude/hooks/, and every sibling scripts/check-*.test.sh compensates with an explicit step in .github/workflows/ci.yml — this one has none. The PR's rationale for not wiring the checker into CI (out-of-repo queue) doesn't apply to the fully self-contained unit tests.
  3. scripts/check-queue-front-matter.test.sh (Suggestion) — no test exercises an individual missing key (vs. wholesale-missing front matter), an invalid priority, or — most notably — the reconciliation-count output/violation that is this PR's headline fix for handoff-queue: consumer-side front-matter validator (a status grep reports a false all-clear on a malformed item) #1647.

Everything else in the script read cleanly: the required-key/status/priority/id checks avoid the classic grep '^status:'-style false-clear the PR is fixing, the main loop correctly avoids the subshell-variable-loss pitfall (no find | while read), and exit codes (0/1/2) match the documented contract.

I reviewed by reading the code; this session's Bash tool wouldn't let me actually execute the scripts (blocked at the permission layer), so the findings above are static-analysis-based, not test-run-confirmed — worth a quick manual check of finding #1 before merge if there's any doubt.

Comment on lines +50 to +58
fm_value() {
awk -v key="$2" '
$1 == key ":" {
sub(/^[^:]*:[[:space:]]*/, "")
print
exit
}
' <<<"$1"
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important — trailing whitespace on a value causes false-positive violations.

sub(/^[^:]*:[[:space:]]*/, "") only strips the leading key: portion; it leaves any trailing whitespace on the line untouched (e.g. a stray trailing space, or a \r if the item file happens to be CRLF-terminated).

That trailing whitespace survives into every comparison that isn't itself whitespace-tolerant:

  • status '$status' enum check at line 82status: unclaimed (trailing space) fails ^(unclaimed|...)$ and is wrongly reported as an invalid status.
  • priority enum check at line 89 — same failure mode.
  • id vs filename-stem check at line 95id: 20260812-sample would be reported as a mismatch against stem 20260812-sample even though they're the same id.

The "missing required key" check at line 75 happens to be immune (it strips all whitespace before testing emptiness), which is likely why this wasn't caught by hand-testing.

A one-line fix in fm_value (e.g. also trimming trailing [[:space:]]*$ in the sub, or piping through something that trims both ends) would remove this whole class of false positive — which matters here specifically because the script's stated purpose is to avoid false readings of queue state.

Fix this →

Comment on lines +1 to +6
#!/usr/bin/env bash
# Unit tests for check-queue-front-matter.sh.
set -uo pipefail

SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="$SELF_DIR/check-queue-front-matter.sh"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Important — this test suite doesn't appear to run anywhere.

scripts/run-plugin-tests.sh only discovers plugins/**/*.test.sh and .claude/hooks/*.test.sh (mapfile -t tests < <(find plugins .claude/hooks -type f -name '*.test.sh' ...)), so it never picks up scripts/*.test.sh. Every other scripts/check-*.sh in this repo compensates by getting an explicit run: bash scripts/<name>.test.sh step added to .github/workflows/ci.yml (see e.g. check-silent-skips.test.sh, check-plugin-manifest-presence.test.sh, check-orphaned-fixtures.test.sh). I couldn't find check-queue-front-matter anywhere in .github/workflows/, so this 107-line test file has no CI step invoking it.

The PR's decision brief says the checker itself is intentionally "not wired to CI" because the queue lives outside the repo — but that reasoning doesn't extend to the unit tests: they're fully self-contained (each test does its own mktemp -d and doesn't touch anything outside the repo), just like the sibling tests that do run in CI. As written, a future regression in check-queue-front-matter.sh's parsing logic wouldn't be caught automatically.

Fix this →

Comment on lines +100 to +107
if run_check "$q" >/dev/null 2>&1; then
ok "README.md ignored"
else
fail "README should be ignored: valid sole item should pass"
fi

printf '\n%d passed, %d failed\n' "$PASS" "$FAIL"
[[ "$FAIL" -eq 0 ]]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion — coverage gaps relative to the checker's own logic.

The five cases here (valid item, wholesale-missing front matter, bad status, id/stem mismatch, README skip) all just assert pass/fail via exit status. A few things the checker does aren't exercised by any case:

  • No test for an individual missing required key (title/created/producer) when front matter otherwise parses — only "front matter entirely absent" is covered.
  • No test for an out-of-set priority value (the optional-key branch at check-queue-front-matter.sh:87-92).
  • No test asserting the Reconciliation: %d item file(s), %d with parseable front matter line/count-gap violation (check-queue-front-matter.sh:100-106) — this is the PR's headline fix for the "grep '^status:' false all-clear" problem (handoff-queue: consumer-side front-matter validator (a status grep reports a false all-clear on a malformed item) #1647), but nothing here verifies the counts are actually reported correctly for a mixed queue (some valid items + some with no front matter at all).

None of these are required for the PR to be correct, but since this suite won't run in CI yet (see the other comment on this file) and the checker's core value proposition is exactly the reconciliation-count behavior, it'd be worth locking that down with a test before it can silently regress.

@github-actions

Copy link
Copy Markdown

Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

handoff-queue: consumer-side front-matter validator (a status grep reports a false all-clear on a malformed item)

2 participants