Skip to content

feat(git-shim): path-scope enforcement for claims (QuorumGit adoption) - #303

Merged
getappz merged 2 commits into
masterfrom
item-234-path-scope-claims
Jul 22, 2026
Merged

feat(git-shim): path-scope enforcement for claims (QuorumGit adoption)#303
getappz merged 2 commits into
masterfrom
item-234-path-scope-claims

Conversation

@getappz

@getappz getappz commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Adopts QuorumGit's claim-scope classification for flare-git-shim, closing the top deferred guard gap: all existing branch-protection layers key off host cwd, not changed file paths, which is why opencode has twice edited the canonical checkout instead of its claim's worktree (agentflare item #234).

  • Claims can now declare path-glob write scopes (claim acquire --scope / MCP scope param). Unscoped claims (the back-compat default) never deny another agent's unrelated work — many claims normally coexist per repo, one per target.
  • flare_git_core::scope::classify_scopes classifies a commit/push's changed paths against live claim scopes: Clear/Related pass, Overlapping (touches another live claim's declared scope) and OutOfTree (own claim held but committing from the canonical checkout, not its worktree) deny.
  • flare-git-shim shells out to a new hidden agentflare git scope-check CLI command for commit/push (the shim itself has no DB access to live claims) and is deliberately fail-closed on any scope-resolution error — a documented exception to this crate's usual fail-open default, matching the spec. Existing bypass envs (AGENTFLARE_GIT_BYPASS and friends) remain the escape hatch.
  • claim acquire prints a non-blocking warning when a new scope overlaps another live claim's declared scope — v1 enforcement is at mutation time only, per spec non-goals (no claim-time hard refusal, no server-side pre-receive hook).
  • Every denial is audited to ~/.agentflare/audit/git.jsonl, same sink as the rest of the shim's decisions.

Not included (fast-follow): the opencode tool.execute.before plugin (src/hook_redirect.rs) still only checks branch protection, not claim scopes. Acceptance criteria didn't require it, and it's the softer best-effort layer — the shim/hook is where real enforcement lives.

Test plan

  • cargo test --workspace — 732 passed, 0 failed
  • cargo test -p flare-git-core — 82/82 (incl. 10 new scope tests)
  • cargo test -p flare-git-shim — 13/13 integration tests
  • cargo fmt --check clean on touched crates
  • cargo clippy --all-features -- -D warnings clean on touched crates (2 remaining errors in daemon_autostart.rs are pre-existing and untouched by this diff, confirmed via git diff --stat origin/master)
  • Manual smoke test: agentflare git scope-check --subcommand commit against the real claim DB from inside this PR's own worktree (claim on item fix(flare-output): don't fail RealLlm on a benign stdin broken-pipe #234) — correctly passed

Summary by CodeRabbit

  • New Features

    • Added optional path scopes to claims through the CLI and MCP interfaces.
    • Added warnings when claim scopes overlap.
    • Enforced scope checks for agent-driven git commit and git push operations.
    • Added clear denial messages when changes fall outside permitted worktrees or overlap another claim.
  • Compatibility

    • Existing unscoped claims retain their previous, non-enforcing behavior.
    • Operations without relevant claim or agent context continue to proceed normally.

Adopt QuorumGit's claim-scope classification for flare-git-shim, closing
the top deferred guard gap: all existing branch-protection layers key off
host cwd, not changed file paths, which is why opencode has twice edited
the canonical checkout instead of its claim's worktree.

- claims can now declare path-glob write scopes (`--scope`/MCP `scope`
  param on claim acquire); unscoped claims (the back-compat default)
  never deny another agent's unrelated work
- flare-git-core::scope::classify_scopes classifies commit/push against
  live claim scopes: CLEAR/RELATED pass, OVERLAPPING (touches another
  live claim's declared scope) and OUT_OF_TREE (own claim held but
  committing from the canonical checkout) deny
- flare-git-shim shells out to the new hidden `agentflare git
  scope-check` CLI command for commit/push (the shim itself has no DB
  access) and is deliberately fail-closed on any scope-resolution error,
  unlike this crate's usual fail-open default; existing bypass envs
  remain the escape hatch
- claim acquire warns (non-blocking) when a new scope overlaps another
  live claim's declared scope -- v1 enforcement is at mutation time only

Every denial is audited to ~/.agentflare/audit/git.jsonl, same sink as
the rest of the shim's decisions.

Not yet wired: the opencode tool.execute.before plugin (hook_redirect.rs)
still only checks branch protection, not claim scopes -- left as a
fast-follow since it's a softer, best-effort layer and the native
shim/hook boundary is where real enforcement lives.

Agentflare-Agent: claude-code_2-1-217_agent
Agentflare-Branch: item-234-path-scope-claims
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@getappz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 11 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 37960cac-5ea3-4649-93ce-5c21ce546064

📥 Commits

Reviewing files that changed from the base of the PR and between 8c48fbe and 9b65cc1.

📒 Files selected for processing (4)
  • src/claims.rs
  • src/cli/claim.rs
  • src/cli/git.rs
  • src/mcp_server/claim.rs
