Skip to content

feat(api): expose credential sharing and SSO administration - #8770

Open
waleedlatif1 wants to merge 1 commit into
stagingfrom
codex/credential-sharing-sso-api
Open

waleedlatif1 wants to merge 1 commit into
stagingfrom
codex/credential-sharing-sso-api

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • Add credential member management, organization SSO providers and policy, and verified-domain administration to the public API.
  • Expose all 14 operations through the generated CLI and MCP, with matching command conventions and documentation.
  • Reuse authorized application operations across the UI and API, preserve secret redaction and DNS ownership checks, and handle concurrent grants and failed SSO trust writes safely.

Type of Change

  • New feature

Testing

  • Root lint, all workspace type checks, 58 repository audits, docs manifest, and block registry checks.
  • Full root test suite with four workers.
  • 41 integration checks against disposable PostgreSQL and Redis, with a JSON report; regression cases demonstrated failures before their fixes.
  • 73 focused application checks, 127 CLI checks, and real CLI help checks.
  • Regenerated OpenAPI, CLI, MCP, route tables, and CLI documentation. Semantic comparison confirms existing endpoint definitions are unchanged.

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 Oct 7, 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 Oct 8, 2026 12:02am UTC

Request Review

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

We detected this is a high-risk PR and are running a free ultrareview. An ultrareview is a deeper, multi-pass review that catches hard-to-find bugs a standard review can miss. We'll post the findings when it completes.

This PR appears to change authentication, authorization, or input validation, where a missed bug can expose data or grant the wrong access, so a deeper multi-pass review is worth running.

Want an ultrareview on every high-risk PR? Set up automated ultrareviews.

@greptile-apps

greptile-apps Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Critical risk] Exposes new APIs for SSO administration and credential sharing.

Fix the two failing CLI commands and the ignored UserInfo setting before merging.

Findings

  1. P1 Two CLI commands fail ▶
  2. P1 UserInfo changes are ignored ▶

Summary

Adds 14 public API operations for credential sharing, SSO providers and policy, and verified domains. The CLI and MCP expose the same operations.

  • Moves existing SSO routes into shared application operations.
  • Adds paginated lists, safe provider responses, and concurrent credential grants.
  • Two CLI commands fail because they omit a required JSON body.
  • API updates ignore the request to clear an existing UserInfo endpoint.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  UI[Settings UI] --> Operations[Shared authorized operations]
  CLI[CLI] --> API[Public v2 API]
  MCP[MCP] --> API
  API --> Operations
  Operations --> Credentials[Credential grants]
  Operations --> Domains[Domain ownership checks]
  Operations --> Writer{Caller credential}
  Writer -->|Session| BetterAuth[Better Auth writer]
  Writer -->|API key or OAuth| Repository[Provider repository]
  Domains --> Trust[Provider domain trust]
  Repository --> Trust
  BetterAuth --> Trust
Loading

Reviews (1) · Last reviewed commit: "feat(api): expose credential sharing and..." · Reviewed by Greptile

path: '/api/v2/organizations/[organizationId]/sso/providers/[providerId]/primary',
params: v2SsoProviderParamsSchema,
query: noInputSchema,
body: noInputSchema,

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.

P1 Two CLI commands fail

sim organizations sso providers primary and sim organizations domains verify send no request body, but both new contracts require JSON through body: noInputSchema. Their generated CLI entries omit body, so buildRequest returns undefined. The server rejects both commands with 400 before running them.

Remove the body requirement from these parameter-only operations, or make the generated CLI send an empty JSON object.

Knowledge Base Used: Developer interfaces

Comment on lines +238 to +242
const updated: Record<string, unknown> = {
...current,
...filterUndefined(config),
issuer,
}

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.

P1 UserInfo changes are ignored

Updating an existing OIDC provider through a personal API key or OAuth token silently ignores skipUserInfoEndpoint: true when an endpoint is already saved. saveSsoProvider clears the endpoint by setting it to undefined, but this merge drops that value and keeps current.userInfoEndpoint. The save succeeds while the stored settings still contain the endpoint the administrator asked to stop using.

Carry an explicit clear operation into the repository and remove the saved field.

@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.

We detected this is a high-risk PR and ran a free ultrareview. An ultrareview is a deeper, multi-pass review that catches hard-to-find bugs a standard review can miss.

