Skip to content

fix(pr-review-toolkit): tolerate checkout-index partial failures - #75

Merged
cblecker merged 1 commit into
mainfrom
fix/pr-review-checkout-partial-failure
Jul 7, 2026
Merged

fix(pr-review-toolkit): tolerate checkout-index partial failures#75
cblecker merged 1 commit into
mainfrom
fix/pr-review-checkout-partial-failure

Conversation

@cblecker

@cblecker cblecker commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • The plumbing checkout in checkout.sh treated any checkout-index failure as fatal, falling back to MCP-only mode — even when most files were checked out successfully
  • This was triggered by sandbox-protected files like vendored .gitmodules that cannot be unlinked (EPERM)
  • Breaks the monolithic if ! { ... && ... && ... } block into three independent steps: read-tree and update-ref failures still trigger the fallback, while checkout-index partial failures are silently tolerated

Test plan

  • Validate plugin: claude plugin validate ./pr-review-toolkit
  • Run shellcheck: shellcheck pr-review-toolkit/skills/review-pr/scripts/checkout.sh
  • Review a PR in a repo with vendored .gitmodules files (e.g. openshift/hypershift) and confirm the checkout succeeds instead of falling back to MCP-only mode
  • Verify fallback still works when read-tree fails (e.g. not a git repo)

Summary by CodeRabbit

  • Chores
    • Updated the plugin version to 1.11.1.
  • Bug Fixes
    • Improved repository checkout behavior to better preserve protected local files and hidden workspace settings.
    • Added more specific error handling when checkout steps fail, making issues easier to diagnose.

Copilot AI review requested due to automatic review settings July 7, 2026 04:15
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The plugin manifest version was bumped from 1.11.0 to 1.11.1. The checkout.sh script's plumbing checkout logic was refactored to exclude sandbox-protected files (dotfiles, editor configs, .claude/, .vscode/, .idea/**) using multiple ls-files exclusion patterns, with split error handling for read-tree, checkout-index, and update-ref failures.

Changes

Sandbox-protected checkout exclusion refactor

