[PM-32802] fix: 400 error when archiving/unarchiving org-owned ciphers#6592
[PM-32802] fix: 400 error when archiving/unarchiving org-owned ciphers#6592SaintPatrck merged 3 commits intomainfrom
Conversation
|
Claude finished @SaintPatrck's task in 5m 15s —— View job Code Review: PR #6592
SummaryThis PR correctly fixes the 400 error by removing the unnecessary FindingsNo new issues found. The previous review's Detailed AnalysisCorrectness — The fix is sound. Archive and unarchive only toggle a server-side state flag and don't require client-side encryption. Removing Pattern Consistency — The implementation follows established codebase patterns well:
Error Handling — 400 errors are caught at the service layer via Comment at lines 252-254 — The explanatory comment on Test Coverage — Tests are comprehensive:
Security — No concerns. No encrypted content is modified or transmitted during archive/unarchive operations. Minor Observations (Non-Blocking)The suppress annotations in Overall, this is a clean, well-structured fix that correctly addresses the root cause. |
app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt
Show resolved
Hide resolved
app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/CipherManagerImpl.kt
Show resolved
Hide resolved
|
Fixed Issues (2)Great job! The following issues were fixed in this Pull Request
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #6592 +/- ##
==========================================
+ Coverage 85.78% 85.95% +0.17%
==========================================
Files 937 800 -137
Lines 59541 57157 -2384
Branches 8324 8270 -54
==========================================
- Hits 51075 49130 -1945
+ Misses 5567 5154 -413
+ Partials 2899 2873 -26
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
network/src/test/kotlin/com/bitwarden/network/service/CiphersServiceTest.kt
Outdated
Show resolved
Hide resolved
network/src/test/kotlin/com/bitwarden/network/service/CiphersServiceTest.kt
Outdated
Show resolved
Hide resolved
network/src/test/kotlin/com/bitwarden/network/service/CiphersServiceTest.kt
Outdated
Show resolved
Hide resolved
| ): UnarchiveCipherResult { | ||
| val userId = activeUserId ?: return UnarchiveCipherResult.Error(NoActiveUserException()) | ||
| return cipherView | ||
| .encryptCipherAndCheckForMigration(userId = userId, cipherId = cipherId) |
There was a problem hiding this comment.
So this was completely unnecessary?
There was a problem hiding this comment.
At some point it was because the archive endpoints were not returning the entire updated cipher, it was only returning the "mini" version. This was never updated when that changed.
Remove unnecessary encryptCipherAndCheckForMigration call from archive
and unarchive flows. This migration check triggered a full cipher update
via PUT /api/ciphers/{id}, which the server rejects with HTTP 400 for
users with restricted permissions on org-owned ciphers.
Archive and unarchive now call the API directly and upsert the
server-returned cipher to disk, following the restoreCipher pattern.
…hers Copy collectionIds from the original CipherView onto the response cipher before saving to disk, preventing loss of collection associations for org-owned ciphers. Update tests to verify the preserved collectionIds.
2c5ae02 to
775d881
Compare


🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-32802
📔 Objective
Fix a 400 error when users with restricted permissions ("can view, hidden passwords" or "can edit, hidden passwords") attempt to archive or unarchive org-owned ciphers.
Root cause:
archiveCipher()andunarchiveCipher()inCipherManagerImplunnecessarily calledencryptCipherAndCheckForMigration()before the archive/unarchive API call. When the SDK generated a new cipher key (migration), this triggered a fullPUT /api/ciphers/{id}update that the server rejected with HTTP 400 for users lacking edit permissions — aborting the archive before it was ever attempted.Fix: Remove the encryption/migration check from archive and unarchive flows entirely. These operations now call the archive/unarchive API directly and upsert the server-returned cipher to disk, following the existing
restoreCipherpattern. The server handles all state changes; no client-side encryption is needed.Changes:
SyncResponseJson.Cipherinstead ofUnitArchiveCipherResponseJson/UnarchiveCipherResponseJsonwith 400 error recoveryencryptCipherAndCheckForMigrationfrom archive/unarchive; upsert server response directlyArchiveCipherResponseJsonandUnarchiveCipherResponseJsonsealed classes