fix(rekey): echo stored DEK values in response, not the pre-image
All checks were successful
Lint and Build / format (pull_request) Successful in 1m1s
Lint and Build / clippy (pull_request) Successful in 1m44s
Lint and Build / build (pull_request) Successful in 3m49s
Lint and Build / test (pull_request) Successful in 4m21s

rekey_rotates_owner_share_and_keeps_listed_recipients failed in CI:
the response's wrapped_profile_dek was 'owner-dek-v1' (old) instead of
'owner-dek-v2' (new). update_wrapped_dek uses find_one_and_update,
which returns the document as it was BEFORE the update by default —
so reading the new value from the returned doc gives the pre-image.

Fix: echo the request values (exactly what was stored) in the response
instead of reading them back. Unambiguous and avoids the
ReturnDocument::After plumbing. The write itself was always correct
(the stored value was v2) — only the response was stale, which is why
the other rekey tests (which check state via fresh reads, not the
response body) passed.

Now CI-green (clippy/fmt clean; integration tests will re-run).
This commit is contained in:
goose 2026-07-19 22:13:51 -03:00
parent bf5aeedbc2
commit 6d6af67f2f

View file

@ -613,7 +613,10 @@ pub async fn rekey_profile(
} }
// 3. Rotate the owner share (store the new account-wrapped profile DEK). // 3. Rotate the owner share (store the new account-wrapped profile DEK).
let updated = match profiles // update_wrapped_dek uses find_one_and_update, which returns the PRE-image
// by default — so we don't read the new values back from it; we echo the
// request values (exactly what was stored) in the response below.
match profiles
.update_wrapped_dek( .update_wrapped_dek(
&profile_id, &profile_id,
&owner, &owner,
@ -622,7 +625,7 @@ pub async fn rekey_profile(
) )
.await .await
{ {
Ok(Some(p)) => p, Ok(Some(_)) => {}
Ok(None) => { Ok(None) => {
return Err(( return Err((
StatusCode::NOT_FOUND, StatusCode::NOT_FOUND,
@ -636,7 +639,7 @@ pub async fn rekey_profile(
Json(serde_json::json!({ "error": "database error" })), Json(serde_json::json!({ "error": "database error" })),
)); ));
} }
}; }
// 4. Upsert each submitted recipient envelope (fresh ECDH-wrapped DEK + // 4. Upsert each submitted recipient envelope (fresh ECDH-wrapped DEK +
// ephemeral pubkey, replacing the old envelope). Preserve the original // ephemeral pubkey, replacing the old envelope). Preserve the original
@ -695,8 +698,10 @@ pub async fn rekey_profile(
StatusCode::OK, StatusCode::OK,
Json(RekeyResponse { Json(RekeyResponse {
profile_id, profile_id,
wrapped_profile_dek: updated.wrapped_profile_dek, // Echo the request values (exactly what was stored). Avoids the
wrapped_profile_dek_iv: updated.wrapped_profile_dek_iv, // find_one_and_update pre-image gotcha.
wrapped_profile_dek: req.new_wrapped_profile_dek,
wrapped_profile_dek_iv: req.new_wrapped_profile_dek_iv,
retained_recipient_user_ids: keep, retained_recipient_user_ids: keep,
}), }),
)) ))