Skip to content

improvement(credentials): hold unsaved keyless subjects so trust policies applied later still match - #10011

Merged
waleedlatif1 merged 3 commits into
stagingfrom
improvement/keyless-pending-subject
Nov 13, 2026
Merged

waleedlatif1 merged 3 commits into
stagingfrom
improvement/keyless-pending-subject

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Problem 1, a subject that dies with the dialog: a keyless subject only lived as long as the connect dialog. Every open minted a new random subject with a 24-hour proof, and nothing was stored. A customer whose trust policy goes through change review (Terraform, a merge request) could never save: by the time the policy was live, the subject was gone.
  • Fix: Sim holds an issued, unsaved subject for 30 days. It is held for the person it was issued to, and the hold restarts each time the subject is shown or renewed. This follows the common pattern for vendor-issued trust identifiers, which stay stable across sessions until used (Datadog's AWS external ID, Fivetran's setup ID).
    • New table: workload_identity_pending_subject (migration 0457, additive), one row per workspace, user and provider. A person keeps at most 20 held subjects per provider in a workspace; the least recently shown are dropped.
    • Connect dialog: reopening it shows the held subject. When it opens on one from an earlier visit, a Trust setup dropdown offers "Use the subject issued " (default) or "Issue a new subject". The Subject hint says how long Sim holds it, and no longer says "Unique to this credential", which read as if the subject were the credential's ID.
    • Reconnect: unchanged. Opening the dialog holds nothing, and "Issue a new subject" always mints a new one.
    • v2 API and CLI:
      • POST /api/v2/credentials/workload-identity/subjects still issues a new subject per call.
      • A new optional subject renews the proof for a held subject: sim credentials keyless-subject <provider> --subject <subject>.
      • The response adds subjectIssuedAt and subjectHeldUntil.
      • Renewing a subject that isn't held for the caller returns WORKLOAD_IDENTITY_SUBJECT_NOT_PENDING. The CLI's hints now say "renew" for an expired proof.
    • Concurrency:
      • Saving a credential deletes the held row inside the same transaction.
      • Renewal takes the same subject lock saves take, so it never offers a subject a concurrent save just claimed.
      • A subject that a live credential holds is dropped.
      • An unreadable sibling credential doesn't wipe holds.
  • Problem 2, Databricks verification bypassed the org's egress: saving a Databricks credential checks the workspace identity (SCIM /Me) with plain fetch. That bypassed the organization's outbound routing, so the check left from shared IPs and a workspace whose IP access list allows only the organization's dedicated egress IPs returned 403.
    • Fix: it now goes through secureFetchWithValidation, the same guarded and org-routed path the Snowflake and client-credentials verifiers use. The token exchange is unchanged.
    • Error reason: a refusal now carries Databricks' own reason (an IP access list vs. a missing entitlement).
  • Clearer refusals:
    • An Entra Conditional Access block (AADSTS53003) and a Google VPC Service Controls denial are named, instead of being reported as a federation mismatch or a missing IAM role.
  • Unchanged: proofs (24h, bound to one user, workspace and provider), stored credentials, the subject format, and the v2 default. The migration runs before the deploy, and older pods ignore the table.

Type of Change

  • Bug fix
  • Improvement

Testing

  • New integration suite workload-identity-pending-subject.integration.ts (real Postgres, provisioned through the versioned migrations) covers:
    • reopen returns the same subject;
    • a save 10 days later works on a renewed proof;
    • a saved subject is never offered again, even after its credential is deleted;
    • a subject a credential already holds is dropped;
    • reconnect releases the subject;
    • renewing someone else's subject is refused;
    • an expired hold is refused and cleaned up;
    • an unreadable sibling doesn't drop the hold;
    • the 20-subject cap, and a recently renewed subject survives it.
  • Existing suite: workload-identity-subject-reuse.integration.ts passes. Both suites now serve the Databricks identity fixture through the egress guard.
  • New unit tests:
    • Databricks verification goes through the egress guard, not global fetch;
    • a 403 carries Databricks' reason;
    • an egress refusal is reported as host not allowed;
    • Entra 53003 and Google VPC-SC messages;
    • the CLI --subject, an empty --subject, and the renewal hints.
  • Red proofs: each guard was reverted and its test went red. That covers the release on save, the held check, ignoring unreadable siblings, the hold expiry, the per-user renew filter, the cap and its eviction order, cross-workspace signing, the v2 default, the Databricks egress path, its reason and refusal mapping, the Entra and VPC-SC messages, and the CLI branches.
  • Concurrency: the issuer advisory lock and the renew-vs-save subject lock are not covered by a test. A parallel test passed with the lock removed, so it wasn't shipped.
  • Unit runs: 326 credential tests (workload identity, prepare, v2 subjects route, orchestration, Databricks, Google, Microsoft) and 27 sim-cli credential tests pass.
  • Lint and audits: bun run lint, check:audits (all), check:migrations origin/staging, the drizzle schema sync, check-block-registry.ts origin/staging and check:test-types pass.
  • Type-check and the full suite run in CI.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing (new tests pass the test-audit authoring gate)
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel

vercel Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 13, 2026 9:43pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge, with the earlier reconnect-mode issue fixed and no new actionable findings.

Summary

Sim now holds unsaved keyless subjects for 30 days, so delayed trust policies can keep using the same subject.

  • Unsaved keyless subjects stay available while cloud trust policies are set up.
  • Databricks credential checks now use the organization’s guarded outbound route.
  • Entra and Google refusals now name their access-policy blocks.

The earlier reconnect-mode finding is fixed: reconnectAuthType checks heldTrust, so keeping the saved subject no longer hides the stored keyless mode. No new actionable issues were found.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Request subject] --> B[Hold subject for 30 days]
  B --> C[Configure cloud trust]
  C --> D[Renew proof for same subject]
  D --> B
  D --> E[Verify and save credential]
  E --> F[Delete held row in same transaction]
Loading

Reviews (3) · Last reviewed commit: "test(credentials): save on the proof a r..." · Reviewed by Greptile

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 33 files

Turn on auto-fix | Re-trigger cubic

…, keep keyless reconnects on their mode, and harden held-subject renewal
@waleedlatif1
waleedlatif1 force-pushed the improvement/keyless-pending-subject branch from a78d52d to 6d01b28 Compare November 13, 2026 21:25
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 40 files

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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 issues found across 41 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Turn on auto-fix | Re-trigger cubic

This branch was successfully deployed

1 active deployment
Preview — 68e83fd1 Deployed Nov 13, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant