Fetch accepts an unchanged attestation serial; push still requires a greater one adec9a0796b8
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-09-26 18:37 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
adec9a0796b863e2dc79a20917011fd4e5bd733068b0bfe54bf7a441a2fe526b- Depends on
- 5b9c6ad45f6e ff0af1ee299d
- Depended on by
- nothing yet
- In bookmarks
- agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.1.0 v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 5 atoms, 0 tree operations, 1 file
Browse the tree at this change
modified crates/oxy-core/src/repo.rs +6 −4
| … | 673 unchanged lines |
||
| 674 | 674 | } |
|
| 675 | 675 | ||
| 676 | 676 | /// Verify a reference attestation against an update it claims to describe. |
|
| 677 | - | fn check_ref_attest(&self, sa: &SignedAttest, name: &str, old_state: &ObjectRef, new_state: &ObjectRef, last_serial: Option<u64>) -> std::result::Result<u64, String> { |
|
| 677 | + | /// `allow_equal` lets a client re-read the attestation it already has; a |
|
| 678 | + | /// server receiving a push requires a strictly greater serial. |
|
| 679 | + | fn check_ref_attest(&self, sa: &SignedAttest, name: &str, old_state: &ObjectRef, new_state: &ObjectRef, last_serial: Option<u64>, allow_equal: bool) -> std::result::Result<u64, String> { |
|
| 678 | 680 | let AttestBody::Ref { name: n, old_state: o, new_state: nw, serial } = &sa.attest.body else { |
|
| 679 | 681 | return Err("attestation is not a ref attestation".into()); |
|
| 680 | 682 | }; |
|
| … | 4 unchanged lines |
||
| 685 | 687 | return Err("attestation is for a different repository".into()); |
|
| 686 | 688 | } |
|
| 687 | 689 | if let Some(last) = last_serial { |
|
| 688 | - | if *serial <= last { |
|
| 690 | + | if *serial < last || (*serial == last && !allow_equal) { |
|
| 689 | 691 | return Err(format!("attestation serial {serial} is not greater than the last seen {last}")); |
|
| 690 | 692 | } |
|
| 691 | 693 | } |
|
| … | 54 unchanged lines |
||
| 746 | 748 | AttestBody::Ref { serial, .. } => Some(serial), |
|
| 747 | 749 | _ => None, |
|
| 748 | 750 | }); |
|
| 749 | - | self.check_ref_attest(sa, &u.name, &u.old_state, &u.new_state, last)?; |
|
| 751 | + | self.check_ref_attest(sa, &u.name, &u.old_state, &u.new_state, last, false)?; |
|
| 750 | 752 | let r = self.store.put_attest(&sa.attest).map_err(|e| e.to_string())?; |
|
| 751 | 753 | for sig in &sa.sigs { |
|
| 752 | 754 | self.store.put_signature(&r, sig).map_err(|e| e.to_string())?; |
|
| … | 65 unchanged lines |
||
| 818 | 820 | }; |
|
| 819 | 821 | let (old_state, new_state) = (*old_state, *new_state); |
|
| 820 | 822 | let serial = self |
|
| 821 | - | .check_ref_attest(sa, &r.name, &old_state, &new_state, self.last_seen_serial(remote_name, &r.name)) |
|
| 823 | + | .check_ref_attest(sa, &r.name, &old_state, &new_state, self.last_seen_serial(remote_name, &r.name), true) |
|
| 822 | 824 | .map_err(|e| RepoError::Msg(format!("attestation for {}/{}: {e}", remote_name, r.name)))?; |
|
| 823 | 825 | if new_state != r.state { |
|
| 824 | 826 | return fail(format!("attestation for {}/{} does not cover its current state", remote_name, r.name)); |
|
| … | 1693 unchanged lines |