fix(api): resolve every secret before writing any of them in PublicSecretsView.put - #1006
Open
omlahore wants to merge 1 commit into
Open
fix(api): resolve every secret before writing any of them in PublicSecretsView.put#1006omlahore wants to merge 1 commit into
omlahore wants to merge 1 commit into
Conversation
…cretsView.put E2EESecretsView.put builds a secret_objects list first and says why: "a late foreign, missing, or rotating ID would leave an earlier update committed". PublicSecretsView.put still saved as it iterated, so a batch whose second entry is soft-deleted, rotating, or attempting to unseal returned 400 or 404 after the first entry had already been written. There is no transaction.atomic in this view and the surrounding try has only a finally, so an early return commits rather than rolls back. Ordering is the only thing that makes the batch atomic, which is what c192966 fixed for the E2EE view. The lookup, rotating-secret and seal-permanence checks move into a preflight loop, and the write loop zips over the resolved objects. No behaviour change for a batch that passes validation.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to c192966, which fixed this for the other view.
The problem
E2EESecretsView.putresolves every secret intosecret_objectsbefore writing any of them, and the comment says exactly why:PublicSecretsView.putstill saved as it iterated. It callssecret_obj.save(trigger_sync=False)inside the loop, and three separate early returns can fire on a later entry:So
PUT /v1/secretswith[{good}, {rotating}]answers 400 and the first secret is already written, with nothing telling the caller which part of the batch applied.Nothing rolls it back. There is no
transaction.atomicanywhere insecrets.py, and the surroundingtryhas only afinally, noexcept. An earlyreturninside an atomic block would commit anyway, so ordering is the only thing that can make this batch atomic, which is what c192966 established for the E2EE view.The change
The lookup, the rotating-secret check and the seal-permanence check move into a preflight loop, and the write loop zips over the already-resolved objects. Same shape and same ordering as
E2EESecretsView.put.No behaviour change for a batch that passes validation: same queries, same saves, same order, same response.
Verification
Two tests, mirroring the existing
test_rotating_secret_is_rejected_before_any_updatefor the E2EE view:Each asserts the 400, then
first.save.assert_not_called(),env.save.assert_not_called()and no audit event.I checked they fail for the right reason rather than passing by accident. With the view change stashed, both fail on exactly that line and not on the status code, because the endpoint already returned 400 correctly before this change:
That is the whole bug: the right answer, after the wrong write.
Full backend suite with the fix: 1505 passed.
Not included
The
_resolve_secret_tagserror path at the end of the write loop can still return early after earlier saves. It needs an organisation lookup per secret and could be hoisted too, but it changes when tags are resolved relative to encryption, so it is a separate decision rather than something to fold in here.