Skip to content

CLI-279 Fail soft on hook crash outside CI#273

Open
kirill-knize-sonarsource wants to merge 1 commit into
masterfrom
task/kk/CLI-279-fail-soft-on-hook-crash
Open

CLI-279 Fail soft on hook crash outside CI#273
kirill-knize-sonarsource wants to merge 1 commit into
masterfrom
task/kk/CLI-279-fail-soft-on-hook-crash

Conversation

@kirill-knize-sonarsource
Copy link
Copy Markdown
Member

No description provided.

@sonar-review-alpha
Copy link
Copy Markdown
Contributor

sonar-review-alpha Bot commented May 13, 2026

Summary

This PR changes git hooks (pre-commit and pre-push) to gracefully handle scan failures differently depending on the environment. In CI (CI=true): failures block the operation (existing behavior). Outside CI: failures log a warning and allow the operation to proceed, so a broken secrets scan doesn't interrupt local development workflows.

The implementation adds a handleScanError() function that checks process.env.CI and either throws or warns. Both hook handlers now call this function instead of unconditionally throwing. The pre-push logic is refactored into a scanRef() function to support early exit when scanning fails outside CI.

Test coverage includes new cases for fail-soft behavior alongside updated assertions that the fail-hard behavior still works in CI.

What reviewers should know

Start with the core logic: Check hook-dependencies.ts:handleScanError() — this is the decision point for the entire feature. Then look at how it's called in git-pre-commit.ts (simple) and git-pre-push.ts (more involved due to the ref-scanning loop).

Non-obvious changes:

  • The git-pre-push.ts refactor introduces a scanRef() function that returns boolean to signal success/failure, enabling the caller to break after the first failure. This is necessary because you can't throw in a loop and continue to the next iteration outside CI.
  • Both hooks now return without throwing after calling handleScanError() outside CI, allowing the hook to exit 0.
  • Existing unit tests were updated to explicitly set process.env.CI = 'true' to preserve their original intent, with cleanup in finally blocks.

What to watch:

  • The ref-scanning loop in pre-push now has early-break behavior only when outside CI — verify this doesn't mask legitimate failures in CI (it shouldn't, but trace through the control flow).
  • The warning message text is user-facing — check if it's appropriate for the audience.
  • Tests mock readGitPushRefs() — make sure the new test for "stops scanning after first crash" (runSecretsBinarySpy called once) correctly reflects the expected behavior.

  • Generate Walkthrough
  • Generate Diagram

🗣️ Give feedback

@hashicorp-vault-sonar-prod
Copy link
Copy Markdown

hashicorp-vault-sonar-prod Bot commented May 13, 2026

CLI-279

@kirill-knize-sonarsource kirill-knize-sonarsource force-pushed the task/kk/CLI-279-fail-soft-on-hook-crash branch from cc6964e to 7a6519d Compare May 13, 2026 10:33
sonar-review-alpha[bot]

This comment was marked as resolved.

@kirill-knize-sonarsource kirill-knize-sonarsource force-pushed the task/kk/CLI-279-fail-soft-on-hook-crash branch 2 times, most recently from d30bf0f to 08c5ae6 Compare May 13, 2026 11:17
sonar-review-alpha[bot]

This comment was marked as resolved.

@kirill-knize-sonarsource kirill-knize-sonarsource marked this pull request as draft May 13, 2026 11:51
@kirill-knize-sonarsource kirill-knize-sonarsource force-pushed the task/kk/CLI-279-fail-soft-on-hook-crash branch from 08c5ae6 to 3aefd0c Compare May 13, 2026 14:16
@kirill-knize-sonarsource kirill-knize-sonarsource marked this pull request as ready for review May 13, 2026 14:23
@kirill-knize-sonarsource kirill-knize-sonarsource force-pushed the task/kk/CLI-279-fail-soft-on-hook-crash branch from 3aefd0c to b1d9705 Compare May 13, 2026 14:32
sonar-review-alpha[bot]

This comment was marked as resolved.

@kirill-knize-sonarsource kirill-knize-sonarsource force-pushed the task/kk/CLI-279-fail-soft-on-hook-crash branch from b1d9705 to 300f9cf Compare May 13, 2026 15:09
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@sonar-review-alpha sonar-review-alpha Bot left a comment

Choose a reason for hiding this comment

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

Three previously flagged issues remain open; none have been fixed in this revision. Until all three are addressed, the PR cannot be approved.

🗣️ Give feedback

binaryPath: string;
}

export function handleScanError(context: 'Commit' | 'Push'): void {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: process.env.CI === 'true' is still an exact-string match. The previous review comment on this line flagged that several common CI platforms (Azure DevOps, custom runners with CI=1 or CI=yes) will not match this check and will silently skip enforcement. A truthy check is safer and matches the convention used by Jest, create-react-app, and most JS tooling.

Suggested change
export function handleScanError(context: 'Commit' | 'Push'): void {
if (process.env.CI) {
  • Mark as noise


export function handleScanError(context: 'Commit' | 'Push'): void {
if (process.env.CI === 'true') {
throw new CommandFailedError('Secrets scan failed');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The original error is still not surfaced in the fail-soft path. handleScanError() accepts no error parameter, so the debug log at the call site already printed the message, but the warn() shown to the user is always the same generic string regardless of what actually went wrong (binary not found, SIGSEGV, network timeout, etc.). Accepting the error here and including at least its message in the warning would make local debugging meaningful without changing the fail-soft contract.

  • Mark as noise

Comment on lines +59 to 60
throw new CommandFailedError('Secrets detected in pushed commits');
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: return false is still reached after handleScanError('Push') returns normally (outside CI). This breaks the loop and silently skips all remaining refs — the opposite of the fail-soft contract, which should warn but keep scanning. The return false / break pattern is only correct for the CI throw path; it should not apply when the soft path falls through.

Fix: return true after handleScanError so remaining refs are still scanned:

Suggested change
throw new CommandFailedError('Secrets detected in pushed commits');
}
handleScanError('Push'); // throws in CI, warns outside CI
return true;
  • Mark as noise

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