Layer / File(s) Summary
Plumbing checkout logic with sandbox exclusions
pr-review-toolkit/skills/review-pr/scripts/checkout.sh
Replaces the single-conditional checkout with a stepwise flow: read-tree the merge SHA, build an exclusion list via git ls-files with multiple glob,exclude patterns (dotfiles, editor configs, .claude/**, .vscode/**, .idea/**), run git checkout-index, then git update-ref HEAD; error handling split into distinct skip messages per step, with updated top comment.
Plugin manifest version bump
pr-review-toolkit/.claude-plugin/plugin.json
Increments the manifest version from 1.11.0 to 1.11.1.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CheckoutScript
  participant Git

  CheckoutScript->>Git: git read-tree (merge SHA from FETCH_HEAD)
  Git-->>CheckoutScript: success or read-tree failed (skip)

  CheckoutScript->>Git: git ls-files with glob,exclude patterns
  Git-->>CheckoutScript: filtered file list (excludes dotfiles, .claude/**, .vscode/**, .idea/**)

  CheckoutScript->>Git: git checkout-index on filtered files
  Git-->>CheckoutScript: success or checkout-index failed (skip)

  CheckoutScript->>Git: git update-ref HEAD to merge SHA
  Git-->>CheckoutScript: success or update-ref failed (skip)
Loading

Possibly related PRs

  • cblecker/claude-plugins#45: Introduced the original plumbing checkout logic and versioning in the same plugin that this PR refines with more granular exclusions and error handling.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(pr-review-toolkit): tolerate checkout-index partial failures' directly aligns with the main objective: improving checkout.sh to handle partial checkout-index failures gracefully.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pr-review-checkout-partial-failure

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI 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.

Pull request overview

This PR updates the pr-review-toolkit plumbing checkout so that checkout-index partial failures (e.g., from sandbox-protected files that can’t be unlinked) no longer force a fallback to MCP-only mode, while still treating read-tree / update-ref failures as fatal. It also bumps the plugin version for the release.

Changes:

  • Split the previous monolithic “plumbing checkout” command chain into discrete steps, tolerating checkout-index non-zero exit statuses.
  • Suppress checkout-index stderr to avoid noisy sandbox-related errors during partial checkout.
  • Bump pr-review-toolkit plugin version from 1.11.0 to 1.11.1.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
pr-review-toolkit/skills/review-pr/scripts/checkout.sh Makes the checkout flow more tolerant of partial checkout-index failures while preserving fallback behavior for critical plumbing failures.
pr-review-toolkit/.claude-plugin/plugin.json Version bump to publish the behavioral change.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +38 to +42
# checkout-index may fail on sandbox-protected files (e.g. .gitmodules);
# partial checkout is acceptable — tolerate its exit status.
git ls-files -z -- . ':(exclude).claude/' \
| git checkout-index -f -z --stdin 2>/dev/null || true

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Good catch. Rather than adding error-filtering logic (which would be fragile across git versions and locales), the root cause is that the sandbox runtime has a mandatory deny list of files that are always write-protected (DANGEROUS_FILES + DANGEROUS_DIRECTORIES). On macOS, macGetMandatoryDenyPatterns() blocks these at any depth via **/filename globs.

Fixed by excluding all sandbox mandatory-deny files from the checkout-index pathspec using :(glob,exclude) patterns that match at any depth. With the root cause addressed, || true is replaced with || skip "checkout-index failed" so genuine errors properly trigger the MCP fallback.

The plumbing checkout treated any checkout-index failure as fatal,
falling back to MCP-only mode even when most files were checked out
successfully. This was triggered by sandbox-protected files like
vendored .gitmodules that cannot be unlinked.

Break the monolithic if-block into independent steps so read-tree and
update-ref failures still trigger the fallback while checkout-index
partial failures are silently tolerated.

Assisted-by: Claude:claude-opus-4-6
@cblecker
cblecker force-pushed the fix/pr-review-checkout-partial-failure branch from ee9adaa to 02eebcf Compare July 7, 2026 04:42
@cblecker
cblecker requested a review from Copilot July 7, 2026 04:44

Copilot AI 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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

':(glob,exclude)**/.vscode/**' \
':(glob,exclude)**/.idea/**' \
| git checkout-index -f -z --stdin \
|| skip "checkout-index failed"

@coderabbitai coderabbitai 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.

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 `@pr-review-toolkit/skills/review-pr/scripts/checkout.sh`:
- Around line 38-56: The checkout logic in checkout.sh is over-excluding safe
root-level dotfiles, which can hide legitimate PR changes from disk-based
review. Update the git ls-files exclude patterns so they only skip
sandbox-protected paths when they are actually dangerous at nested locations,
and ensure top-level files like .gitmodules, .gitconfig, and shell rc files are
still checked out when part of the change. Also avoid silent fallback in the
checkout-index pipeline by aligning the exclusion list with the upstream
DANGEROUS_FILES/DANGEROUS_DIRECTORIES source used by the sandbox runtime, so
missing entries surface clearly instead of being hidden by skip.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9a9ce74b-3c56-408d-8c40-2df85d3b9017

📥 Commits

Reviewing files that changed from the base of the PR and between adb85fc and 02eebcf.

📒 Files selected for processing (2)
  • pr-review-toolkit/.claude-plugin/plugin.json
  • pr-review-toolkit/skills/review-pr/scripts/checkout.sh

Comment on lines +38 to +56
# Exclude files on the sandbox mandatory-deny list (DANGEROUS_FILES,
# DANGEROUS_DIRECTORIES in anthropic-experimental/sandbox-runtime).
# These are always write-protected regardless of sandbox config;
# checkout-index would fail with EPERM trying to unlink them.
git ls-files -z -- . \
':(glob,exclude)**/.gitconfig' \
':(glob,exclude)**/.gitmodules' \
':(glob,exclude)**/.bashrc' \
':(glob,exclude)**/.bash_profile' \
':(glob,exclude)**/.zshrc' \
':(glob,exclude)**/.zprofile' \
':(glob,exclude)**/.profile' \
':(glob,exclude)**/.ripgreprc' \
':(glob,exclude)**/.mcp.json' \
':(glob,exclude)**/.claude/**' \
':(glob,exclude)**/.vscode/**' \
':(glob,exclude)**/.idea/**' \
| git checkout-index -f -z --stdin \
|| skip "checkout-index failed"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm DANGEROUS_FILES/DANGEROUS_DIRECTORIES semantics (repo-relative vs. home-dir only)
# and whether root-level matches are intentionally excluded from PR review checkouts.
gh api graphql -f query='{ search(query: "repo:anthropic-experimental/sandbox-runtime DANGEROUS_FILES", type: CODE, first: 5) { nodes { ... on CodeSearchResultItem { path } } } }' 2>/dev/null || true

Repository: cblecker/claude-plugins

Length of output: 701


🏁 Script executed:

#!/bin/bash
# Test git glob exclude pattern behavior
# Create a temporary test directory to verify if **/filename excludes root-level files
cd /tmp
mkdir -p git-glob-test
cd git-glob-test
git init

# Create test structure: files at root and nested directories
touch .gitmodules
mkdir -p subdir/nested
touch subdir/.gitmodules
touch subdir/nested/.gitmodules
touch other.txt
touch subdir/other.txt

git add -A
git commit -m "test"

# Test 1: List files WITHOUT the exclude pattern
echo "=== Files without exclude ==="
git ls-files

# Test 2: List files WITH the exclude pattern (as in the review comment)
echo -e "\n=== Files WITH ':(glob,exclude)**/.gitmodules' ==="
git ls-files ':(glob,exclude)**/.gitmodules'

# Test 3: Check if root-level .gitmodules is excluded
echo -e "\n=== Does root .gitmodules appear? ==="
git ls-files ':(glob,exclude)**/.gitmodules' | grep -c "^\\.gitmodules$" && echo "YES - root .gitmodules included" || echo "NO - root .gitmodules excluded"

Repository: cblecker/claude-plugins

Length of output: 1368


🏁 Script executed:

#!/bin/bash
# Search the current repository for any reference to DANGEROUS_FILES or similar sandbox protections
echo "=== Searching for DANGEROUS_FILES reference ==="
rg -i "dangerous_files|dangerous_directories" --max-count=10 || true

echo -e "\n=== Searching for sandbox-runtime reference ==="
rg "sandbox-runtime|anthropic-experimental" --max-count=10 || true

echo -e "\n=== Looking for .gitmodules handling context ==="
rg "gitmodules" --max-count=20 || true

Repository: cblecker/claude-plugins

Length of output: 209


Root-level files matching excluded basenames will be silently hidden from disk-based review — including legitimate PR changes.

The ':(glob,exclude)**/.gitmodules' pattern excludes .gitmodules at every path depth, including the repository root. If a PR legitimately modifies the top-level .gitmodules (or .gitconfig, .bashrc, etc.), checkout-index will not write it to disk, even though the index and HEAD correctly reference the merged tree. Any reviewer using disk-based tools (rather than git show/git diff) will silently miss that change.

Additionally, this list (mirroring DANGEROUS_FILES/DANGEROUS_DIRECTORIES from the sandbox) is manually maintained and can drift from its upstream source. If checkout-index fails on a sandbox-protected path not enumerated here, the pipeline falls back to skip, making the failure silent rather than alerting reviewers to incomplete diffs.

🤖 Prompt for 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.

In `@pr-review-toolkit/skills/review-pr/scripts/checkout.sh` around lines 38 - 56,
The checkout logic in checkout.sh is over-excluding safe root-level dotfiles,
which can hide legitimate PR changes from disk-based review. Update the git
ls-files exclude patterns so they only skip sandbox-protected paths when they
are actually dangerous at nested locations, and ensure top-level files like
.gitmodules, .gitconfig, and shell rc files are still checked out when part of
the change. Also avoid silent fallback in the checkout-index pipeline by
aligning the exclusion list with the upstream
DANGEROUS_FILES/DANGEROUS_DIRECTORIES source used by the sandbox runtime, so
missing entries surface clearly instead of being hidden by skip.

@cblecker
cblecker merged commit 93262ed into main Jul 7, 2026
14 checks passed
@cblecker
cblecker deleted the fix/pr-review-checkout-partial-failure branch July 7, 2026 05:02
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.

2 participants