This PR appears to change authentication, authorization, or input validation, where a missed bug can expose data or grant the wrong access, so a deeper multi-pass review is worth running.

Want an ultrareview on every high-risk PR? Set up automated ultrareviews.

22 issues found across 68 files

Confidence score: 2/5

  • The domain verification route requires a JSON body, but the generated CLI sends none, so verification fails with a 400; the OpenAPI contract also marks these no-input actions as requiring a body. Make the empty-body contract optional.
  • sso-presenters.ts turns legacy SAML metadata into an empty object, so saving settings can overwrite existing IdP metadata and break SAML sign-in. Preserve the stored metadata when presenting and saving it.
  • provider-registration.ts can change an existing OIDC provider to client_secret_post when discovery is unavailable, breaking IdPs that require Basic authentication. Preserve the stored authentication method on re-save.
  • commands.ts exposes the write-only OIDC secret only as a plain argv value. Add prompt or file/stdin input before exposing this command.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/app/api/v2/credentials/[credentialId]/members/[userId]/route.ts">

<violation number="1" location="apps/sim/app/api/v2/credentials/[credentialId]/members/[userId]/route.ts:18">
P2: This new public endpoint exposes a non-atomic grant revocation. Two concurrent DELETEs can both pass the initial active check, and the second returns 200 after updating an already-revoked row instead of the documented 404; lock and revalidate the grant, then make the status update conditional before reporting success.</violation>
</file>

<file name="apps/sim/lib/auth/sso/provider-adapter.ts">

<violation number="1" location="apps/sim/lib/auth/sso/provider-adapter.ts:54">
P3: This SCIM collision check is unreachable and cannot inspect Sim's SCIM connections, so API/OAuth registrations silently skip the conflict protection it advertises. Query the actual SCIM schema using its intended identifier, or remove this check if no shared ID contract exists.</violation>
</file>

<file name="apps/sim/app/api/v2/organizations/[organizationId]/domains/[domainId]/verify/route.ts">

<violation number="1" location="apps/sim/app/api/v2/organizations/[organizationId]/domains/[domainId]/verify/route.ts:9">
P1: This route requires a JSON `{}` body even though the generated CLI/MCP operation exposes no body and sends none, so `organizations domains verify` receives `400 Request body must be valid JSON` before verification runs. Make the no-input body optional with a `{}` default (and regenerate the clients), or otherwise allow an empty POST.</violation>
</file>

<file name="apps/sim/lib/api/server/routes/sso.ts">

<violation number="1" location="apps/sim/lib/api/server/routes/sso.ts:19">
P2: This maps Better Auth's 500 `INTERNAL_SERVER_ERROR` to a 503 Service Unavailable response, causing clients to retry an unexpected server fault as though the dependency were transiently unavailable. Preserve 500-class faults as `INTERNAL_ERROR` and reserve `SERVICE_UNAVAILABLE` for an explicitly transient status such as 503.</violation>
</file>

<file name="apps/sim/lib/api/contracts/auth.ts">

<violation number="1" location="apps/sim/lib/api/contracts/auth.ts:19">
P3: `orgId` now reports “Organization ID is required” for numbers or objects even though the field was supplied. Reuse `organizationIdSchema` (or `missingFieldError`) in both branches so malformed values retain an actionable type error.</violation>
</file>

<file name="apps/sim/lib/api/contracts/v2/sso.ts">

<violation number="1" location="apps/sim/lib/api/contracts/v2/sso.ts:21">
P3: This shared parameter description is inaccurate for the domain administration endpoints, so their generated CLI help and OpenAPI docs describe the wrong resource. Use wording that covers both SSO settings and verified-domain management.</violation>
</file>

<file name="apps/sim/lib/organizations/application/domain-settings.ts">

<violation number="1" location="apps/sim/lib/organizations/application/domain-settings.ts:116">
P2: This pagination branch bypasses the existing 25-domain enumeration cap for `organization_delegated` callers. Keep delegated principals on the capped branch (or reject pagination for them) so a delegated settings caller cannot enumerate every domain by following `nextCursorKeys`.</violation>
</file>

<file name="apps/sim/lib/auth/sso/application/provider-settings.ts">

<violation number="1" location="apps/sim/lib/auth/sso/application/provider-settings.ts:167">
P2: The membership check runs before the delete transaction, so a concurrent role downgrade or removal can commit before this request deletes the provider while the stale authorization is still accepted. Recheck current administrator membership under the transaction's organization/member lock before deleting.</violation>
</file>

<file name="apps/sim/lib/api/contracts/v2/openapi/sso.ts">

<violation number="1" location="apps/sim/lib/api/contracts/v2/openapi/sso.ts:112">
P2: These no-input actions are published with a required JSON request body, so generated clients and callers cannot invoke them as bodyless POSTs. Make the empty-body contract optional/defaulted (as other no-body POSTs do) before documenting it here, so OpenAPI does not require an artificial `{}`.</violation>
</file>

<file name="packages/sim-cli/src/contract/commands.ts">

<violation number="1" location="packages/sim-cli/src/contract/commands.ts:347">
P2: These new inventory list commands stop after the first 100 records by default and leave the remaining records behind a cursor. Add all three operations to the complete-list set so they follow the CLI’s all-pages default used by other inventories.</violation>

<violation number="2" location="packages/sim-cli/src/contract/commands.ts:1123">
P1: `saveSsoProvider` exposes the write-only OIDC secret only as a plain argv value. Add prompt or file/stdin-backed secret input before exposing this command, because the generic string path cannot use the repository’s safe secret-input convention and leaks values through shell history and process listings.</violation>
</file>

<file name="apps/sim/lib/api/server/sso-presenters.ts">

<violation number="1" location="apps/sim/lib/api/server/sso-presenters.ts:50">
P1: `publicConfig` converts legacy string-valued SAML metadata into `{}`. The settings editor then sends no metadata, and the next save overwrites the existing IdP metadata with `{ metadata: '' }`, potentially breaking SAML sign-in; preserve string values as metadata objects before projecting them.</violation>
</file>

<file name="apps/sim/lib/auth/sso/application/sso-requirement.ts">

<violation number="1" location="apps/sim/lib/auth/sso/application/sso-requirement.ts:94">
P2: Self-hosted SSO-disabled requests are labeled `ENTERPRISE_PLAN_REQUIRED` even though the message directs callers to set deployment flags. The v2 API exposes this as `error.details.code`, so clients may incorrectly direct users to upgrade a plan; return a codeless or configuration-specific refusal for this branch, and reserve the plan code for billing-enabled entitlement failures.</violation>
</file>

<file name="apps/sim/lib/auth/sso/provider-repository.ts">

<violation number="1" location="apps/sim/lib/auth/sso/provider-repository.ts:151">
P2: The SCIM namespace check is not race-safe. A concurrent SCIM and SSO registration can both pass this pre-check and commit the same provider ID; use a shared provider-ID lock or another cross-namespace coordination mechanism before inserting.</violation>

<violation number="2" location="apps/sim/lib/auth/sso/provider-repository.ts:240">
P2: API SAML saves replace stored nested metadata objects instead of merging them. This drops existing private keys, entity IDs, and encryption flags, and can make a certificate-only update look like an identity change for linked accounts; merge each nested metadata object with its stored value before serializing.</violation>

<violation number="3" location="apps/sim/lib/auth/sso/provider-repository.ts:266">
P2: The linked-account check is a TOCTOU race because locking the provider does not serialize account creation. A concurrent SSO callback can add the first account after this query, allowing an identity-changing update that should have been rejected; coordinate account creation and updates with the same provider-scoped lock.</violation>
</file>

<file name="apps/sim/lib/auth/sso/application/provider-registration.ts">

<violation number="1" location="apps/sim/lib/auth/sso/application/provider-registration.ts:105">
P2: A 2xx discovery response containing `null` or another non-object JSON value causes an unhandled exception during registration. Validate that the decoded document is a non-array object and return a validation failure otherwise.</violation>

<violation number="2" location="apps/sim/lib/auth/sso/application/provider-registration.ts:428">
P1: A re-save can silently change an existing provider’s token authentication method to `client_secret_post` when discovery is unavailable, breaking IdPs that require Basic authentication. Load the stored OIDC method and pass it as the fallback before selecting the default.</violation>

<violation number="3" location="apps/sim/lib/auth/sso/application/provider-registration.ts:467">
P2: Enabling `skipUserInfoEndpoint` on an existing OIDC provider does not remove its saved UserInfo endpoint because the update repository filters this `undefined` value. Clear the persisted endpoint or store an explicit skip flag so the provider stops calling UserInfo.</violation>

<violation number="4" location="apps/sim/lib/auth/sso/application/provider-registration.ts:687">
P2: A failed trust write can roll back another administrator’s later provider update because the rollback matches only the provider ID. Serialize provider saves or make the rollback conditional on the exact version/config written by this request.</violation>

<violation number="5" location="apps/sim/lib/auth/sso/application/provider-registration.ts:694">
P2: Changing an existing provider from SAML to OIDC or vice versa is not handled: the update sends only the new protocol config, so the repository rejects the switch or leaves the old protocol column behind. Reject protocol changes explicitly or replace both protocol columns atomically.</violation>
</file>

<file name="apps/sim/lib/api/contracts/v2/openapi/credential-members.ts">

<violation number="1" location="apps/sim/lib/api/contracts/v2/openapi/credential-members.ts:23">
P3: These credential-member use cases cannot produce a 409, but `RESOURCE_CONFLICT_ERRORS` advertises one in the public OpenAPI contract. Use `RESOURCE_ERRORS` for these routes so generated clients do not expose an unreachable conflict response.</violation>
</file>

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

Turn on auto-fix | Re-trigger cubic

import { organizationSecurityOperations } from '@/lib/organizations/application/operations'

export const POST = defineV2JsonRoute({
contract: v2VerifyOrganizationDomainContract,

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P1: This route requires a JSON {} body even though the generated CLI/MCP operation exposes no body and sends none, so organizations domains verify receives 400 Request body must be valid JSON before verification runs. Make the no-input body optional with a {} default (and regenerate the clients), or otherwise allow an empty POST.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/app/api/v2/organizations/[organizationId]/domains/[domainId]/verify/route.ts, line 9:

<comment>This route requires a JSON `{}` body even though the generated CLI/MCP operation exposes no body and sends none, so `organizations domains verify` receives `400 Request body must be valid JSON` before verification runs. Make the no-input body optional with a `{}` default (and regenerate the clients), or otherwise allow an empty POST.</comment>

<file context>
@@ -0,0 +1,17 @@
+import { organizationSecurityOperations } from '@/lib/organizations/application/operations'
+
+export const POST = defineV2JsonRoute({
+  contract: v2VerifyOrganizationDomainContract,
+  operation: organizationSecurityOperations.verifyDomain,
+  auth: v2ApiKeyAuth,
</file context>
Fix with cubic

command: 'organizations sso providers get',
pathFlags: ORGANIZATION_FLAG,
},
saveSsoProvider: {

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P1: saveSsoProvider exposes the write-only OIDC secret only as a plain argv value. Add prompt or file/stdin-backed secret input before exposing this command, because the generic string path cannot use the repository’s safe secret-input convention and leaks values through shell history and process listings.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At packages/sim-cli/src/contract/commands.ts, line 1123:

<comment>`saveSsoProvider` exposes the write-only OIDC secret only as a plain argv value. Add prompt or file/stdin-backed secret input before exposing this command, because the generic string path cannot use the repository’s safe secret-input convention and leaks values through shell history and process listings.</comment>

<file context>
@@ -1088,6 +1106,59 @@ export const CLI_CONTRACT: CliContract = {
+    command: 'organizations sso providers get',
+    pathFlags: ORGANIZATION_FLAG,
+  },
+  saveSsoProvider: {
+    command: 'organizations sso providers save',
+    pathFlags: ORGANIZATION_FLAG,
</file context>
Fix with cubic

for (const key of fields) {
if (record[key] === undefined) continue
if (key === 'spMetadata' || key === 'idpMetadata') {
const metadata = toRecord(record[key])

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P1: publicConfig converts legacy string-valued SAML metadata into {}. The settings editor then sends no metadata, and the next save overwrites the existing IdP metadata with { metadata: '' }, potentially breaking SAML sign-in; preserve string values as metadata objects before projecting them.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/api/server/sso-presenters.ts, line 50:

<comment>`publicConfig` converts legacy string-valued SAML metadata into `{}`. The settings editor then sends no metadata, and the next save overwrites the existing IdP metadata with `{ metadata: '' }`, potentially breaking SAML sign-in; preserve string values as metadata objects before projecting them.</comment>

<file context>
@@ -0,0 +1,99 @@
+    for (const key of fields) {
+      if (record[key] === undefined) continue
+      if (key === 'spMetadata' || key === 'idpMetadata') {
+        const metadata = toRecord(record[key])
+        projected[key] = {
+          metadata: metadata.metadata,
</file context>
Fix with cubic

oidcConfig.userInfoEndpoint || toStringOrNull(discovery.userinfo_endpoint) || undefined
oidcConfig.jwksEndpoint =
oidcConfig.jwksEndpoint || toStringOrNull(discovery.jwks_uri) || undefined
oidcConfig.tokenEndpointAuthentication = selectTokenEndpointAuthMethod(

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P1: A re-save can silently change an existing provider’s token authentication method to client_secret_post when discovery is unavailable, breaking IdPs that require Basic authentication. Load the stored OIDC method and pass it as the fallback before selecting the default.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/auth/sso/application/provider-registration.ts, line 428:

<comment>A re-save can silently change an existing provider’s token authentication method to `client_secret_post` when discovery is unavailable, breaking IdPs that require Basic authentication. Load the stored OIDC method and pass it as the fallback before selecting the default.</comment>

<file context>
@@ -0,0 +1,807 @@
+          oidcConfig.userInfoEndpoint || toStringOrNull(discovery.userinfo_endpoint) || undefined
+        oidcConfig.jwksEndpoint =
+          oidcConfig.jwksEndpoint || toStringOrNull(discovery.jwks_uri) || undefined
+        oidcConfig.tokenEndpointAuthentication = selectTokenEndpointAuthMethod(
+          discovery.token_endpoint_auth_methods_supported,
+          oidcConfig.tokenEndpointAuthentication
</file context>
Fix with cubic

rateLimit: v2RateLimits.publicApi,
errorPolicy: createV2ResourceConcealmentPolicy({ notFoundMessage: 'Credential not found' }),
mapInput: ({ params, query }) => ({ ...params, assertedWorkspaceId: query.workspaceId }),
useCase: removeCredentialMemberUseCase,

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P2: This new public endpoint exposes a non-atomic grant revocation. Two concurrent DELETEs can both pass the initial active check, and the second returns 200 after updating an already-revoked row instead of the documented 404; lock and revalidate the grant, then make the status update conditional before reporting success.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/app/api/v2/credentials/[credentialId]/members/[userId]/route.ts, line 18:

<comment>This new public endpoint exposes a non-atomic grant revocation. Two concurrent DELETEs can both pass the initial active check, and the second returns 200 after updating an already-revoked row instead of the documented 404; lock and revalidate the grant, then make the status update conditional before reporting success.</comment>

<file context>
@@ -0,0 +1,20 @@
+  rateLimit: v2RateLimits.publicApi,
+  errorPolicy: createV2ResourceConcealmentPolicy({ notFoundMessage: 'Credential not found' }),
+  mapInput: ({ params, query }) => ({ ...params, assertedWorkspaceId: query.workspaceId }),
+  useCase: removeCredentialMemberUseCase,
+  present: ({ targetUserId }) => ({ data: { userId: targetUserId, revoked: true as const } }),
+})
</file context>
Fix with cubic

}

if (skipUserInfoEndpoint) {
oidcConfig.userInfoEndpoint = undefined

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P2: Enabling skipUserInfoEndpoint on an existing OIDC provider does not remove its saved UserInfo endpoint because the update repository filters this undefined value. Clear the persisted endpoint or store an explicit skip flag so the provider stops calling UserInfo.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/auth/sso/application/provider-registration.ts, line 467:

<comment>Enabling `skipUserInfoEndpoint` on an existing OIDC provider does not remove its saved UserInfo endpoint because the update repository filters this `undefined` value. Clear the persisted endpoint or store an explicit skip flag so the provider stops calling UserInfo.</comment>

<file context>
@@ -0,0 +1,807 @@
+      }
+
+      if (skipUserInfoEndpoint) {
+        oidcConfig.userInfoEndpoint = undefined
+        logger.info('Skipping UserInfo endpoint for provider, claims will come from the ID token', {
+          providerId,
</file context>
Fix with cubic

...context.trustedProviders,
],
hasScimProvider: async (providerId) =>
context.hasPlugin('scim') &&

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P3: This SCIM collision check is unreachable and cannot inspect Sim's SCIM connections, so API/OAuth registrations silently skip the conflict protection it advertises. Query the actual SCIM schema using its intended identifier, or remove this check if no shared ID contract exists.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/auth/sso/provider-adapter.ts, line 54:

<comment>This SCIM collision check is unreachable and cannot inspect Sim's SCIM connections, so API/OAuth registrations silently skip the conflict protection it advertises. Query the actual SCIM schema using its intended identifier, or remove this check if no shared ID contract exists.</comment>

<file context>
@@ -0,0 +1,62 @@
+      ...context.trustedProviders,
+    ],
+    hasScimProvider: async (providerId) =>
+      context.hasPlugin('scim') &&
+      Boolean(
+        await context.adapter.findOne({
</file context>
Fix with cubic

skipUserInfoEndpoint: z.boolean().default(false),
jwksEndpoint: z.string().url().optional(),
ssoRegistrationInputSchema.options[0].omit({ organizationId: true }).extend({
orgId: z.string({ error: 'Organization ID is required' }).min(1, 'Organization ID is required'),

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P3: orgId now reports “Organization ID is required” for numbers or objects even though the field was supplied. Reuse organizationIdSchema (or missingFieldError) in both branches so malformed values retain an actionable type error.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/api/contracts/auth.ts, line 19:

<comment>`orgId` now reports “Organization ID is required” for numbers or objects even though the field was supplied. Reuse `organizationIdSchema` (or `missingFieldError`) in both branches so malformed values retain an actionable type error.</comment>

<file context>
@@ -14,69 +14,14 @@ export const authProviderStatusResponseSchema = z.object({
-    skipUserInfoEndpoint: z.boolean().default(false),
-    jwksEndpoint: z.string().url().optional(),
+  ssoRegistrationInputSchema.options[0].omit({ organizationId: true }).extend({
+    orgId: z.string({ error: 'Organization ID is required' }).min(1, 'Organization ID is required'),
   }),
-  z.object({
</file context>
Fix with cubic

const v2SsoOrganizationParamsSchema = z
.object({
organizationId: organizationIdSchema.describe(
'Organization whose single sign-on settings are managed.'

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P3: This shared parameter description is inaccurate for the domain administration endpoints, so their generated CLI help and OpenAPI docs describe the wrong resource. Use wording that covers both SSO settings and verified-domain management.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/api/contracts/v2/sso.ts, line 21:

<comment>This shared parameter description is inaccurate for the domain administration endpoints, so their generated CLI help and OpenAPI docs describe the wrong resource. Use wording that covers both SSO settings and verified-domain management.</comment>

<file context>
@@ -0,0 +1,375 @@
+const v2SsoOrganizationParamsSchema = z
+  .object({
+    organizationId: organizationIdSchema.describe(
+      'Organization whose single sign-on settings are managed.'
+    ),
+  })
</file context>
Fix with cubic

summary: 'List Credential Members',
description: `List explicit credential grants, including revoked grants, and inherited workspace administrator access. Requires workspace read access. Credentials must be OAuth or service-account connections. ${WORKSPACE_API_KEY_DENIED}`,
tags: ['Credentials'],
errors: RESOURCE_CONFLICT_ERRORS,

@cubic-dev-ai cubic-dev-ai Bot Oct 8, 2026 •

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.

P3: These credential-member use cases cannot produce a 409, but RESOURCE_CONFLICT_ERRORS advertises one in the public OpenAPI contract. Use RESOURCE_ERRORS for these routes so generated clients do not expose an unreachable conflict response.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/api/contracts/v2/openapi/credential-members.ts, line 23:

<comment>These credential-member use cases cannot produce a 409, but `RESOURCE_CONFLICT_ERRORS` advertises one in the public OpenAPI contract. Use `RESOURCE_ERRORS` for these routes so generated clients do not expose an unreachable conflict response.</comment>

<file context>
@@ -0,0 +1,117 @@
+      summary: 'List Credential Members',
+      description: `List explicit credential grants, including revoked grants, and inherited workspace administrator access. Requires workspace read access. Credentials must be OAuth or service-account connections. ${WORKSPACE_API_KEY_DENIED}`,
+      tags: ['Credentials'],
+      errors: RESOURCE_CONFLICT_ERRORS,
+      success: { description: 'List Credential Members result.', headers: RATE_LIMIT_HEADERS },
+    },
</file context>
Fix with cubic

This branch was successfully deployed

1 active deployment
Preview — a76af458 Deployed Oct 8, 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