feat(api-keys): add multi-tenant persistence layer - #2159
Draft
nvaghela-oss wants to merge 2 commits into
Draft
nvaghela-oss wants to merge 2 commits into
nvaghela-oss wants to merge 2 commits into
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueComment |
nvaghela-oss
force-pushed
the
feat/api-keys-multi-tenant-schema
branch
from
September 29, 2026 21:18
0aee203 to
6c8c8c8
Compare
nvaghela-oss
force-pushed
the
feat/api-keys-multi-tenant-persistence
branch
from
September 29, 2026 22:44
13d7c44 to
847db42
Compare
nvaghela-oss
changed the base branch from
feat/api-keys-multi-tenant-schema
to
feat/multi-tenant-api-keys
September 29, 2026 22:44
nvaghela-oss
marked this pull request as draft
September 29, 2026 22:48
nvaghela-oss
force-pushed
the
feat/api-keys-multi-tenant-persistence
branch
from
September 30, 2026 00:56
847db42 to
a161c01
Compare
Add Spring Data Cassandra models, repositories, and DAOs for the multi-tenant API Keys tables: - keys.nca_id on KeyModel and KeyVo - keys_by_account_owner_and_service with encrypted key details, partition lookups, and paged account and issuer scans on the storage-attached indexes - owner_status_by_account and owner_status_by_account_and_service with an effective-status helper - key_operations_by_id for bulk operation progress and paging state Add Testcontainers integration tests for each DAO. Closes #2051 Signed-off-by: Nilesh Vaghela <[email protected]>
…sor paging Match the Cloud Tasks paging pattern: account key listings return AccountKeysSliceVo with a hex paging-state cursor and limit set only when more rows remain. A malformed cursor is reported as a bad request. Add unit and integration coverage for batch writes, deletes, paging boundaries, invalid cursors, effective owner status, and key operations. Relates to #2051 Signed-off-by: Nilesh Vaghela <[email protected]>
nvaghela-oss
force-pushed
the
feat/api-keys-multi-tenant-persistence
branch
from
September 30, 2026 08:04
a161c01 to
c7e241c
Compare
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.
TL;DR
Adds the Java persistence layer for the multi-tenant API Keys tables: models, Spring Data repositories, DAOs, and Testcontainers integration tests. Targets
feat/multi-tenant-api-keys, which already has the schema from #2157.Additional Details (optional for docs, build, test, refactor, ci, chore, style, and revert PRs)
#2157 adds the Cassandra tables. The service cannot read or write them until there is a persistence layer. This PR adds that layer. It does not change any API behavior or existing write paths.
What changed:
keysgains annca_idcolumn.KeyModelandKeyVoboth getncaIdbecauseEncryptedModelConvertermaps each model column to a same-named value-object field.nca_idis a plain column, not part of the encrypted payload. Old rows read it as null.keys_by_account_owner_and_servicegetsKeyByAccountOwnerAndServiceModel, a@ValueObject, a converter wrapper that applies expiration status on read, andAccountKeysDao:savewrites thekeyshash row and the account row in one logged batch.getandlistare partition lookups by account, owner, and optional issuer.listByAccountandlistByAccountAndServicepage through the storage-attached indexes and returnAccountKeysSliceVo. This follows the Cloud Tasks paging pattern: the cursor is the hex-encoded Cassandra paging state, andcursorandlimitare set only when more rows remain. A malformed cursor raisesBadRequestException. Other query failures are passed through unchanged.deleteremoves both rows in one batch.owner_status_by_accountandowner_status_by_account_and_serviceget models, repositories, andAccountOwnerStatusDao. Saves keepcreated_atand refreshupdated_at.getEffectiveStatusreturns SUSPENDED if the owner is suspended for the whole account or for the issuer service. A missing row means ACTIVE.key_operations_by_idgetsKeyOperationModelandKeyOperationsDao.createassigns an ID, sets PENDING status and zero counters, and usesIF NOT EXISTSso it never overwrites an existing operation.updatewrites progress and refreshesupdated_at.Limitations:
keys_by_owner_and_servicewrite path is unchanged.KeysDaostill does not writenca_idor account rows. Dual-write and read switching are follow-up work.operationandactor_typeare plain strings for now. Their values are not defined yet.operation_statususes a small lifecycle enum: PENDING, RUNNING, COMPLETED, FAILED.created_at. The status value is still last-write-wins.For the Reviewer
Start with
AccountKeysDao(batching and cursor handling) and theKeyVo.ncaIdchange. Every existing key write now goes through a model that has annca_idcolumn. Spring Data skips null columns on insert, so single-tenant writes still work on clusters that already applied04_add_multi_tenant_schema.up.sql.Deployments must apply the
04migration from #2157 before this code starts readingnca_id.For QA (optional for docs, build, test, refactor, ci, chore, style, and revert PRs)
Ran
bazel test //src/control-plane-services/api-keys/...with local Docker.tests_coverage,image_contract_test, andnotice_check_testpass. All 326 JUnit tests pass. DAO integration tests run on Cassandra 5 through Testcontainers.The new tests cover:
nca_idin CQL, and no plaintext inkey_detailsnca_id, and repeated saves keeping one row with the latest statusKeysDaopath writing nonca_idand no account rowcreated_atkept on updateNo manual QA is needed. There is no API change.
Issues
Closes #2051
Relates to #2048
Checklist