📝 Walkthrough

Walkthrough

Adds claim write scopes with SQLite persistence, glob-based overlap classification, acquisition warnings, and enforcement for agent-driven git commit and git push operations.

Changes

Claim scope enforcement

Layer / File(s) Summary
Scope classification primitives
crates/flare-git-core/src/lib.rs, crates/flare-git-core/src/scope.rs
Adds public scope verdicts, claim scope data, conservative glob overlap helpers, classification precedence, and unit tests.
Claim scope persistence and acquisition
src/claims.rs, src/cli/claim.rs, src/mcp_server/claim.rs, src/mcp_server/types.rs
Stores scopes in the claims ledger, adds repeatable CLI and MCP scope inputs, and returns overlap warnings after acquisition.
Internal scope-check command
src/cli/git.rs
Adds the hidden scope-check command, loads live claims, resolves changed paths for commits and pushes, and emits JSON decisions.
Commit and push enforcement
crates/flare-git-shim/Cargo.toml, crates/flare-git-shim/src/main.rs
Invokes scope-check from the shim, fails closed on errors, audits denials, and blocks denied commit or push operations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant GitShim
  participant ScopeCheck
  participant ClaimsLedger
  participant Git
  Agent->>GitShim: git commit or git push
  GitShim->>ScopeCheck: request scope-check
  ScopeCheck->>ClaimsLedger: load live claims
  ScopeCheck->>Git: resolve changed paths
  ScopeCheck-->>GitShim: allow or deny JSON
  alt denied
    GitShim-->>Agent: print reason and exit failure
  else allowed
    GitShim->>Git: execute operation
  end
Loading

Possibly related PRs

Suggested labels: enhancement, rust

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding path-scope enforcement for claims in the git shim.
Description check ✅ Passed The PR description covers the summary and test plan, and it mentions reviewer notes/backwards compatibility, though the notes section is not fully structured.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch item-234-path-scope-claims

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.

@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

🧹 Nitpick comments (1)
src/claims.rs (1)

79-101: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Re-acquiring without --scope silently clears a previously declared scope.

acquire_persists_and_overwrites_scope confirms this is intentional ("mirroring git_commit's always-overwrite behavior"), but it means any caller that re-acquires an already-held claim (e.g. a heartbeat-style refresh done via acquire instead of heartbeat) without re-supplying --scope/scope silently disables path-scope enforcement for that claim, with no warning surfaced anywhere. Given this is a security-relevant control, consider at least emitting a warning (similar to scope_overlap_warning) when an existing non-empty scope is being cleared, so agents don't lose enforcement unknowingly.

🤖 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 `@src/claims.rs` around lines 79 - 101, Update claims::acquire so re-acquiring
a claim with scope=None detects an existing non-empty scope and emits a warning,
using the established scope_overlap_warning behavior or logging path. Preserve
the current overwrite semantics for git_commit and scope while ensuring the
warning is produced before the existing scope is cleared.
🤖 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 `@src/cli/git.rs`:
- Around line 587-607: Update changed_paths for the "commit" subcommand to
include both staged changes and unstaged working-tree changes, so git commit
-a/--all paths are included in the result passed to run_scope_check. Preserve
the existing cached-diff behavior and combine the two name-only path sets
without omitting either source.

---

Nitpick comments:
In `@src/claims.rs`:
- Around line 79-101: Update claims::acquire so re-acquiring a claim with
scope=None detects an existing non-empty scope and emits a warning, using the
established scope_overlap_warning behavior or logging path. Preserve the current
overwrite semantics for git_commit and scope while ensuring the warning is
produced before the existing scope is cleared.
🪄 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 Plus

Run ID: f8052b22-7e6b-4416-905c-46e82cb73dfe

📥 Commits

Reviewing files that changed from the base of the PR and between fae88fb and 8c48fbe.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • crates/flare-git-core/src/lib.rs
  • crates/flare-git-core/src/scope.rs
  • crates/flare-git-shim/Cargo.toml
  • crates/flare-git-shim/src/main.rs
  • src/claims.rs
  • src/cli/claim.rs
  • src/cli/git.rs
  • src/mcp_server/claim.rs
  • src/mcp_server/types.rs

Comment thread src/cli/git.rs
…clear

Two CodeRabbit findings on PR #303:

- changed_paths() for "commit" only checked `git diff --cached`, so
  `git commit -a`/`--all` (which implicitly stages+commits tracked
  modifications without a prior `git add`) bypassed path-scope
  enforcement entirely. Union staged + working-tree diffs instead.
- claims::acquire() always overwrites the scope column (matching
  git_commit's existing always-overwrite behavior), so re-acquiring an
  already-held claim without re-supplying --scope silently disabled
  enforcement with no signal anywhere. Added scope_clear_warning(),
  wired into both the CLI and MCP acquire handlers alongside the
  existing overlap warning.

Agentflare-Agent: claude-code_2-1-217_agent
Agentflare-Branch: item-234-path-scope-claims
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.

1 participant