Skip to content

feat(deployment): open hidden variables sealed under a team's data key - #4474

Merged
baktun14 merged 2 commits into
mainfrom
feat/deployment-open-team-sealed-secrets
Oct 18, 2026
Merged

baktun14 merged 2 commits into
mainfrom
feat/deployment-open-team-sealed-secrets

Conversation

@baktun14

@baktun14 baktun14 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Why

Part of CON-1213. Builds on #4473 (merged).

Every read path for a deployment's hidden variables can now open a token sealed under the team's data key. The writer that seals under it comes in the next PR, behind team_data_keys, so this PR has to be in prod before that flag is turned on.

What

  • SdlSecretsService.openStored takes the row's organizationId. A token whose header carries an org claim opens under the key and binding ({ org, dseq }) of the organization the row is filed in. A member's token keeps the { sub, dseq } binding as before. The row decides the owner and the header only says which kind.
  • Patch, update, definition, redeploy inheritance and the lease manifest pass the row's organization. Inheritance accepts a team-sealed source whose filer has deleted their account.
  • A team-claimed token on a row with no organization is refused as unreadable. A member's token whose filer is gone stays a 409, as today.
  • rekey-user-data-key leaves team-sealed rows to the team and reports them as deploymentsSealedForOrganization, in its end report and its batch log.
  • Runbook deployment-secrets.md: the re-key report field, and the decrypt-failure triage compares a team token's kid with the organization's data_keys rather than the member's.

Rollback floor: once team_data_keys is on, the API must not roll back below this release. Older versions can't open team-sealed tokens, so patch, redeploy and manifest sends would fail for those deployments.

Testing

  • Unit: writer, lease manifest, inheritance, sdl-secrets, rekey.
  • Integration: deployment writer, deployment settings, apply update, rekey, rewrap, user (363 tests).
  • Functional: deployment-patch, deployment-definition, deployment-sealed-secrets, deployments, deployment-patch-in-background, organization-wallet.
  • Mutation on changed lines: 97.0% (64 of 66).

@baktun14
baktun14 requested a review from a team as a code owner October 18, 2026 02:06

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 19 billable files and costs up to $4.75.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 7 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 2 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: akash-network/console/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: e732a7dd-22c1-4b26-924a-3eaf218f03c5
📥 Commits

Reviewing files that changed from the base of the PR and between b2750aa and 0dc4a8f.

📒 Files selected for processing: 19
  • apps/api/docs/runbooks/deployment-secrets.md
  • apps/api/scripts/rehearseDeploymentSecrets.ts
  • apps/api/src/deployment/repositories/deployment-setting/deployment-setting.repository.ts
  • apps/api/src/deployment/services/deployment-writer/deployment-writer.service.spec.ts
  • apps/api/src/deployment/services/deployment-writer/deployment-writer.service.ts
  • apps/api/src/deployment/services/lease-manifest/lease-manifest.service.spec.ts
  • apps/api/src/deployment/services/lease-manifest/lease-manifest.service.ts
  • apps/api/src/deployment/services/sdl-secrets-inheritance/sdl-secrets-inheritance.service.spec.ts
  • apps/api/src/deployment/services/sdl-secrets-inheritance/sdl-secrets-inheritance.service.ts
  • apps/api/src/deployment/services/sdl-secrets/sdl-secrets.service.spec.ts
  • apps/api/src/deployment/services/sdl-secrets/sdl-secrets.service.ts
  • apps/api/src/secret/services/data-key-rekey/data-key-rekey.service.integration.ts
  • apps/api/src/secret/services/data-key-rekey/data-key-rekey.service.spec.ts
  • apps/api/src/secret/services/data-key-rekey/data-key-rekey.service.ts
  • apps/api/test/functional/deployment-definition.spec.ts
  • apps/api/test/functional/deployment-patch.spec.ts
  • apps/api/test/functional/deployment-sealed-secrets.spec.ts
  • apps/api/test/functional/deployments.spec.ts
  • apps/api/test/functional/organization-wallet.spec.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No critical issues — one minor suggestion inline.

