- Case ID
- #4576
- Severity
- WARN
- Decision
- FORCE
- Agent
- Windsurf
- Category
- Git Hygiene
Correction note (2026-10-13). The per-call timings and latency figures that appeared in this article had no benchmark behind them and were removed. Sample output in this article is illustrative, not a recorded run. The only published measurement is p50 0.39 ms and p99 1.91 ms (sigmashake-bench daemon-socket run, 2026-06-10, ssg 0.29.156, n=500). Sub-2 ms evaluation is a design target.
Correction note (2026-10-13). An earlier version of the rule in this article used the operator
MATCHES_REGEX, which the rule DSL does not have, so the rule did not load. The rule now usesREGEX.
Describe the task
You ask Windsurf to rebase and clean up a branch. After the rebase completes, the agent pushes back to the remote — but uses --force to overwrite the branch history and accidentally targets main instead of your feature branch:
git push origin main --force
A force-push to a shared branch rewrites everyone's history. Teammates' local branches diverge. CI artifacts pointing to rewritten commits become invalid. SSG's no-force-push-main rule blocks it immediately.
# illustrative sample output
[BLOCK] bash › git push origin main --force — rule: no-force-push-main
Give SSG context
SSG evaluates Windsurf's shell commands via the SSG MCP Server integration inside Windsurf (Cascade).
Required context
rule no-force-push-main {
enabled true
priority 95
severity error
DENY execution
IF command CONTAINS "git push" AND command CONTAINS "--force"
AND command CONTAINS "main"
MESSAGE "Force push to main is blocked. Use --force-with-lease on feature branches only."
}
Optional context
Extend to protect additional protected branches:
rule no-force-push-protected {
enabled true
priority 95
severity error
DENY execution
IF command CONTAINS "git push"
AND command CONTAINS "--force"
AND command REGEX "(main|master|release|production)"
MESSAGE "Force push to a protected branch is blocked."
}
What SSG does
SSG inspects the full git command including all flags and arguments. The block fires before any network connection to the remote is opened — no packets sent, no history rewritten.
Ask the agent to use a feature branch
Force push to main was blocked. Push your changes to a feature branch instead:
git push origin HEAD:feature/my-fix --force-with-lease
--force-with-lease is the safer alternative — it fails if the remote has diverged, preventing overwrites of others' work.
See all blocked push attempts in your audit log
Run ssg dashboard and filter by no-force-push to see every push attempt blocked across all agent sessions. This is particularly useful in team environments where multiple developers use the same agent tooling.
Combine with a git pre-push hook for defense in depth
SSG blocks at the tool-call layer. Pair it with a server-side protected branch rule in GitHub/GitLab for defense-in-depth — even if an agent somehow bypasses SSG, the remote will still reject the push.
How your rule syntax handles flag ordering
Git flag ordering is flexible — git push --force origin main and git push origin main --force both work. Using CONTAINS for each component (rather than STARTS_WITH) handles all orderings correctly.
Check the rule against your release automation
Some release scripts legitimately force-push version tags or release branches. Create an exemption rule at higher priority for those specific patterns, or move release automation to a service account with SSG configured in ALLOW mode for that specific command.