Describe the bug
There's a critical state-leak in internal/engine/actions/remediate/pull_request/pull_request.go where failing to fully commit and push a pull request remediation poisons the ingestion cache for all subsequent rule evaluations in that run.
When the PR remediator runs, it checks out a new branch in the go-git workspace (which sits directly on the shared ingestCache.Fs virtual filesystem). If the remediation algorithm fails after modifying files but before committing (e.g. failing during wt.Add or crashing during file generation), the worktree is left in a dirty state.
The code attempts to clean up in a defer block using checkoutToOriginallyFetchedBranch:
func checkoutToOriginallyFetchedBranch(...) {
err := wt.Checkout(&git.CheckoutOptions{
Branch: originallyFetchedBranch,
// BUG: Missing `Force: true`
})
}
Because this wt.Checkout call omits Force: true and CleanOptions{Dir: true}, go-git defaults to preserving all uncommitted/untracked modifications and carrying them into the target branch.
Impact
Because the executor shares a single ingestCache.Fs across all rule evaluations for a repository during a run, this dirty state leaks across boundaries. If Rule A attempts remediation, modifies a file to be "compliant", but crashes out, Rule B will then evaluate against that dirty cache. Rule B will falsely evaluate the repository as compliant, creating a silent security bypass (false negative).
Steps to reproduce
- Configure two rules against the same entity (e.g., Rule A and Rule B).
- Set Rule A to auto-remediate with PRs.
- Simulate a failure during Rule A's remediation (after it modifies fs but before wt.Commit).
- Observe that Rule B evaluates against the uncommitted files produced by Rule A rather than the upstream repository state.
Expected Behavior
A failed remediation attempt should completely blow away the dirty worktree and restore the ingest cache entirely to its pristine upstream state.
Suggested Fix
Update checkoutToOriginallyFetchedBranch to aggressively reset the workspace:
err := wt.Checkout(&git.CheckoutOptions{
Branch: originallyFetchedBranch,
Force: true, // Discards modified tracked files
})
// And also run:
// wt.Clean(&git.CleanOptions{Dir: true}) // Removes left-behind untracked files
Describe the bug
There's a critical state-leak in internal/engine/actions/remediate/pull_request/pull_request.go where failing to fully commit and push a pull request remediation poisons the ingestion cache for all subsequent rule evaluations in that run.
When the PR remediator runs, it checks out a new branch in the
go-gitworkspace (which sits directly on the sharedingestCache.Fsvirtual filesystem). If the remediation algorithm fails after modifying files but before committing (e.g. failing duringwt.Addor crashing during file generation), the worktree is left in a dirty state.The code attempts to clean up in a
deferblock usingcheckoutToOriginallyFetchedBranch:Because this
wt.Checkoutcall omits Force: true andCleanOptions{Dir: true}, go-git defaults to preserving all uncommitted/untracked modifications and carrying them into the target branch.Impact
Because the executor shares a single
ingestCache.Fsacross all rule evaluations for a repository during a run, this dirty state leaks across boundaries. If Rule A attempts remediation, modifies a file to be "compliant", but crashes out, Rule B will then evaluate against that dirty cache. Rule B will falsely evaluate the repository as compliant, creating a silent security bypass (false negative).Steps to reproduce
Expected Behavior
A failed remediation attempt should completely blow away the dirty
worktreeand restore the ingest cache entirely to its pristine upstream state.Suggested Fix
Update
checkoutToOriginallyFetchedBranchto aggressively reset the workspace: