Add collision-safe KeyRing rename API - #144
Conversation
|
Thank you for the contribution! Appreciate it. I think the semantics mostly make sense, but the type output should really be a Result here. A boolean made sense when we expected the user to hold the interface right - if there's multiple ways to fail, however, then a Result communicates the full range of behaviours. Here is my request for how to do this:
If new key is same as old key, we return an Let me know what you think! |
|
Makes sense, thanks! I’ll keep Quick question on an edge case: if |
|
Apply an order of precedence:
|
|
and I don't think we need to have rename_key as a wrapper around try_rename_key, especially since we're marking it deprecated. Just leave a comment explaining it doesn't guarantee renaming conflicts. I'll cut a new version later. |
|
Just pushed the updates in
|
| if !self.ring.contains_key(&old_identifier) { | ||
| return Err(OperationError::KeyNotPresent); | ||
| } | ||
| if old_identifier == new_identifier { |
There was a problem hiding this comment.
This needs to be swapped with the check on line 247 - that is, checking if the new identifier is already present should happen before checking if the two identifiers are the same.
There was a problem hiding this comment.
Should an existing same-identifier rename now return KeyOccupied, or should it remain Ok(()) as previously requested?
| .remove(&old_identifier) | ||
| .ok_or(OperationError::KeyNotPresent)?; | ||
| let replaced = self.ring.insert(new_identifier, value); | ||
| debug_assert!(replaced.is_none()); |
There was a problem hiding this comment.
Let's not use debug_assert! - this is going to be exposed to end users. We can remove this line altogether.
| return Err(OperationError::KeyOccupied); | ||
| } | ||
|
|
||
| let value = self |
There was a problem hiding this comment.
slightly simpler to just:
if let Some(value) = self.ring.remove(&old_identifier) {
self.ring.insert(new_identifier, value);
}
Ok(())
The preceding checks will ensure our invariant of old existing / new key not existing.
| /// | ||
| /// This method does not safely handle destination conflicts. Use [`Self::try_rename_key`] | ||
| /// instead. | ||
| #[deprecated(note = "does not safely handle destination conflicts; use `try_rename_key`")] |
There was a problem hiding this comment.
You can set since to be 0.7.1
1. Purpose
KeyRing::rename_keyreturns a boolean, so callers cannot distinguish a missing source key from an occupied destination. Its legacy remove-then-insert behavior can also replace the destination before reporting failure.This PR adds a fallible rename API that reports each failure explicitly while retaining the existing method for compatibility.
2. Implementation
crates/web-bot-auth/src/keyring.rsadds:OperationError::KeyNotPresentwhen the source identifier is absent.OperationError::KeyOccupiedwhen a distinct destination identifier is already present.try_rename_key, returningResult<(), OperationError>.try_rename_keyapplies source absence first, treats an existing same-identifier rename as a successful no-op, rejects occupied destinations before mutation, and otherwise moves the existingKeyEntryto the new identifier.The existing
rename_keyimplementation remains independent and is marked deprecated with a warning that it does not safely handle destination conflicts.3. Behavior
The new API behaves as follows:
Err(OperationError::KeyNotPresent).Ok(())without reinsertion.Err(OperationError::KeyOccupied)and preserves both keys.KeyEntry, including its prepared verification state.The legacy
rename_keysignature and behavior remain available during the deprecation period.4. Tests
The Rust tests cover:
KeyOccupiedresult.KeyNotPresenttaking precedence when the source is absent.Internal test call sites now use
try_rename_key, avoiding deprecation warnings.5. Review Guide
Review
crates/web-bot-auth/src/keyring.rs:try_rename_key.rename_keyretains its legacy implementation.Review
crates/web-bot-auth/src/message_signatures.rs:try_rename_key.6. Risk
The new API is additive. The existing method remains callable with unchanged behavior, but now emits a deprecation warning.
This PR does not change key import, lookup, JWK handling, prepared-key construction, or signature verification.
7. Validation
The following commands passed:
cargo test -p web-bot-auth --all-features(41 tests plus doc-tests)cargo clippy -p web-bot-auth --all-features --all-targets -- -D warningscargo fmt --all -- --checkgit diff --check