Reviewed changes

  • Team-sealed token opening in SdlSecretsService: openStored now takes the row's organizationId and routes an org-claimed token to the organization's data key with the { org, dseq } binding taken from the row; member tokens keep the { sub, dseq } binding, a team-claimed token on an organization-less row is refused as unreadable, and a member token on a row whose filer is gone stays a 409.
  • Read paths pass the row's organization: patch preparation, saved-patch apply, the lease manifest, redeploy inheritance and the rekey pass all forward the row's own organizationId; npx tsc --noEmit plus a repo-wide grep of openStored confirm no caller was missed.
  • Inheritance accepts a team-sealed source whose filer deleted their account (outlivesItsFiler), since the team's key outlives them; anything else with a null filer still answers 404.
  • rekey-user-data-key leaves team-sealed rows to the team, counting them as deploymentsSealedForOrganization ahead of the kid checks so they cannot surface as deploymentsUnderUnknownKey.
  • Binding and key-ownership semantics verified at the cipher layer: the row (not the header) decides the key owner and the binding, and SecretCipherService enforces exact header-claim equality plus org-owned kid lookup, so a token moved between rows, users or organizations fails closed rather than decrypting.
  • Tests: unit specs for sdl-secrets, inheritance, lease-manifest, deployment-writer and rekey pass (556 tests), and the typecheck is clean.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using GLM-5.3 | 𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found — the prior review's runbook finding is fully addressed.

Reviewed changes

Since the previous pullfrog review, the one open finding was closed by 2e37d98 (the rebase to 6338b7c8 left the reviewed patch byte-identical):

  • Documented deploymentsSealedForOrganization in the re-key runbook: the report-field list now names it and explains that the user's key never sealed those deployments, so they neither move nor hold back the retired key's deletion.
  • Retargeted §5.1 triage for team-sealed tokens: an operator now compares a team token's claims.kid against the organization's data_keys rows (organization_id = claims.org) instead of the user's, so a legitimate team-sealed state no longer reads as tampering.
  • Carried the team-sealed count into DATA_KEY_REKEY_BATCH: #counts logs sealedForOrganization mid-run, and the rekey spec asserts it alongside the end-report counts.
  • Updated the events table's USER_DATA_KEY_UNWRAPPED row to carry userId, or organizationId for a team's key — verified against DataKeyUnwrapperService, which spreads the owner into the log.

The new runbook text checks out against the code: the org-claim routing and org-owned data_keys lookup are real, and "a team token whose kid the team does not hold is tampering" holds because no org-side rekey exists to orphan one. The changed rekey spec passes (22 tests).

Pullfrog  | View workflow run | Using GLM-5.3 | 𝕏

Base automatically changed from feat/organization-team-data-keys to main October 18, 2026 06:51
A stored token whose header names an organization instead of a member opens under
the data key and binding of the organization its row is filed in. Patching,
redeploying, inheriting and sending the manifest of a team deployment read it
that way, including after the member who filed the row deleted their account.
A user re-key leaves such a row to the team and counts it apart.

Nothing seals under a team's key yet, so every stored token still opens as before.

Part of CON-1213
…riage team tokens

The re-key's batch log now carries the count of team deployments it leaves to
the team's key, as its end report already did. The runbook names that report
field and tells the decrypt-failure triage to compare a team token's kid with
the organization's data keys rather than the member's.

Part of CON-1213
@baktun14
baktun14 force-pushed the feat/deployment-open-team-sealed-secrets branch from 2e37d98 to 0dc4a8f Compare October 18, 2026 07:10
@codecov

codecov Bot commented Oct 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.07%. Comparing base (b2750aa) to head (0dc4a8f).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4474      +/-   ##
==========================================
+ Coverage   93.87%   94.07%   +0.20%     
==========================================
  Files        1722     1613     -109     
  Lines       49516    46718    -2798     
  Branches    12117    11565     -552     
==========================================
- Hits        46481    43949    -2532     
+ Misses       2720     2470     -250     
+ Partials      315      299      -16     
Flag Coverage Δ *Carryforward flag
api 96.01% <100.00%> (+<0.01%) ⬆️
deploy-web 92.56% <ø> (ø) Carriedforward from b2750aa
log-collector ?
notifications 95.76% <ø> (ø) Carriedforward from b2750aa
provider-console 81.68% <ø> (ø) Carriedforward from b2750aa
provider-inventory ?
provider-proxy 92.21% <ø> (ø) Carriedforward from b2750aa
tx-signer ?

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
...eployment-setting/deployment-setting.repository.ts 99.30% <ø> (ø)
...ces/deployment-writer/deployment-writer.service.ts 100.00% <100.00%> (ø)
.../services/lease-manifest/lease-manifest.service.ts 100.00% <100.00%> (ø)
...ets-inheritance/sdl-secrets-inheritance.service.ts 100.00% <100.00%> (ø)
...oyment/services/sdl-secrets/sdl-secrets.service.ts 100.00% <100.00%> (ø)
.../services/data-key-rekey/data-key-rekey.service.ts 100.00% <100.00%> (ø)

... and 109 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@baktun14
baktun14 added this pull request to the merge queue Oct 18, 2026
Merged via the queue into main with commit 97d5730 Oct 18, 2026
84 checks passed
@baktun14
baktun14 deleted the feat/deployment-open-team-sealed-secrets branch October 18, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant