Skip to content

Fix vault secret label validation#22257

Merged
prashantkumar1982 merged 12 commits intodevelopfrom
codex/vault-secret-labeling-bug
May 2, 2026
Merged

Fix vault secret label validation#22257
prashantkumar1982 merged 12 commits intodevelopfrom
codex/vault-secret-labeling-bug

Conversation

@prashantkumar1982
Copy link
Copy Markdown
Contributor

Summary

  • Fixes vault secret label validation for the org-ID-as-secret-owner flow so gateway allowlist requests can be forwarded when the gateway cannot know the org ID.
  • Keeps JWT-authenticated writes strict by validating labels against the org ID and rejecting workflow-owner-labeled ciphertexts.
  • Resolves vault-node create/update identity before label validation, and updates CRE vault tests/helpers to encrypt secrets explicitly with workflow owner or org ID as appropriate.

@github-actions
Copy link
Copy Markdown
Contributor

I see you updated files related to core. Please run make gocs in the root directory to add a changeset as well as in the text include at least one of the following tags:

  • #added For any new functionality added.
  • #breaking_change For any functionality that requires manual action for the node to boot.
  • #bugfix For bug fixes.
  • #changed For any change to the existing functionality.
  • #db_update For any feature that introduces updates to database schema.
  • #deprecation_notice For any upcoming deprecation functionality.
  • #internal For changesets that need to be excluded from the final changelog.
  • #nops For any feature that is NOP facing and needs to be in the official Release Notes for the release.
  • #removed For any functionality/config that is removed.
  • #updated For any functionality that is updated.
  • #wip For any change that is not ready yet and external communication about it should be held off till it is feature complete.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 29, 2026

✅ No conflicts with other open PRs targeting develop

@trunk-io
Copy link
Copy Markdown

trunk-io Bot commented Apr 29, 2026

Static BadgeStatic BadgeStatic BadgeStatic Badge

View Full Report ↗︎Docs

