fix(check): derive scoped-executor scan set from filesystem (dead guard)#208
Conversation
check-no-destructive-actions.ts hardcoded a SCAN_FILES entry for a removed executor, so readFileSync threw ENOENT and the FR-009 guard crashed before validating anything. Derive the scoped-executor set from the filesystem (scoped-*-executor.ts under src/daemon) so it cannot go stale, fail closed on convention drift, and wire check:no-destructive into ci.yml so the guard is actually enforced. Closes #203 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 45 minutes and 33 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe PR fixes a crash in the ChangesDynamic Scoped-Executor Discovery and Enforcement
🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Restores the FR-009 destructive-action safety guard by removing a stale hard-coded executor list and deriving the scoped-executor scan set from the filesystem, then enforces the guard in CI to prevent future “dead guard” regressions.
Changes:
- Update
check-no-destructive-actionsto discoversrc/daemon/scoped-*-executor.tsfiles dynamically and fail closed on convention drift. - Add an end-to-end test suite exercising fixture repos plus a real-repo regression run.
- Wire
bun run check:no-destructiveinto the CI workflow and sync related documentation.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/check-no-destructive-actions.ts |
Derives scoped executor scan targets from src/daemon and updates the guard’s reporting. |
test/scripts/check-no-destructive-actions.test.ts |
Adds regression + fixture-based coverage for the guard’s behavior and failure modes. |
.github/workflows/ci.yml |
Enforces the destructive-action guard in CI via a dedicated step. |
docs/use/safety.md |
Updates safety docs to reflect filesystem-derived executor scanning + CI enforcement. |
CLAUDE.md |
Documents the CI-enforced guards (test-glob drift + destructive-action). |
Compute scopedExecutorFiles() a single time and thread it into scan() and the summary so src/daemon is read once and the logged count always matches what was scanned. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/check-no-destructive-actions.ts`:
- Around line 88-95: The scan function's pure-comment-line filter currently only
skips trimmed lines starting with '//' or '*' which misses single-line block
comments like '/* ... */', causing false positives; update the pure-comment
check in scan(...) to also skip lines that begin with '/*' or '*/' or that end
with '*/' (i.e., treat single-line block comment markers as pure comment lines),
keep the rest of the line-by-line scanning logic intact, and add a regression
test that feeds a file (e.g., a stub matching src/daemon/scoped-*-executor.ts)
containing a line like '/* NEVER call gh pr merge */' to assert scan() does not
report that line as a violation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 127ad9bc-b6d1-47f8-8665-2180f9b3fad1
📒 Files selected for processing (5)
.github/workflows/ci.ymlCLAUDE.mddocs/use/safety.mdscripts/check-no-destructive-actions.tstest/scripts/check-no-destructive-actions.test.ts
A pure /* ... */ comment documenting a forbidden call (now observable on the scoped executors) must not trip the guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The prior single-line block-comment exemption skipped the whole line, so a closed comment followed by a destructive call (/* */ gh pr merge) could bypass the FR-009 guard. Strip only CLOSED /* */ spans and test the remaining code, so the legit documentation case is still exempt but trailing destructive code is scanned. Flagged by automated security review. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
What
Closes #203. The FR-009 destructive-action guard (
scripts/check-no-destructive-actions.ts) hard-codedSCAN_FILESwithsrc/daemon/scoped-explain-thread-executor.ts, which was removed when chat-thread subsumed explain-thread.readFileSyncthrewENOENTand the guard crashed before validating anything — a dead CI safety guard. It surfaced only locally (it was wired intobun run checkbut notci.yml).Fix
scripts/check-no-destructive-actions.ts— derive the scoped-executor set from the filesystem (scoped-*-executor.tsundersrc/daemon, viascopedExecutorFiles()) instead of a hard-coded list, so a renamed/removed executor cannot leave a stale entry. Hardenings from review:withFileTypes+isFile()so a directory matching the regex can't causeEISDIR(parity withwalk())..github/workflows/ci.yml— new "Destructive-action guard (FR-009)" step runningbun run check:no-destructive, so the security guard is actually enforced in CI, not just localbun run check.test/scripts/check-no-destructive-actions.test.ts(new) — 8 cases viacwd-fixtures + a real-repo exit-0 regression: real-repo run, clean-with-only-some-executors, destructive-in-executor, destructive-under-ship, comment-not-flagged, non-executor-daemon-file-excluded (narrowing boundary), convention-drift fail-closed, missing-src/daemonfail-closed.docs/use/safety.md/CLAUDE.md— doc-sync: drop the stale "four scoped daemon executors" count (the derived set tracks the filesystem), and document the now-CI-enforcedcheck:no-destructive+check:test-globsguards.Red → green
All 8 tests failed against the broken script (ENOENT crash on any
cwd); they pass after the derive-from-filesystem fix. The real guard now exits 0 ("3 scoped executors scanned").Acceptance criteria (issue #203)
bun run check:no-destructiveexits 0 onmain.check:no-destructivewired intoci.yml.Provenance
Filed by me during cycle 1 of this bulk-implement run, when the dead guard was discovered while fixing #201.
🤖 Generated with Claude Code
Summary by CodeRabbit
Tests
Chores