OXYGENHUB

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