fix(storage): don't query the encryption key registry when storage is off (unblocks backend:dev:saas) - #7265
Merged
Conversation
jbrunton96
previously approved these changes
Aug 3, 2026
…s off Deployments that never enable storage - the SaaS flavour among them - query file_encryption_keys during bean creation, because the decrypt-only probe runs whenever storage.encryption.enabled is false. That table only exists if ddl-auto managed to create it, and ddl-auto logs and continues when it cannot, so a schema warning becomes a refusal to start. Reported against 'task backend:dev:saas', where storage.enabled is false and the schema is Supabase's stirling_pdf. - The boot probe now runs only when storage.enabled is true, so a deployment that does not use storage never touches the table. - Registry reads are wrapped: the boot probe degrades to 'no keys' instead of propagating, and suppressDirectDownloads() fails SAFE (suppresses) rather than handing out a presigned URL it cannot vouch for. Losing the direct-download fast path is recoverable; serving ciphertext is not. Safety is unchanged. The decorator is still installed unconditionally, so any blob carrying the SPDFEAR1 magic is decrypted via lazy materialisation or fails loudly; the probe only ever bought earlier master-key verification. A node that can actually serve stored files has storage.enabled by definition, which is why the drifted-node test now configures it that way. Tests: storage-disabled never calls count(); an unreadable registry still boots and still suppresses direct downloads; the decorator stays installed with storage off; storage-enabled still probes.
ConnorYoh
force-pushed
the
claude/fix-saas-storage-encryption-probe
branch
from
August 3, 2026 14:49
e302049 to
0576a27
Compare
jbrunton96
approved these changes
Aug 3, 2026
reecebrowne
approved these changes
Aug 3, 2026
ConnorYoh
added a commit
that referenced
this pull request
Aug 4, 2026
Addresses the Aikido code-quality finding on #7155: rotateMasterKey() and verifyMasterKey() loaded every key row and filtered in memory. Both now push the predicate into the query (findByMasterKeyVersionLessThan / countByMasterKeyVersionLessThan), so the rotation check costs a counted query rather than a full table read. The SaaS boot-probe fix that originally shared this commit landed on its own in #7265, so only the rebase leftovers remain here: one assertion proving a storage-disabled node resolves no master key at boot.
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.
Description of Changes
Fixes a startup failure introduced by #7155 and reported against
task backend:dev:saas.What goes wrong
StorageProviderConfig.storageEncryptionState(...)is created on every startup, in every profile. Whenstorage.encryption.enabledis false — the default, and what SaaS ships — the||short-circuit evaluatesfileEncryptionKeyRepository.count(), a live query againstfile_encryption_keys:That table only exists if
ddl-auto=updatemanaged to create it. When it cannot — permissions on a shared Supabase branch DB, concurrent DDL from several developers, schema ordering — ddl-auto logs and continues, so the situation used to be a warning nobody noticed. Now it is a query that throws during bean creation and takes the whole context down.Two things make this sting in SaaS specifically:
storage.enabledis false there, so before this feature nothing ever touched the table; andhibernate.default_schema=stirling_pdfmeans the table has to exist in a schema the app may not be able to create in.There is a second exposure on the request path:
suppressDirectDownloads()also counts (60s cached), so even a surviving boot could 500 on downloads.Fix
storage.enabledis true, so a deployment that does not use storage never touches the table.suppressDirectDownloads()fails safe by suppressing rather than issuing a presigned URL it cannot vouch for. Losing the direct-download fast path is recoverable; serving ciphertext is not.Safety is unchanged, and that is the important part. The decorator is still installed unconditionally, so any blob carrying the
SPDFEAR1magic is still decrypted via lazy materialisation or fails loudly — the eager probe only ever bought earlier master-key verification. A node that can actually serve stored files hasstorage.enabledon by definition, which is exactly the node the drifted-node protection is for; that test now configures it that way, and a new test pins that the decorator remains installed even with storage off.Tests — storage-disabled never calls
count(); an unreadable registry still boots and still suppresses direct downloads; the decorator stays installed with storage off; storage-enabled still probes. Full proprietary suite green apart from the pre-existing Windows-symlinkFolderIdentitiesTestfailure, which is environmental and unrelated.Note on scope: deliberately minimal so it can land quickly. The Aikido
findAll()code-quality finding lives in #7173 only (rotateMasterKeydoes not exist on main), so it is fixed there rather than here. #7173 will be rebased once this merges.Checklist
General
Documentation
Translations (if applicable)
scripts/counter_translation.pyUI Changes (if applicable)
Testing (if applicable)
task checkto verify linters, typechecks, and tests pass