fix: accept no-op pushes where old_oid == new_oid

Fixes race condition where user's push becomes no-op after state event
is applied between fetch and push. Now accepts these as successful
no-ops, matching Git's 'Everything up-to-date' behavior.

- Add early detection in get_state_authorization_for_specific_owner_repo
- Return success for all-noop pushes without requiring purgatory event
- Document behavior in inline-authorization.md
This commit is contained in:
DanConwayDev
2026-02-03 17:05:16 +00:00
parent 874a8abe1d
commit c163d71714
2 changed files with 26 additions and 0 deletions
+4
View File
@@ -352,6 +352,10 @@ pub async fn authorize_push(
- If no event found, create placeholder (git-data-first scenario)
- Collect PR events from purgatory for post-push processing
**No-Op Push Acceptance:** Pushes where all refs have `old_oid == new_oid` are accepted without requiring a purgatory state event, matching Git's "Everything up-to-date" behavior and avoiding race condition rejections.
---
## State Event Authorization
State events (kind 30618) undergo authorization checks at three points (defense-in-depth):
+22
View File
@@ -575,6 +575,28 @@ pub async fn get_state_authorization_for_specific_owner_repo(
owner_pubkey
);
// Accept pushes where all refs are already at the desired state (old_oid == new_oid)
// This handles race conditions where state events are applied between fetch and push
if !pushed_refs.is_empty() {
let all_refs_unchanged = pushed_refs
.iter()
.all(|(old_oid, new_oid, _)| old_oid == new_oid);
if all_refs_unchanged {
debug!(
"All pushed refs unchanged (old_oid == new_oid) for {} owned by {}, accepting without purgatory check",
identifier, owner_pubkey
);
return Ok(AuthorizationResult {
authorized: true,
reason: "Push accepted: all refs already at desired state (no-op)".to_string(),
state: None,
maintainers: authorized.into_iter().collect(),
purgatory_events: vec![],
});
}
}
// Check purgatory for matching state events
// Convert pushed refs to RefUpdate (filter out refs/nostr/* refs)
let pushed_updates: Vec<RefUpdate> = pushed_refs