Files
openconcho/scripts/pr-evidence.sh
BenSheridanEdwards 86bb9d6be0 chore(hooks): pre-push gate, secret scan, pr:evidence drafter
Phase A of the quality-gate rollout — local + pre-push gates that stop
slop before it leaves the laptop. Preventative controls, per the
architect playbook.

- .husky/pre-commit — adds scripts/secret-scan.sh as the first check
  before the existing Biome format/lint. Blocks the commit when a
  likely secret is found in staged additions. Existing Biome behaviour
  is preserved.
- .husky/pre-push (new) — runs `pnpm check` (lint + typecheck + test)
  before the branch leaves the laptop. Mirrors the `check` job in
  .github/workflows/ci.yml so PR-blocking issues surface locally first.
  Bypassable for genuine emergencies with `git push --no-verify`.
- scripts/secret-scan.sh (new) — regex scan over staged additions for
  the common accidents: AWS keys, Anthropic/OpenAI/GitHub/Slack/Google/
  Stripe tokens, JWTs, PEM private key blocks, hardcoded password
  literals. Validated against synthetic leaks of each type. No external
  tool dependency — pure bash + grep, runs in <100ms typical.
- scripts/pr-evidence.sh (new) — drafts a PR_BODY.md from the diff vs
  origin/main: file lists (added/modified/deleted), commit summaries,
  and the QA checklist. Flags screenshots as REQUIRED when the diff
  touches packages/web/src/{components,routes} or packages/desktop.
  Wired as `pnpm pr:evidence` so it runs from anywhere in the
  workspace.
- .gitignore — adds PR_BODY.md so drafts don't get committed by
  accident.

Pre-commit stays fast (<2s typical). Heavy checks (typecheck, full
test run) live in pre-push.
2026-05-28 14:01:20 -05:00

117 lines
4.0 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# Draft a PR body for the current branch based on the diff vs origin/main.
#
# Writes to PR_BODY.md in the repo root (gitignored — see end of script).
# Pre-fills the structure required by .github/pull_request_template.md
# and flags whether screenshots are required based on touched paths.
#
# Usage:
# ./scripts/pr-evidence.sh # writes ./PR_BODY.md
# ./scripts/pr-evidence.sh > /tmp/body.md # write to stdout
set -euo pipefail
OUTPUT="${1:-PR_BODY.md}"
# Find the base branch (default origin/main) the current branch diverged from.
BASE_REF="${BASE_REF:-origin/main}"
git fetch origin main --quiet 2>/dev/null || true
MERGE_BASE=$(git merge-base HEAD "$BASE_REF" 2>/dev/null || echo "$BASE_REF")
CHANGED=$(git diff --name-only "$MERGE_BASE"...HEAD)
ADDED=$(git diff --name-status --diff-filter=A "$MERGE_BASE"...HEAD | awk '{print $2}')
MODIFIED=$(git diff --name-status --diff-filter=M "$MERGE_BASE"...HEAD | awk '{print $2}')
DELETED=$(git diff --name-status --diff-filter=D "$MERGE_BASE"...HEAD | awk '{print $2}')
# Heuristic: any touched path under packages/web/src/{components,routes} or
# packages/desktop counts as a UI change and requires screenshots.
UI_CHANGED=0
if echo "$CHANGED" | grep -qE '^(packages/web/src/(components|routes)|packages/desktop)/'; then
UI_CHANGED=1
fi
# Commits since base — useful for the "What" section.
COMMITS=$(git log --pretty=format:'- %s' "$MERGE_BASE"..HEAD)
# Tests touched?
TESTS_TOUCHED=$(echo "$CHANGED" | grep -E '(\.test\.|/test/|/e2e/)' || true)
BRANCH=$(git rev-parse --abbrev-ref HEAD)
draft() {
cat <<EOF
<!--
Auto-drafted by scripts/pr-evidence.sh from the diff vs ${BASE_REF}.
Fill in the prose sections; the file lists and checklist are pre-populated.
-->
## Why
<!-- The problem this solves, in 13 sentences. What pain or gap does this close? -->
## What
$(if [ -n "$COMMITS" ]; then printf 'Commits on this branch:\n%s\n' "$COMMITS"; else echo '<!-- describe the change -->'; fi)
$(if [ -n "$ADDED" ]; then printf '\n**Added:**\n'; printf '%s\n' "$ADDED" | sed 's/^/- /'; fi)
$(if [ -n "$MODIFIED" ]; then printf '\n**Modified:**\n'; printf '%s\n' "$MODIFIED" | sed 's/^/- /'; fi)
$(if [ -n "$DELETED" ]; then printf '\n**Deleted:**\n'; printf '%s\n' "$DELETED" | sed 's/^/- /'; fi)
## Screenshots
EOF
if [ $UI_CHANGED -eq 1 ]; then
cat <<EOF
**Required** — this PR touches packages/web/src/{components,routes} or packages/desktop.
Commit screenshots under \`docs/screenshots/<feature-slug>/\` and reference here:
\`\`\`markdown
![Description](https://raw.githubusercontent.com/BenSheridanEdwards/openconcho/${BRANCH}/docs/screenshots/<feature-slug>/01-<state>.png)
\`\`\`
See \`.claude/rules/workflows.md\` → "Open a PR" for capture + commit guidance.
EOF
else
cat <<EOF
<!-- No packages/web/src/{components,routes} or packages/desktop paths touched —
screenshots not strictly required. Delete this section if truly docs-only. -->
EOF
fi
cat <<EOF
## QA checklist
- [ ] \`pnpm typecheck\` clean locally
- [ ] \`pnpm lint\` clean locally
- [ ] \`pnpm test\` green locally
$(if [ -n "$TESTS_TOUCHED" ]; then echo '- [x] Tests touched on this branch:'; printf '%s\n' "$TESTS_TOUCHED" | sed 's/^/ - /'; else echo '- [ ] Tests added for new behaviour (or note why none are needed)'; fi)
- [ ] Manual verification: <!-- which Honcho instance, which workspace/peer, what you clicked, what you saw -->
$(if echo "$CHANGED" | grep -qE '^packages/desktop/'; then echo '- [ ] \`pnpm --filter @openconcho/desktop cargo-check\` passes'; fi)
- [x] Worked in a git worktree (current branch: \`${BRANCH}\`)
## Out-of-scope
<!-- What was intentionally left out and why. -->
## Notes
<!-- Caveats, follow-ups, anything reviewers should know. -->
EOF
}
if [ "$OUTPUT" = "-" ] || [ -t 1 ]; then
# When piped or first arg is "-", write to stdout.
if [ "${1:-}" = "-" ]; then
draft
exit 0
fi
fi
draft > "$OUTPUT"
echo "✓ Drafted PR body → ${OUTPUT}"
echo " Open it, fill in Why / Manual verification / Out-of-scope / Notes, then use as the PR body."