diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-03 16:13:59 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-03 17:05:16 +0000 |
| commit | c163d717147b92b16d89da2fbccef775647b5a07 (patch) | |
| tree | 8e512d1d64a3665c2b90954fac9f3d707d7e99d3 /src | |
| parent | 874a8abe1d076cfafd9baf919ec23d7d58200698 (diff) | |
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
Diffstat (limited to 'src')
| -rw-r--r-- | src/git/authorization.rs | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/src/git/authorization.rs b/src/git/authorization.rs index e174b51..db2b992 100644 --- a/src/git/authorization.rs +++ b/src/git/authorization.rs | |||
| @@ -575,6 +575,28 @@ pub async fn get_state_authorization_for_specific_owner_repo( | |||
| 575 | owner_pubkey | 575 | owner_pubkey |
| 576 | ); | 576 | ); |
| 577 | 577 | ||
| 578 | // Accept pushes where all refs are already at the desired state (old_oid == new_oid) | ||
| 579 | // This handles race conditions where state events are applied between fetch and push | ||
| 580 | if !pushed_refs.is_empty() { | ||
| 581 | let all_refs_unchanged = pushed_refs | ||
| 582 | .iter() | ||
| 583 | .all(|(old_oid, new_oid, _)| old_oid == new_oid); | ||
| 584 | |||
| 585 | if all_refs_unchanged { | ||
| 586 | debug!( | ||
| 587 | "All pushed refs unchanged (old_oid == new_oid) for {} owned by {}, accepting without purgatory check", | ||
| 588 | identifier, owner_pubkey | ||
| 589 | ); | ||
| 590 | return Ok(AuthorizationResult { | ||
| 591 | authorized: true, | ||
| 592 | reason: "Push accepted: all refs already at desired state (no-op)".to_string(), | ||
| 593 | state: None, | ||
| 594 | maintainers: authorized.into_iter().collect(), | ||
| 595 | purgatory_events: vec![], | ||
| 596 | }); | ||
| 597 | } | ||
| 598 | } | ||
| 599 | |||
| 578 | // Check purgatory for matching state events | 600 | // Check purgatory for matching state events |
| 579 | // Convert pushed refs to RefUpdate (filter out refs/nostr/* refs) | 601 | // Convert pushed refs to RefUpdate (filter out refs/nostr/* refs) |
| 580 | let pushed_updates: Vec<RefUpdate> = pushed_refs | 602 | let pushed_updates: Vec<RefUpdate> = pushed_refs |