@prashantkumar1982 prashantkumar1982 added the build-publish Build and Publish image to SDLC label Apr 29, 2026
@prashantkumar1982 prashantkumar1982 marked this pull request as ready for review April 29, 2026 21:57
@prashantkumar1982 prashantkumar1982 requested review from a team as code owners April 29, 2026 21:57
timothyF95
timothyF95 previously approved these changes Apr 29, 2026
russell-stern
russell-stern previously approved these changes Apr 30, 2026
@prashantkumar1982 prashantkumar1982 added build-publish Build and Publish image to SDLC and removed build-publish Build and Publish image to SDLC labels Apr 30, 2026
timothyF95
timothyF95 previously approved these changes Apr 30, 2026
russell-stern
russell-stern previously approved these changes Apr 30, 2026
@prashantkumar1982 prashantkumar1982 added build-publish Build and Publish image to SDLC and removed build-publish Build and Publish image to SDLC labels Apr 30, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46977cafe4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 332 to 336
vaultCapRequest.RequestId = req.ID
if err := setAuthorizedIdentityFields(&vaultCapRequest, authResult); err != nil {
return h.errorResponse(ctx, gatewayID, req, api.FatalError, err)
}
for idx, encryptedSecret := range vaultCapRequest.EncryptedSecrets {
if encryptedSecret != nil && encryptedSecret.Id != nil && normalizeOwner(encryptedSecret.Id.Owner) != normalizeOwner(authorizedOwner) {
h.lggr.Debugw("create secrets request owner mismatch", "requestID", req.ID, "secretOwner", encryptedSecret.Id.Owner, "authorizedOwner", authorizedOwner, "index", idx)
return h.errorResponse(ctx, gatewayID, req, api.FatalError, fmt.Errorf("secret ID owner %q does not match authorized owner %q at index %d", encryptedSecret.Id.Owner, authorizedOwner, idx))
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce org-only owner checks for JWT write requests

In the node-side gateway handler path (used by core/services/ocr2/delegate.go), write requests are now forwarded immediately after setAuthorizedIdentityFields without any owner-level guard. Because capability-side identity validation now accepts either WorkflowOwner or OrgId (validateOwnerMatchesResolvedIdentity), a JWT-authenticated request that carries both fields can submit workflow-owner-labeled secret IDs/ciphertext and still pass, which weakens the intended JWT strictness for org-scoped writes. This regression is specific to requests processed through this node-side handler, where the removed per-item owner check previously blocked that case.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f3939b9139

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +630 to +631
validationRequest = proto.Clone(createSecretsRequest).(*vaultcommon.CreateSecretsRequest)
validationRequest.WorkflowOwner = ""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate JWT org-label enforcement behind org-owner flag

Clearing WorkflowOwner whenever OrgId is present forces create/update validation to accept only org-labeled ciphertext, even when VaultOrgIdAsSecretOwnerEnabled is off. In the configuration where JWT auth is enabled but org-as-owner migration is disabled, this rejects workflow-owner-labeled writes and pushes clients toward org-labeled ciphertexts that the read path later validates against workflow owner only, causing secrets to be unreadable. This strict JWT-only org-label check should be conditioned on the org-owner gate (or equivalent migration mode), not just on OrgId being non-empty.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

we're only clearing from gateway, that too from top-level.
top-level field shouldn't be set or used at gateway level

Comment on lines +195 to +196
if orgIDGateEnabled && s.orgID == "" {
return nil, errors.New("org_id is required when VaultOrgIdAsSecretOwnerEnabled is enabled")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid runtime outage when org ID is missing at startup

This new early return turns an empty s.orgID into a hard failure for every secret fetch whenever VaultOrgIdAsSecretOwnerEnabled is on. The engine startup path explicitly tolerates org-resolution failures and continues without org ID, so after this change a transient resolver/linking failure at startup can leave workflows running but permanently unable to fetch secrets until restart/relink. Either preserve workflow-owner fallback in this case or fail engine initialization immediately when the gate is enabled and org resolution did not succeed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is ok to fail is orgID is not fetchable on workflow nodes.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 876a2f513f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +195 to +196
if orgIDGateEnabled && s.orgID == "" {
return nil, errors.New("org_id is required when VaultOrgIdAsSecretOwnerEnabled is enabled")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Avoid hard-failing secret reads when startup org lookup failed

Returning an error as soon as VaultOrgIdAsSecretOwnerEnabled is on and s.orgID is empty makes every GetSecrets call fail for the lifetime of that engine instance, even though startup explicitly tolerates org-resolution failures and continues running. In practice, a transient resolver/linking outage during Engine.start now becomes a persistent secrets outage until restart/relink, instead of falling back to workflow-owner reads as before.

Useful? React with 👍 / 👎.

Comment on lines 333 to 338
if err := setAuthorizedIdentityFields(&vaultCapRequest, authResult); err != nil {
return h.errorResponse(ctx, gatewayID, req, api.FatalError, err)
}
for idx, encryptedSecret := range vaultCapRequest.EncryptedSecrets {
if encryptedSecret != nil && encryptedSecret.Id != nil && normalizeOwner(encryptedSecret.Id.Owner) != normalizeOwner(authorizedOwner) {
h.lggr.Debugw("create secrets request owner mismatch", "requestID", req.ID, "secretOwner", encryptedSecret.Id.Owner, "authorizedOwner", authorizedOwner, "index", idx)
return h.errorResponse(ctx, gatewayID, req, api.FatalError, fmt.Errorf("secret ID owner %q does not match authorized owner %q at index %d", encryptedSecret.Id.Owner, authorizedOwner, idx))
}
}

h.lggr.Debugf("Processing authorized and normalized create secrets request [%s]", vaultCapRequest.String())
vaultCapResponse, err := h.secretsService.CreateSecrets(ctx, &vaultCapRequest)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reinstate JWT owner guard before forwarding create requests

The node-side gateway handler now forwards create requests immediately after setting authorized identity fields, but no longer enforces that each secret identifier owner matches the authorized owner. Because capability-side validation accepts either resolved WorkflowOwner or OrgId, JWT requests that include both identities can now pass with workflow-owner IDs in this path (especially when gateway-side label checks are skipped due to missing cached public key), weakening the intended org-scoped JWT write enforcement.

Useful? React with 👍 / 👎.

return workflowOwner, requestDigest, nil
}

func validateOrgIDOwnedVaultRequest(req jsonrpc.Request[json.RawMessage], orgID string) error {
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.

Can we move these to the validator file? I'm assuming other parts of the code will want to use these as well.

@cl-sonarqube-production
Copy link
Copy Markdown

@prashantkumar1982 prashantkumar1982 added this pull request to the merge queue May 2, 2026
Merged via the queue into develop with commit a117e73 May 2, 2026
234 checks passed
@prashantkumar1982 prashantkumar1982 deleted the codex/vault-secret-labeling-bug branch May 2, 2026 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build-publish Build and Publish image to SDLC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants