Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
5cd4486
fix(review-cycle): make Copilot CLI step non-optional + document auth…
willgriffin May 22, 2026
cf96d99
fix(review-cycle): add hard rules for loop convergence
willgriffin May 22, 2026
4fc975e
fix(review-cycle): exit on P3/nit-only — don't loop on trivia
willgriffin May 22, 2026
768f502
fix(review-cycle): clarify P3 triage — fix inline, record, or follow up
willgriffin May 22, 2026
e65e9a7
fix(review-cycle): address pr-review round-1 findings on this PR
willgriffin May 22, 2026
da2bd1a
fix(review-cycle): round-2 — correct Copilot --allow-tool syntax + St…
willgriffin May 22, 2026
badf1e7
fix(review-cycle): round-3 — workflow contract repairs
willgriffin May 22, 2026
2dbe20b
fix(review-cycle,ship): round-4 — accepted-P2 stop condition + ship h…
willgriffin May 22, 2026
1fc8677
fix(review-cycle,ship): round-5 — remove leaked transcripts, fix
willgriffin May 22, 2026
a8067f7
fix(review-cycle,ship): round-6 — security gap + workflow contract fixes
willgriffin May 22, 2026
ab01756
fix(review-cycle): round-7 — fully scope Copilot path access + narrow…
willgriffin May 22, 2026
876319b
revert(review-cycle): walk back wrong-threat-model security overspec
willgriffin May 22, 2026
9be0cf5
docs(review-cycle,ship): rename codex/claude/copilot → *-cli everywhere
willgriffin May 22, 2026
f3a11a5
fix(ci): allow multi-scope and slash in commit scope + escape commit …
willgriffin May 23, 2026
d9db0cf
fix(review-cycle): one reviewer clean ≠ ensemble convergence
willgriffin May 23, 2026
4714ea3
fix(review-cycle,ci): round-1 — close 3 ensemble findings on PR #5
willgriffin May 23, 2026
d17b7f4
fix(review-cycle,ship): round-2 — close 3 ensemble findings + 1 self-…
willgriffin May 23, 2026
1dd7688
fix(review-cycle,ship,ci): round-3 — close 6 of 8 ensemble findings (…
willgriffin May 23, 2026
d81ed7d
fix(review-cycle,ship,ci): round-4 — 4 ensemble findings (4 reviewers…
willgriffin May 23, 2026
6248006
fix(review-cycle,ship): round-5 — 5 of 6 ensemble findings (4 reviewers)
willgriffin May 23, 2026
1cdffc9
fix(review-cycle,ship): round-6 — 7 ensemble findings (4 reviewers, n…
willgriffin May 23, 2026
4c8256e
fix(review-cycle): round-7 — 6 ensemble findings, slot model + bias c…
willgriffin May 23, 2026
c0d577d
fix(review-cycle,ship): round-8 — 6 ensemble findings (1 medium real …
willgriffin May 23, 2026
4ad6360
fix(review-cycle,ship): round-9 — 4 ensemble findings, 1 reject (4 re…
willgriffin May 23, 2026
3a371db
fix(review-cycle): round-10 — delete WIP recipe entirely (5 reviewers…
willgriffin May 23, 2026
2161b86
fix(review-cycle): round-11 — fix shell injection in snapshot recipe …
willgriffin May 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 38 additions & 3 deletions .github/workflows/commitlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ on:
types: [opened, synchronize, reopened]

permissions:
# Only contents:read is needed — the job does `actions/checkout`
# + `git log` over commit SHAs from the event payload. No PR API
# calls or PR metadata reads, so `pull-requests:read` would be
# dead scope. Per least-privilege, drop it.
contents: read
pull-requests: read

jobs:
commitlint:
Expand All @@ -27,17 +30,49 @@ jobs:
# GitHub Actions injection-defense guidance.
COMMITS=$(git log --format=%s "$BASE_SHA".."$HEAD_SHA")

# Escape `%`, CR, LF in user-controlled commit messages
# before printing inside `::error::` workflow commands. Per
# GitHub's workflow-commands docs, unescaped event-payload
# strings can corrupt the command payload or inject
# additional workflow commands via `%`, `\r`, or `\n` in
# the source string.
escape_wc() {
local s="$1"
s="${s//%/%25}"
s="${s//$'\r'/%0D}"
s="${s//$'\n'/%0A}"
printf '%s' "$s"
}

FAILED=0
while IFS= read -r msg; do
[[ -z "$msg" ]] && continue
# Allow merge commits
if [[ "$msg" =~ ^Merge\ ]]; then
continue
fi
if ! echo "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\([a-z0-9-]+\))?!?: .+'; then
echo "::error::Invalid commit message: $msg"
# Scope grammar:
# scope = segment ("," segment)*
# segment = "@"? alpha-run ( ("/" | "-") alpha-run )*
# alpha-run = [a-z0-9]+
# Each comma-separated segment is:
# - optional leading "@" (for scoped npm packages like
# "@happyvertical/sql")
# - one or more alphanumeric runs separated by single
# "/" or "-" characters (no repeated separators like
# "a//b" or "a--b", no trailing separators like "a/"
# or "a-", no leading separators after the optional "@")
# Examples that pass: fix(release), fix(review-cycle,ship),
# chore(tibdex/github-app-token), feat(@happyvertical/sql)
# Examples that fail: fix(a,), fix(a/), fix(a-), fix(a,,b),
# fix(a//b), fix(a--b), fix(,b), fix(/foo), fix(Foo),
# fix(have:review-cycle)
if ! printf '%s' "$msg" | grep -qE '^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\(@?[a-z0-9]+([/-][a-z0-9]+)*(,@?[a-z0-9]+([/-][a-z0-9]+)*)*\))?!?: .+'; then
msg_escaped=$(escape_wc "$msg")
echo "::error::Invalid commit message: $msg_escaped"
echo " Expected format: type(scope?): subject"
echo " Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert"
echo " Scope chars: alphanumeric, hyphen, comma (multi-scope), forward slash (e.g. dep names), optional leading @ (scoped npm packages)"
FAILED=1
fi
done <<< "$COMMITS"
Expand Down
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,31 @@
*.swp
*.swo
node_modules/

# Copilot CLI session transcripts can leak into the working dir if
# probe prompts reference filenames. Per `gh copilot -- --help`:
# - `--share[=path]` writes `copilot-session-<id>.md` (markdown) in
# cwd by default
# - `--output-format json` writes JSONL to stdout (not a file)
# - `--log-dir <dir>` defaults to `~/.copilot/logs/` (outside repo)
#
# We ignore both `.md` (the current documented file leak vector
# from `--share`) and `.jsonl` (for any future CLI version that
# writes session output as JSONL to a file).
#
# NOTE: These narrow patterns DO NOT cover the prior 1fc8677
# incident filenames (`.deny-test.jsonl`, `.revparse-test.jsonl`),
# which came from internal Copilot tool-permission probes that
# don't match `copilot-session-*`. A wildcard like `*-test.jsonl`
# would catch them but would also hide legitimate fixtures
# (e.g. `fixtures/payment-test.jsonl`) — the round-7 walkback
# (commit ab01756) chose narrow-correct over broad-defense.
#
# The PRIMARY prevention is the review-cycle docs' rule: review
# outputs go to /tmp, not the repo. These patterns catch only the
# documented `copilot-session-*` file shapes; for arbitrary
# Copilot-internal probe filenames the structural defense is /tmp.
copilot-session-*.md
.copilot-session-*.md
copilot-session-*.jsonl
.copilot-session-*.jsonl
Loading