From 6bc03f7a0e83e302574c29a60517da92d2ef739d Mon Sep 17 00:00:00 2001 From: msukkari Date: Thu, 30 Oct 2025 21:22:25 -0700 Subject: [PATCH 01/16] add identity provider schema --- docs/snippets/schemas/v3/app.schema.mdx | 4 +- .../schemas/v3/authProvider.schema.mdx | 1307 ++++++++++++++++ docs/snippets/schemas/v3/index.schema.mdx | 1312 ++++++++++++++++- packages/schemas/src/v3/app.schema.ts | 4 +- packages/schemas/src/v3/app.type.ts | 2 +- .../schemas/src/v3/authProvider.schema.ts | 1306 ++++++++++++++++ packages/schemas/src/v3/authProvider.type.ts | 275 ++++ packages/schemas/src/v3/index.schema.ts | 1312 ++++++++++++++++- packages/schemas/src/v3/index.type.ts | 278 +++- schemas/v3/app.json | 2 +- schemas/v3/authProvider.json | 152 ++ schemas/v3/index.json | 7 + 12 files changed, 5950 insertions(+), 11 deletions(-) create mode 100644 docs/snippets/schemas/v3/authProvider.schema.mdx create mode 100644 packages/schemas/src/v3/authProvider.schema.ts create mode 100644 packages/schemas/src/v3/authProvider.type.ts create mode 100644 schemas/v3/authProvider.json diff --git a/docs/snippets/schemas/v3/app.schema.mdx b/docs/snippets/schemas/v3/app.schema.mdx index 6d5e5a212..ab2502181 100644 --- a/docs/snippets/schemas/v3/app.schema.mdx +++ b/docs/snippets/schemas/v3/app.schema.mdx @@ -8,7 +8,7 @@ "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -70,7 +70,7 @@ "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { diff --git a/docs/snippets/schemas/v3/authProvider.schema.mdx b/docs/snippets/schemas/v3/authProvider.schema.mdx new file mode 100644 index 000000000..0ebf9eb19 --- /dev/null +++ b/docs/snippets/schemas/v3/authProvider.schema.mdx @@ -0,0 +1,1307 @@ +{/* THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! */} +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] +} +``` diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 89ed6be21..6570edb5b 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -4305,7 +4305,7 @@ "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -4367,7 +4367,7 @@ "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -4425,6 +4425,1314 @@ } ] } + }, + "identityProviders": { + "type": "array", + "description": "Defines a collection of identity providers that are available to Sourcebot.", + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] + } } }, "additionalProperties": false diff --git a/packages/schemas/src/v3/app.schema.ts b/packages/schemas/src/v3/app.schema.ts index 87a7eb27f..c03a2015f 100644 --- a/packages/schemas/src/v3/app.schema.ts +++ b/packages/schemas/src/v3/app.schema.ts @@ -7,7 +7,7 @@ const schema = { "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -69,7 +69,7 @@ const schema = { "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { diff --git a/packages/schemas/src/v3/app.type.ts b/packages/schemas/src/v3/app.type.ts index c087a7594..f743fa9ad 100644 --- a/packages/schemas/src/v3/app.type.ts +++ b/packages/schemas/src/v3/app.type.ts @@ -6,7 +6,7 @@ export interface GitHubAppConfig { /** * GitHub App Configuration */ - type: "githubApp"; + type: "github"; /** * The hostname of the GitHub App deployment. */ diff --git a/packages/schemas/src/v3/authProvider.schema.ts b/packages/schemas/src/v3/authProvider.schema.ts new file mode 100644 index 000000000..32a0bc46d --- /dev/null +++ b/packages/schemas/src/v3/authProvider.schema.ts @@ -0,0 +1,1306 @@ +// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! +const schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] +} as const; +export { schema as authProviderSchema }; \ No newline at end of file diff --git a/packages/schemas/src/v3/authProvider.type.ts b/packages/schemas/src/v3/authProvider.type.ts new file mode 100644 index 000000000..5cea9cf45 --- /dev/null +++ b/packages/schemas/src/v3/authProvider.type.ts @@ -0,0 +1,275 @@ +// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! + +export type IdentityProviderConfig = + | GitHubIdentityProviderConfig + | GitLabIdentityProviderConfig + | GoogleIdentityProviderConfig + | OktaIdentityProviderConfig + | KeycloakIdentityProviderConfig + | MicrosoftEntraIDIdentityProviderConfig + | GCPIAPIdentityProviderConfig; + +export interface GitHubIdentityProviderConfig { + provider: "github"; + purpose: "sso" | "identity"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl?: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GitLabIdentityProviderConfig { + provider: "gitlab"; + purpose: "sso" | "identity"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GoogleIdentityProviderConfig { + provider: "google"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface OktaIdentityProviderConfig { + provider: "okta"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface KeycloakIdentityProviderConfig { + provider: "keycloak"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface MicrosoftEntraIDIdentityProviderConfig { + provider: "microsoft-entra-id"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GCPIAPIdentityProviderConfig { + provider: "gcp-iap"; + audience: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index e49d998b4..c4f4358d8 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -4304,7 +4304,7 @@ const schema = { "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -4366,7 +4366,7 @@ const schema = { "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { @@ -4424,6 +4424,1314 @@ const schema = { } ] } + }, + "identityProviders": { + "type": "array", + "description": "Defines a collection of identity providers that are available to Sourcebot.", + "items": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "identity" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "secret": { + "type": "string", + "description": "The name of the secret that contains the token." + } + }, + "required": [ + "secret" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] + } } }, "additionalProperties": false diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index eb2b412c9..60ad4861d 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -26,6 +26,14 @@ export type LanguageModel = | OpenRouterLanguageModel | XaiLanguageModel; export type AppConfig = GitHubAppConfig; +export type IdentityProviderConfig = + | GitHubIdentityProviderConfig + | GitLabIdentityProviderConfig + | GoogleIdentityProviderConfig + | OktaIdentityProviderConfig + | KeycloakIdentityProviderConfig + | MicrosoftEntraIDIdentityProviderConfig + | GCPIAPIdentityProviderConfig; export interface SourcebotConfig { $schema?: string; @@ -50,6 +58,10 @@ export interface SourcebotConfig { * Defines a collection of apps that are available to Sourcebot. */ apps?: AppConfig[]; + /** + * Defines a collection of identity providers that are available to Sourcebot. + */ + identityProviders?: IdentityProviderConfig[]; } /** * Defines the global settings for Sourcebot. @@ -1078,7 +1090,7 @@ export interface GitHubAppConfig { /** * GitHub App Configuration */ - type: "githubApp"; + type: "github"; /** * The hostname of the GitHub App deployment. */ @@ -1104,3 +1116,267 @@ export interface GitHubAppConfig { env: string; }; } +export interface GitHubIdentityProviderConfig { + provider: "github"; + purpose: "sso" | "identity"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl?: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GitLabIdentityProviderConfig { + provider: "gitlab"; + purpose: "sso" | "identity"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GoogleIdentityProviderConfig { + provider: "google"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface OktaIdentityProviderConfig { + provider: "okta"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface KeycloakIdentityProviderConfig { + provider: "keycloak"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface MicrosoftEntraIDIdentityProviderConfig { + provider: "microsoft-entra-id"; + clientId: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GCPIAPIdentityProviderConfig { + provider: "gcp-iap"; + audience: + | { + /** + * The name of the secret that contains the token. + */ + secret: string; + } + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} diff --git a/schemas/v3/app.json b/schemas/v3/app.json index 2fadfef4a..c6923cd2a 100644 --- a/schemas/v3/app.json +++ b/schemas/v3/app.json @@ -6,7 +6,7 @@ "type": "object", "properties": { "type": { - "const": "githubApp", + "const": "github", "description": "GitHub App Configuration" }, "deploymentHostname": { diff --git a/schemas/v3/authProvider.json b/schemas/v3/authProvider.json new file mode 100644 index 000000000..bb6c390fc --- /dev/null +++ b/schemas/v3/authProvider.json @@ -0,0 +1,152 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": ["sso", "identity"] + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "baseUrl": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "purpose", "clientId", "clientSecret"] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": ["sso", "identity"] + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "baseUrl": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "purpose", "clientId", "clientSecret", "baseUrl"] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "clientId", "clientSecret"] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "issuer": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "clientId", "clientSecret", "issuer"] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "issuer": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "clientId", "clientSecret", "issuer"] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "$ref": "./shared.json#/definitions/Token" + }, + "clientSecret": { + "$ref": "./shared.json#/definitions/Token" + }, + "issuer": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "clientId", "clientSecret", "issuer"] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "$ref": "./shared.json#/definitions/Token" + } + }, + "required": ["provider", "audience"] + } + }, + "oneOf": [ + { + "$ref": "#/definitions/GitHubIdentityProviderConfig" + }, + { + "$ref": "#/definitions/GitLabIdentityProviderConfig" + }, + { + "$ref": "#/definitions/GoogleIdentityProviderConfig" + }, + { + "$ref": "#/definitions/OktaIdentityProviderConfig" + }, + { + "$ref": "#/definitions/KeycloakIdentityProviderConfig" + }, + { + "$ref": "#/definitions/MicrosoftEntraIDIdentityProviderConfig" + }, + { + "$ref": "#/definitions/GCPIAPIdentityProviderConfig" + } + ] +} diff --git a/schemas/v3/index.json b/schemas/v3/index.json index 3bb129b1c..72c7e58d6 100644 --- a/schemas/v3/index.json +++ b/schemas/v3/index.json @@ -125,6 +125,13 @@ "items": { "$ref": "./app.json" } + }, + "identityProviders": { + "type": "array", + "description": "Defines a collection of identity providers that are available to Sourcebot.", + "items": { + "$ref": "./authProvider.json" + } } }, "additionalProperties": false From d4cf329af2e9e147f68d246c466d689b018a0831 Mon Sep 17 00:00:00 2001 From: msukkari Date: Fri, 31 Oct 2025 11:55:39 -0700 Subject: [PATCH 02/16] wip using identityprovider from config --- packages/web/src/auth.ts | 7 +- packages/web/src/ee/features/sso/sso.ts | 329 ++++++++++-------- ...uthProvider.json => identityProvider.json} | 4 +- schemas/v3/index.json | 2 +- 4 files changed, 194 insertions(+), 148 deletions(-) rename schemas/v3/{authProvider.json => identityProvider.json} (97%) diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index 27800d0c1..544976d00 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -20,6 +20,7 @@ import { getAuditService } from '@/ee/features/audit/factory'; import { SINGLE_TENANT_ORG_ID } from './lib/constants'; const auditService = getAuditService(); +const ssoProviders = hasEntitlement("sso") ? await getSSOProviders() : []; export const runtime = 'nodejs'; @@ -38,11 +39,7 @@ declare module 'next-auth/jwt' { } export const getProviders = () => { - const providers: Provider[] = []; - - if (hasEntitlement("sso")) { - providers.push(...getSSOProviders()); - } + const providers: Provider[] = ssoProviders; if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') { providers.push(EmailProvider({ diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 7accc0658..0d12a5edc 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -12,172 +12,221 @@ import Credentials from "next-auth/providers/credentials"; import type { User as AuthJsUser } from "next-auth"; import { onCreateUser } from "@/lib/authUtils"; import { createLogger } from "@sourcebot/logger"; -import { hasEntitlement } from "@sourcebot/shared"; +import { hasEntitlement, loadConfig } from "@sourcebot/shared"; +import { getTokenFromConfig } from "@sourcebot/crypto"; +import { SINGLE_TENANT_ORG_ID } from "@/lib/constants"; const logger = createLogger('web-sso'); -export const getSSOProviders = (): Provider[] => { +export const getSSOProviders = async (): Promise => { const providers: Provider[] = []; + const config = env.CONFIG_PATH ? await loadConfig(env.CONFIG_PATH) : undefined; + const identityProviders = config?.identityProviders ?? []; + + for (const identityProvider of identityProviders) { + if (identityProvider.provider === "github") { + const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db); + const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db); + const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined; + providers.push(createGitHubProvider(clientId, clientSecret, baseUrl)); + } + if (identityProvider.provider === "gitlab") { + const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db); + const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db); + const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined; + providers.push(createGitLabProvider(clientId, clientSecret, baseUrl)); + } + } + if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { - providers.push(GitHub({ - clientId: env.AUTH_EE_GITHUB_CLIENT_ID, - clientSecret: env.AUTH_EE_GITHUB_CLIENT_SECRET, - enterprise: { - baseUrl: env.AUTH_EE_GITHUB_BASE_URL, - }, - authorization: { - params: { - scope: [ - 'read:user', - 'user:email', - // Permission syncing requires the `repo` scope in order to fetch repositories - // for the authenticated user. - // @see: https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-the-authenticated-user - ...(env.EXPERIMENT_EE_PERMISSION_SYNC_ENABLED === 'true' && hasEntitlement('permission-syncing') ? - ['repo'] : - [] - ), - ].join(' '), - }, - }, - })); + providers.push(createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL)); } if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) { - providers.push(Gitlab({ - clientId: env.AUTH_EE_GITLAB_CLIENT_ID, - clientSecret: env.AUTH_EE_GITLAB_CLIENT_SECRET, - authorization: { - url: `${env.AUTH_EE_GITLAB_BASE_URL}/oauth/authorize`, - params: { - scope: [ - "read_user", - // Permission syncing requires the `read_api` scope in order to fetch projects - // for the authenticated user and project members. - // @see: https://docs.gitlab.com/ee/api/projects.html#list-all-projects - ...(env.EXPERIMENT_EE_PERMISSION_SYNC_ENABLED === 'true' && hasEntitlement('permission-syncing') ? - ['read_api'] : - [] - ), - ].join(' '), - }, - }, - token: { - url: `${env.AUTH_EE_GITLAB_BASE_URL}/oauth/token`, - }, - userinfo: { - url: `${env.AUTH_EE_GITLAB_BASE_URL}/api/v4/user`, - }, - })); + providers.push(createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL)); } if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) { - providers.push(Google({ - clientId: env.AUTH_EE_GOOGLE_CLIENT_ID, - clientSecret: env.AUTH_EE_GOOGLE_CLIENT_SECRET, - })); + providers.push(createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET)); } if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) { - providers.push(Okta({ - clientId: env.AUTH_EE_OKTA_CLIENT_ID, - clientSecret: env.AUTH_EE_OKTA_CLIENT_SECRET, - issuer: env.AUTH_EE_OKTA_ISSUER, - })); + providers.push(createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER)); } if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) { - providers.push(Keycloak({ - clientId: env.AUTH_EE_KEYCLOAK_CLIENT_ID, - clientSecret: env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, - issuer: env.AUTH_EE_KEYCLOAK_ISSUER, - })); + providers.push(createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER)); } if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) { - providers.push(MicrosoftEntraID({ - clientId: env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, - clientSecret: env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, - issuer: env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER, - })); + providers.push(createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER)); } if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { - providers.push(Credentials({ - id: "gcp-iap", - name: "Google Cloud IAP", - credentials: {}, - authorize: async (credentials, req) => { - try { - const iapAssertion = req.headers?.get("x-goog-iap-jwt-assertion"); - if (!iapAssertion || typeof iapAssertion !== "string") { - logger.warn("No IAP assertion found in headers"); - return null; - } - - const oauth2Client = new OAuth2Client(); - - const { pubkeys } = await oauth2Client.getIapPublicKeys(); - const ticket = await oauth2Client.verifySignedJwtWithCertsAsync( - iapAssertion, - pubkeys, - env.AUTH_EE_GCP_IAP_AUDIENCE, - ['https://cloud.google.com/iap'] - ); - - const payload = ticket.getPayload(); - if (!payload) { - logger.warn("Invalid IAP token payload"); - return null; - } - - const email = payload.email; - const name = payload.name || payload.email; - const image = payload.picture; - - if (!email) { - logger.warn("Missing email in IAP token"); - return null; - } - - const existingUser = await prisma.user.findUnique({ - where: { email } - }); + providers.push(createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE)); + } - if (!existingUser) { - const newUser = await prisma.user.create({ - data: { - email, - name, - image, - } - }); - - const authJsUser: AuthJsUser = { - id: newUser.id, - email: newUser.email, - name: newUser.name, - image: newUser.image, - }; - - await onCreateUser({ user: authJsUser }); - return authJsUser; - } else { - return { - id: existingUser.id, - email: existingUser.email, - name: existingUser.name, - image: existingUser.image, - }; - } - } catch (error) { - logger.error("Error verifying IAP token:", error); + return providers; +} + +const createGitHubProvider = (clientId: string, clientSecret: string, baseUrl?: string): Provider => { + return GitHub({ + clientId: clientId, + clientSecret: clientSecret, + enterprise: { + baseUrl: baseUrl, + }, + authorization: { + params: { + scope: [ + 'read:user', + 'user:email', + // Permission syncing requires the `repo` scope in order to fetch repositories + // for the authenticated user. + // @see: https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-the-authenticated-user + ...(env.EXPERIMENT_EE_PERMISSION_SYNC_ENABLED === 'true' && hasEntitlement('permission-syncing') ? + ['repo'] : + [] + ), + ].join(' '), + }, + }, + }); +} + +const createGitLabProvider = (clientId: string, clientSecret: string, baseUrl?: string): Provider => { + const url = baseUrl ?? 'https://gitlab.com'; + return Gitlab({ + clientId: clientId, + clientSecret: clientSecret, + authorization: { + url: `${url}/oauth/authorize`, + params: { + scope: [ + "read_user", + // Permission syncing requires the `read_api` scope in order to fetch projects + // for the authenticated user and project members. + // @see: https://docs.gitlab.com/ee/api/projects.html#list-all-projects + ...(env.EXPERIMENT_EE_PERMISSION_SYNC_ENABLED === 'true' && hasEntitlement('permission-syncing') ? + ['read_api'] : + [] + ), + ].join(' '), + }, + }, + token: { + url: `${url}/oauth/token`, + }, + userinfo: { + url: `${url}/api/v4/user`, + }, + }); +} + +const createGoogleProvider = (clientId: string, clientSecret: string): Provider => { + return Google({ + clientId: clientId, + clientSecret: clientSecret, + }); +} + +const createOktaProvider = (clientId: string, clientSecret: string, issuer: string): Provider => { + return Okta({ + clientId: clientId, + clientSecret: clientSecret, + issuer: issuer, + }); +} + +const createKeycloakProvider = (clientId: string, clientSecret: string, issuer: string): Provider => { + return Keycloak({ + clientId: clientId, + clientSecret: clientSecret, + issuer: issuer, + }); +} + +const createMicrosoftEntraIDProvider = (clientId: string, clientSecret: string, issuer: string): Provider => { + return MicrosoftEntraID({ + clientId: clientId, + clientSecret: clientSecret, + issuer: issuer, + }); +} + +const createGCPIAPProvider = (audience: string): Provider => { + return Credentials({ + id: "gcp-iap", + name: "Google Cloud IAP", + credentials: {}, + authorize: async (credentials, req) => { + try { + const iapAssertion = req.headers?.get("x-goog-iap-jwt-assertion"); + if (!iapAssertion || typeof iapAssertion !== "string") { + logger.warn("No IAP assertion found in headers"); return null; } - }, - })); - } - return providers; + const oauth2Client = new OAuth2Client(); + + const { pubkeys } = await oauth2Client.getIapPublicKeys(); + const ticket = await oauth2Client.verifySignedJwtWithCertsAsync( + iapAssertion, + pubkeys, + audience, + ['https://cloud.google.com/iap'] + ); + + const payload = ticket.getPayload(); + if (!payload) { + logger.warn("Invalid IAP token payload"); + return null; + } + + const email = payload.email; + const name = payload.name || payload.email; + const image = payload.picture; + + if (!email) { + logger.warn("Missing email in IAP token"); + return null; + } + + const existingUser = await prisma.user.findUnique({ + where: { email } + }); + + if (!existingUser) { + const newUser = await prisma.user.create({ + data: { + email, + name, + image, + } + }); + + const authJsUser: AuthJsUser = { + id: newUser.id, + email: newUser.email, + name: newUser.name, + image: newUser.image, + }; + + await onCreateUser({ user: authJsUser }); + return authJsUser; + } else { + return { + id: existingUser.id, + email: existingUser.email, + name: existingUser.name, + image: existingUser.image, + }; + } + } catch (error) { + logger.error("Error verifying IAP token:", error); + return null; + } + }, + }); } \ No newline at end of file diff --git a/schemas/v3/authProvider.json b/schemas/v3/identityProvider.json similarity index 97% rename from schemas/v3/authProvider.json rename to schemas/v3/identityProvider.json index bb6c390fc..76e6c6ae6 100644 --- a/schemas/v3/authProvider.json +++ b/schemas/v3/identityProvider.json @@ -9,7 +9,7 @@ "const": "github" }, "purpose": { - "enum": ["sso", "identity"] + "enum": ["sso", "integration"] }, "clientId": { "$ref": "./shared.json#/definitions/Token" @@ -30,7 +30,7 @@ "const": "gitlab" }, "purpose": { - "enum": ["sso", "identity"] + "enum": ["sso", "integration"] }, "clientId": { "$ref": "./shared.json#/definitions/Token" diff --git a/schemas/v3/index.json b/schemas/v3/index.json index 72c7e58d6..392a2eb98 100644 --- a/schemas/v3/index.json +++ b/schemas/v3/index.json @@ -130,7 +130,7 @@ "type": "array", "description": "Defines a collection of identity providers that are available to Sourcebot.", "items": { - "$ref": "./authProvider.json" + "$ref": "./identityProvider.json" } } }, From c6dbe075e31dd7a4cd1248619f7f901ddce34e60 Mon Sep 17 00:00:00 2001 From: msukkari Date: Fri, 31 Oct 2025 13:46:05 -0700 Subject: [PATCH 03/16] remove built-in secret manager --- docs/docs/connections/ado-cloud.mdx | 24 +- docs/docs/connections/ado-server.mdx | 24 +- docs/docs/connections/gitea.mdx | 23 +- docs/docs/connections/github.mdx | 23 +- docs/docs/connections/gitlab.mdx | 23 +- docs/snippets/bitbucket-app-password.mdx | 23 - docs/snippets/bitbucket-token.mdx | 21 - docs/snippets/schemas/v2/index.schema.mdx | 9 - docs/snippets/schemas/v3/app.schema.mdx | 26 - .../schemas/v3/azuredevops.schema.mdx | 18 - docs/snippets/schemas/v3/bitbucket.schema.mdx | 18 - .../snippets/schemas/v3/connection.schema.mdx | 90 -- docs/snippets/schemas/v3/gitea.schema.mdx | 18 - docs/snippets/schemas/v3/github.schema.mdx | 18 - docs/snippets/schemas/v3/githubApp.schema.mdx | 76 -- docs/snippets/schemas/v3/gitlab.schema.mdx | 18 - docs/snippets/schemas/v3/index.schema.mdx | 824 +----------------- .../schemas/v3/languageModel.schema.mdx | 702 --------------- docs/snippets/schemas/v3/shared.schema.mdx | 39 - packages/backend/src/azuredevops.ts | 5 +- packages/backend/src/bitbucket.ts | 5 +- packages/backend/src/connectionManager.ts | 14 +- packages/backend/src/ee/githubAppManager.ts | 6 +- .../backend/src/ee/repoPermissionSyncer.ts | 2 +- packages/backend/src/gitea.ts | 7 +- packages/backend/src/github.ts | 5 +- packages/backend/src/gitlab.ts | 5 +- packages/backend/src/repoCompileUtils.ts | 67 +- packages/backend/src/repoIndexManager.ts | 2 +- packages/backend/src/utils.ts | 14 +- packages/crypto/src/tokenUtils.ts | 23 +- .../migration.sql | 11 + packages/db/prisma/schema.prisma | 14 - packages/schemas/src/v2/index.schema.ts | 9 - packages/schemas/src/v3/app.schema.ts | 26 - packages/schemas/src/v3/app.type.ts | 19 +- packages/schemas/src/v3/azuredevops.schema.ts | 18 - packages/schemas/src/v3/azuredevops.type.ts | 19 +- packages/schemas/src/v3/bitbucket.schema.ts | 18 - packages/schemas/src/v3/bitbucket.type.ts | 19 +- packages/schemas/src/v3/connection.schema.ts | 90 -- packages/schemas/src/v3/connection.type.ts | 95 +- packages/schemas/src/v3/gitea.schema.ts | 18 - packages/schemas/src/v3/gitea.type.ts | 19 +- packages/schemas/src/v3/github.schema.ts | 18 - packages/schemas/src/v3/github.type.ts | 19 +- packages/schemas/src/v3/gitlab.schema.ts | 18 - packages/schemas/src/v3/gitlab.type.ts | 19 +- packages/schemas/src/v3/index.schema.ts | 824 +----------------- packages/schemas/src/v3/index.type.ts | 420 +++------ .../schemas/src/v3/languageModel.schema.ts | 702 --------------- packages/schemas/src/v3/languageModel.type.ts | 306 ++----- packages/schemas/src/v3/shared.schema.ts | 39 - packages/schemas/src/v3/shared.type.ts | 19 +- packages/web/src/actions.ts | 89 +- .../components/importSecretDialog.tsx | 314 ------- .../web/src/app/[domain]/settings/layout.tsx | 4 - .../secrets/components/importSecretCard.tsx | 66 -- .../secrets/components/secretsList.tsx | 158 ---- .../app/[domain]/settings/secrets/page.tsx | 36 - .../web/src/app/api/(server)/chat/route.ts | 2 +- packages/web/src/features/chat/actions.ts | 66 +- packages/web/src/lib/strings.ts | 7 - schemas/v2/index.json | 3 - schemas/v3/azuredevops.json | 7 +- schemas/v3/bitbucket.json | 7 +- schemas/v3/gitea.json | 7 +- schemas/v3/github.json | 7 +- schemas/v3/gitlab.json | 7 +- schemas/v3/shared.json | 13 - 70 files changed, 419 insertions(+), 5305 deletions(-) delete mode 100644 docs/snippets/schemas/v3/githubApp.schema.mdx create mode 100644 packages/db/prisma/migrations/20251031191203_remove_secret_table/migration.sql delete mode 100644 packages/web/src/app/[domain]/components/importSecretDialog.tsx delete mode 100644 packages/web/src/app/[domain]/settings/secrets/components/importSecretCard.tsx delete mode 100644 packages/web/src/app/[domain]/settings/secrets/components/secretsList.tsx delete mode 100644 packages/web/src/app/[domain]/settings/secrets/page.tsx delete mode 100644 packages/web/src/lib/strings.ts diff --git a/docs/docs/connections/ado-cloud.mdx b/docs/docs/connections/ado-cloud.mdx index cc20c7450..7071afb1d 100644 --- a/docs/docs/connections/ado-cloud.mdx +++ b/docs/docs/connections/ado-cloud.mdx @@ -86,7 +86,7 @@ If you're not familiar with Sourcebot [connections](/docs/connections/overview), Azure Devops Cloud requires you to provide a PAT in order to index your repositories. To learn how to create PAT, check out the [Azure Devops docs](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows). Sourcebot needs the `Read` access for the `Code` scope in order to find and clone your repos. -Next, provide the access token via the `token` property, either as an environment variable or a secret: +Next, provide the access token via an environment variable which is referenced in the `token` property: @@ -113,28 +113,6 @@ Next, provide the access token via the `token` property, either as an environmen ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "azuredevops", - "deploymentType": "cloud", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - ## Schema reference diff --git a/docs/docs/connections/ado-server.mdx b/docs/docs/connections/ado-server.mdx index 1cfc02525..a62d94c2a 100644 --- a/docs/docs/connections/ado-server.mdx +++ b/docs/docs/connections/ado-server.mdx @@ -100,7 +100,7 @@ If you're not familiar with Sourcebot [connections](/docs/connections/overview), Azure Devops Server requires you to provide a PAT in order to index your repositories. To learn how to create PAT, check out the [Azure Devops docs](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=Windows). Sourcebot needs the `Read` access for the `Code` scope in order to find and clone your repos. -Next, provide the access token via the `token` property, either as an environment variable or a secret: +Next, provide the access token via an environment variable which is referenced in the `token` property: @@ -127,28 +127,6 @@ Next, provide the access token via the `token` property, either as an environmen ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "azuredevops", - "deploymentType": "server", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - ## Schema reference diff --git a/docs/docs/connections/gitea.mdx b/docs/docs/connections/gitea.mdx index 1d439c76d..0f8505cb3 100644 --- a/docs/docs/connections/gitea.mdx +++ b/docs/docs/connections/gitea.mdx @@ -81,7 +81,7 @@ In order to index private repositories, you'll need to generate a Gitea access t ![Gitea Access token creation](/images/gitea_pat_creation.png) -Next, provide the access token via the `token` property, either as an environment variable or a secret: +Next, provide the access token via an environment variable which is referenced in the `token` property: @@ -107,27 +107,6 @@ Next, provide the access token via the `token` property, either as an environmen ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "gitea", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - ## Connecting to a custom Gitea diff --git a/docs/docs/connections/github.mdx b/docs/docs/connections/github.mdx index 98fc5b507..e87a1f6d8 100644 --- a/docs/docs/connections/github.mdx +++ b/docs/docs/connections/github.mdx @@ -128,7 +128,7 @@ In order to index private repositories, you'll need to generate a access token a -Next, provide the access token via the `token` property, either as an environment variable or a secret: +Next, provide the access token via an environment variable which is referenced in the `token` property: @@ -154,27 +154,6 @@ Next, provide the access token via the `token` property, either as an environmen ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "github", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - ## Connecting to a custom GitHub host diff --git a/docs/docs/connections/gitlab.mdx b/docs/docs/connections/gitlab.mdx index 2680064b0..1b71b7ae3 100644 --- a/docs/docs/connections/gitlab.mdx +++ b/docs/docs/connections/gitlab.mdx @@ -116,7 +116,7 @@ In order to index private projects, you'll need to generate a GitLab Personal Ac ![GitLab PAT Scope](/images/gitlab_pat_scopes.png) -Next, provide the PAT via the `token` property, either as an environment variable or a secret: +Next, provide the PAT via an environment variable which is referenced in the `token` property: @@ -142,27 +142,6 @@ Next, provide the PAT via the `token` property, either as an environment variabl ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "gitlab", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - ## Connecting to a custom GitLab host diff --git a/docs/snippets/bitbucket-app-password.mdx b/docs/snippets/bitbucket-app-password.mdx index 0a5fdac3f..2d4511c3c 100644 --- a/docs/snippets/bitbucket-app-password.mdx +++ b/docs/snippets/bitbucket-app-password.mdx @@ -24,27 +24,4 @@ ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your access token: - - ![](/images/secrets_list.png) - - 2. Add the `token` and `user` (username associated with the app password you created) properties to your connection config: - - ```json - { - "type": "bitbucket", - "deploymentType": "cloud", - "user": "myusername", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - \ No newline at end of file diff --git a/docs/snippets/bitbucket-token.mdx b/docs/snippets/bitbucket-token.mdx index 94197e01e..26efe2486 100644 --- a/docs/snippets/bitbucket-token.mdx +++ b/docs/snippets/bitbucket-token.mdx @@ -22,25 +22,4 @@ ghcr.io/sourcebot-dev/sourcebot:latest ``` - - - Secrets are only supported when [authentication](/docs/configuration/auth/overview) is enabled. - - 1. Navigate to **Secrets** in settings and create a new secret with your PAT: - - ![](/images/secrets_list.png) - - 2. Add the `token` property to your connection config: - - ```json - { - "type": "bitbucket", - "token": { - "secret": "mysecret" - } - // .. rest of config .. - } - ``` - - \ No newline at end of file diff --git a/docs/snippets/schemas/v2/index.schema.mdx b/docs/snippets/schemas/v2/index.schema.mdx index df78084a5..f061d3b34 100644 --- a/docs/snippets/schemas/v2/index.schema.mdx +++ b/docs/snippets/schemas/v2/index.schema.mdx @@ -77,7 +77,6 @@ "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -274,7 +273,6 @@ "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -465,7 +463,6 @@ "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -779,7 +776,6 @@ "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -976,7 +972,6 @@ "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1167,7 +1162,6 @@ "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1563,7 +1557,6 @@ "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1760,7 +1753,6 @@ "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1951,7 +1943,6 @@ "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } diff --git a/docs/snippets/schemas/v3/app.schema.mdx b/docs/snippets/schemas/v3/app.schema.mdx index 6d5e5a212..1e95a482b 100644 --- a/docs/snippets/schemas/v3/app.schema.mdx +++ b/docs/snippets/schemas/v3/app.schema.mdx @@ -28,19 +28,6 @@ "privateKey": { "description": "The private key of the GitHub App.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -90,19 +77,6 @@ "privateKey": { "description": "The private key of the GitHub App.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/azuredevops.schema.mdx b/docs/snippets/schemas/v3/azuredevops.schema.mdx index fab796de2..e187f276a 100644 --- a/docs/snippets/schemas/v3/azuredevops.schema.mdx +++ b/docs/snippets/schemas/v3/azuredevops.schema.mdx @@ -11,25 +11,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/bitbucket.schema.mdx b/docs/snippets/schemas/v3/bitbucket.schema.mdx index 829d0254f..85202242e 100644 --- a/docs/snippets/schemas/v3/bitbucket.schema.mdx +++ b/docs/snippets/schemas/v3/bitbucket.schema.mdx @@ -15,25 +15,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/connection.schema.mdx b/docs/snippets/schemas/v3/connection.schema.mdx index 48750ae18..10311eba6 100644 --- a/docs/snippets/schemas/v3/connection.schema.mdx +++ b/docs/snippets/schemas/v3/connection.schema.mdx @@ -15,25 +15,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -228,25 +210,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -435,25 +399,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -707,25 +653,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -880,25 +808,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/gitea.schema.mdx b/docs/snippets/schemas/v3/gitea.schema.mdx index f236e3fe0..f663ba47c 100644 --- a/docs/snippets/schemas/v3/gitea.schema.mdx +++ b/docs/snippets/schemas/v3/gitea.schema.mdx @@ -11,25 +11,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/github.schema.mdx b/docs/snippets/schemas/v3/github.schema.mdx index 1858eee88..49ea2ce6c 100644 --- a/docs/snippets/schemas/v3/github.schema.mdx +++ b/docs/snippets/schemas/v3/github.schema.mdx @@ -11,25 +11,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/githubApp.schema.mdx b/docs/snippets/schemas/v3/githubApp.schema.mdx deleted file mode 100644 index 2d1aea882..000000000 --- a/docs/snippets/schemas/v3/githubApp.schema.mdx +++ /dev/null @@ -1,76 +0,0 @@ -{/* THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! */} -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "object", - "title": "GithubAppConfig", - "properties": { - "type": { - "const": "githubApp", - "description": "GitHub App Configuration" - }, - "deploymentHostname": { - "type": "string", - "format": "hostname", - "default": "github.com", - "description": "The hostname of the GitHub App deployment.", - "examples": [ - "github.com", - "github.example.com" - ] - }, - "id": { - "type": "string", - "description": "The ID of the GitHub App." - }, - "privateKey": { - "description": "The private key of the GitHub App.", - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "type", - "id" - ], - "oneOf": [ - { - "required": [ - "privateKey" - ] - }, - { - "required": [ - "privateKeyPath" - ] - } - ], - "additionalProperties": false -} -``` diff --git a/docs/snippets/schemas/v3/gitlab.schema.mdx b/docs/snippets/schemas/v3/gitlab.schema.mdx index 1d322f441..4783aee6c 100644 --- a/docs/snippets/schemas/v3/gitlab.schema.mdx +++ b/docs/snippets/schemas/v3/gitlab.schema.mdx @@ -11,25 +11,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 89ed6be21..383516820 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -298,25 +298,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -511,25 +493,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -718,25 +682,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -990,25 +936,7 @@ }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1163,25 +1091,7 @@ }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1453,19 +1363,6 @@ "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1484,19 +1381,6 @@ "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1515,19 +1399,6 @@ "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1569,19 +1440,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1626,19 +1484,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1672,19 +1517,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1733,19 +1565,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1783,19 +1602,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1840,19 +1646,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1886,19 +1679,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1943,19 +1723,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1989,19 +1756,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2062,19 +1816,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2108,19 +1849,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2183,19 +1911,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2229,19 +1944,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2286,19 +1988,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2332,19 +2021,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2395,19 +2071,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2454,26 +2117,13 @@ { "type": "object", "properties": { - "secret": { + "env": { "type": "string", - "description": "The name of the secret that contains the token." + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." } }, "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" + "env" ], "additionalProperties": false } @@ -2508,19 +2158,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2557,19 +2194,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2601,19 +2225,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2669,19 +2280,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2715,19 +2313,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2776,19 +2361,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2822,19 +2394,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2882,19 +2441,6 @@ "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2913,19 +2459,6 @@ "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2944,19 +2477,6 @@ "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2998,19 +2518,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3055,19 +2562,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3101,19 +2595,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3162,19 +2643,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3212,19 +2680,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3269,19 +2724,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3315,19 +2757,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3372,19 +2801,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3418,19 +2834,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3491,19 +2894,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3537,19 +2927,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3612,19 +2989,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3658,19 +3022,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3715,19 +3066,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3761,19 +3099,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3824,19 +3149,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3880,19 +3192,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3937,19 +3236,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3986,19 +3272,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4030,19 +3303,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4098,19 +3358,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4144,19 +3391,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4205,19 +3439,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4251,19 +3472,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4324,19 +3532,6 @@ }, "privateKey": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4386,19 +3581,6 @@ }, "privateKey": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/languageModel.schema.mdx b/docs/snippets/schemas/v3/languageModel.schema.mdx index accfc95ca..ebc1bc928 100644 --- a/docs/snippets/schemas/v3/languageModel.schema.mdx +++ b/docs/snippets/schemas/v3/languageModel.schema.mdx @@ -22,19 +22,6 @@ "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -53,19 +40,6 @@ "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -84,19 +58,6 @@ "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -138,19 +99,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -195,19 +143,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -241,19 +176,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -302,19 +224,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -352,19 +261,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -409,19 +305,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -455,19 +338,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -512,19 +382,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -558,19 +415,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -631,19 +475,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -677,19 +508,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -752,19 +570,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -798,19 +603,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -855,19 +647,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -901,19 +680,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -964,19 +730,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1020,19 +773,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1077,19 +817,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1126,19 +853,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1170,19 +884,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1238,19 +939,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1284,19 +972,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1345,19 +1020,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1391,19 +1053,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1451,19 +1100,6 @@ "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1482,19 +1118,6 @@ "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1513,19 +1136,6 @@ "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1567,19 +1177,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1624,19 +1221,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1670,19 +1254,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1731,19 +1302,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1781,19 +1339,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1838,19 +1383,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1884,19 +1416,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1941,19 +1460,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1987,19 +1493,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2060,19 +1553,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2106,19 +1586,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2181,19 +1648,6 @@ }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2227,19 +1681,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2284,19 +1725,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2330,19 +1758,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2393,19 +1808,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2449,19 +1851,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2506,19 +1895,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2555,19 +1931,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2599,19 +1962,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2667,19 +2017,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2713,19 +2050,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2774,19 +2098,6 @@ }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2820,19 +2131,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/docs/snippets/schemas/v3/shared.schema.mdx b/docs/snippets/schemas/v3/shared.schema.mdx index 82ca91951..4087a944a 100644 --- a/docs/snippets/schemas/v3/shared.schema.mdx +++ b/docs/snippets/schemas/v3/shared.schema.mdx @@ -6,19 +6,6 @@ "definitions": { "Token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -86,19 +73,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -130,19 +104,6 @@ }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/backend/src/azuredevops.ts b/packages/backend/src/azuredevops.ts index de5879357..aa0fbf550 100644 --- a/packages/backend/src/azuredevops.ts +++ b/packages/backend/src/azuredevops.ts @@ -2,7 +2,6 @@ import { AzureDevOpsConnectionConfig } from "@sourcebot/schemas/v3/azuredevops.t import { createLogger } from "@sourcebot/logger"; import { measure, fetchWithRetry } from "./utils.js"; import micromatch from "micromatch"; -import { PrismaClient } from "@sourcebot/db"; import { BackendException, BackendError } from "@sourcebot/error"; import { processPromiseResults, throwIfAnyFailed } from "./connectionUtils.js"; import * as Sentry from "@sentry/node"; @@ -29,13 +28,11 @@ function createAzureDevOpsConnection( export const getAzureDevOpsReposFromConfig = async ( config: AzureDevOpsConnectionConfig, - orgId: number, - db: PrismaClient ) => { const baseUrl = config.url || `https://${AZUREDEVOPS_CLOUD_HOSTNAME}`; const token = config.token ? - await getTokenFromConfig(config.token, orgId, db) : + await getTokenFromConfig(config.token) : undefined; if (!token) { diff --git a/packages/backend/src/bitbucket.ts b/packages/backend/src/bitbucket.ts index 75adc311b..c6fa87ffe 100644 --- a/packages/backend/src/bitbucket.ts +++ b/packages/backend/src/bitbucket.ts @@ -3,7 +3,6 @@ import { createBitbucketServerClient } from "@coderabbitai/bitbucket/server"; import { BitbucketConnectionConfig } from "@sourcebot/schemas/v3/bitbucket.type"; import type { ClientOptions, ClientPathsWithMethod } from "openapi-fetch"; import { createLogger } from "@sourcebot/logger"; -import { PrismaClient } from "@sourcebot/db"; import { measure, fetchWithRetry } from "./utils.js"; import * as Sentry from "@sentry/node"; import { @@ -58,9 +57,9 @@ type ServerPaginatedResponse = { readonly nextPageStart: number; } -export const getBitbucketReposFromConfig = async (config: BitbucketConnectionConfig, orgId: number, db: PrismaClient) => { +export const getBitbucketReposFromConfig = async (config: BitbucketConnectionConfig) => { const token = config.token ? - await getTokenFromConfig(config.token, orgId, db) : + await getTokenFromConfig(config.token) : undefined; if (config.deploymentType === 'server' && !config.url) { diff --git a/packages/backend/src/connectionManager.ts b/packages/backend/src/connectionManager.ts index 40637ff0c..006a3bf2a 100644 --- a/packages/backend/src/connectionManager.ts +++ b/packages/backend/src/connectionManager.ts @@ -179,25 +179,25 @@ export class ConnectionManager { const result = await (async () => { switch (config.type) { case 'github': { - return await compileGithubConfig(config, job.data.connectionId, orgId, this.db, abortController); + return await compileGithubConfig(config, job.data.connectionId, abortController); } case 'gitlab': { - return await compileGitlabConfig(config, job.data.connectionId, orgId, this.db); + return await compileGitlabConfig(config, job.data.connectionId); } case 'gitea': { - return await compileGiteaConfig(config, job.data.connectionId, orgId, this.db); + return await compileGiteaConfig(config, job.data.connectionId); } case 'gerrit': { - return await compileGerritConfig(config, job.data.connectionId, orgId); + return await compileGerritConfig(config, job.data.connectionId); } case 'bitbucket': { - return await compileBitbucketConfig(config, job.data.connectionId, orgId, this.db); + return await compileBitbucketConfig(config, job.data.connectionId); } case 'azuredevops': { - return await compileAzureDevOpsConfig(config, job.data.connectionId, orgId, this.db); + return await compileAzureDevOpsConfig(config, job.data.connectionId); } case 'git': { - return await compileGenericGitHostConfig(config, job.data.connectionId, orgId); + return await compileGenericGitHostConfig(config, job.data.connectionId); } } })(); diff --git a/packages/backend/src/ee/githubAppManager.ts b/packages/backend/src/ee/githubAppManager.ts index ffe5f5299..d8a72dff5 100644 --- a/packages/backend/src/ee/githubAppManager.ts +++ b/packages/backend/src/ee/githubAppManager.ts @@ -55,11 +55,7 @@ export class GithubAppManager { for (const app of githubApps) { const deploymentHostname = app.deploymentHostname as string || GITHUB_DEFAULT_DEPLOYMENT_HOSTNAME; - - // @todo: we should move SINGLE_TENANT_ORG_ID to shared package or just remove the need to pass this in - // when resolving tokens - const SINGLE_TENANT_ORG_ID = 1; - const privateKey = await getTokenFromConfig(app.privateKey, SINGLE_TENANT_ORG_ID, this.db); + const privateKey = await getTokenFromConfig(app.privateKey); const octokitApp = new App({ appId: Number(app.id), diff --git a/packages/backend/src/ee/repoPermissionSyncer.ts b/packages/backend/src/ee/repoPermissionSyncer.ts index 4353c34ef..9a1593d6f 100644 --- a/packages/backend/src/ee/repoPermissionSyncer.ts +++ b/packages/backend/src/ee/repoPermissionSyncer.ts @@ -163,7 +163,7 @@ export class RepoPermissionSyncer { logger.info(`Syncing permissions for repo ${repo.displayName}...`); - const credentials = await getAuthCredentialsForRepo(repo, this.db, logger); + const credentials = await getAuthCredentialsForRepo(repo, logger); if (!credentials) { throw new Error(`No credentials found for repo ${id}`); } diff --git a/packages/backend/src/gitea.ts b/packages/backend/src/gitea.ts index ab3eee3fd..91493b0ff 100644 --- a/packages/backend/src/gitea.ts +++ b/packages/backend/src/gitea.ts @@ -4,7 +4,6 @@ import { measure } from './utils.js'; import fetch from 'cross-fetch'; import { createLogger } from '@sourcebot/logger'; import micromatch from 'micromatch'; -import { PrismaClient } from '@sourcebot/db'; import { processPromiseResults, throwIfAnyFailed } from './connectionUtils.js'; import * as Sentry from "@sentry/node"; import { env } from './env.js'; @@ -13,13 +12,13 @@ import { getTokenFromConfig } from "@sourcebot/crypto"; const logger = createLogger('gitea'); const GITEA_CLOUD_HOSTNAME = "gitea.com"; -export const getGiteaReposFromConfig = async (config: GiteaConnectionConfig, orgId: number, db: PrismaClient) => { +export const getGiteaReposFromConfig = async (config: GiteaConnectionConfig) => { const hostname = config.url ? new URL(config.url).hostname : GITEA_CLOUD_HOSTNAME; const token = config.token ? - await getTokenFromConfig(config.token, orgId, db) : + await getTokenFromConfig(config.token) : hostname === GITEA_CLOUD_HOSTNAME ? env.FALLBACK_GITEA_CLOUD_TOKEN : undefined; @@ -53,7 +52,7 @@ export const getGiteaReposFromConfig = async (config: GiteaConnectionConfig, org allRepos = allRepos.filter(repo => repo.full_name !== undefined); allRepos = allRepos.filter(repo => { if (repo.full_name === undefined) { - logger.warn(`Repository with undefined full_name found: orgId=${orgId}, repoId=${repo.id}`); + logger.warn(`Repository with undefined full_name found: repoId=${repo.id}`); return false; } return true; diff --git a/packages/backend/src/github.ts b/packages/backend/src/github.ts index 550d259d5..7d4d617f0 100644 --- a/packages/backend/src/github.ts +++ b/packages/backend/src/github.ts @@ -1,6 +1,5 @@ import { Octokit } from "@octokit/rest"; import * as Sentry from "@sentry/node"; -import { PrismaClient } from "@sourcebot/db"; import { createLogger } from "@sourcebot/logger"; import { GithubConnectionConfig } from "@sourcebot/schemas/v3/github.type"; import { hasEntitlement } from "@sourcebot/shared"; @@ -92,13 +91,13 @@ const getOctokitWithGithubApp = async ( } } -export const getGitHubReposFromConfig = async (config: GithubConnectionConfig, orgId: number, db: PrismaClient, signal: AbortSignal): Promise<{ repos: OctokitRepository[], warnings: string[] }> => { +export const getGitHubReposFromConfig = async (config: GithubConnectionConfig, signal: AbortSignal): Promise<{ repos: OctokitRepository[], warnings: string[] }> => { const hostname = config.url ? new URL(config.url).hostname : GITHUB_CLOUD_HOSTNAME; const token = config.token ? - await getTokenFromConfig(config.token, orgId, db) : + await getTokenFromConfig(config.token) : hostname === GITHUB_CLOUD_HOSTNAME ? env.FALLBACK_GITHUB_CLOUD_TOKEN : undefined; diff --git a/packages/backend/src/gitlab.ts b/packages/backend/src/gitlab.ts index 55bae70c1..6063f7bda 100644 --- a/packages/backend/src/gitlab.ts +++ b/packages/backend/src/gitlab.ts @@ -3,7 +3,6 @@ import micromatch from "micromatch"; import { createLogger } from "@sourcebot/logger"; import { GitlabConnectionConfig } from "@sourcebot/schemas/v3/gitlab.type" import { measure, fetchWithRetry } from "./utils.js"; -import { PrismaClient } from "@sourcebot/db"; import { processPromiseResults, throwIfAnyFailed } from "./connectionUtils.js"; import * as Sentry from "@sentry/node"; import { env } from "./env.js"; @@ -34,13 +33,13 @@ export const createGitLabFromOAuthToken = async ({ oauthToken, url }: { oauthTok }); } -export const getGitLabReposFromConfig = async (config: GitlabConnectionConfig, orgId: number, db: PrismaClient) => { +export const getGitLabReposFromConfig = async (config: GitlabConnectionConfig) => { const hostname = config.url ? new URL(config.url).hostname : GITLAB_CLOUD_HOSTNAME; const token = config.token ? - await getTokenFromConfig(config.token, orgId, db) : + await getTokenFromConfig(config.token) : hostname === GITLAB_CLOUD_HOSTNAME ? env.FALLBACK_GITLAB_CLOUD_TOKEN : undefined; diff --git a/packages/backend/src/repoCompileUtils.ts b/packages/backend/src/repoCompileUtils.ts index 8e8b1f268..8ecd79123 100644 --- a/packages/backend/src/repoCompileUtils.ts +++ b/packages/backend/src/repoCompileUtils.ts @@ -7,7 +7,7 @@ import { BitbucketRepository, getBitbucketReposFromConfig } from "./bitbucket.js import { getAzureDevOpsReposFromConfig } from "./azuredevops.js"; import { SchemaRestRepository as BitbucketServerRepository } from "@coderabbitai/bitbucket/server/openapi"; import { SchemaRepository as BitbucketCloudRepository } from "@coderabbitai/bitbucket/cloud/openapi"; -import { Prisma, PrismaClient } from '@sourcebot/db'; +import { Prisma } from '@sourcebot/db'; import { WithRequired } from "./types.js" import { marshalBool } from "./utils.js"; import { createLogger } from '@sourcebot/logger'; @@ -19,6 +19,7 @@ import { getOriginUrl, isPathAValidGitRepoRoot, isUrlAValidGitRepo } from './git import assert from 'assert'; import GitUrlParse from 'git-url-parse'; import { RepoMetadata } from '@sourcebot/shared'; +import { SINGLE_TENANT_ORG_ID } from './constants.js'; export type RepoData = WithRequired; @@ -32,10 +33,8 @@ type CompileResult = { export const compileGithubConfig = async ( config: GithubConnectionConfig, connectionId: number, - orgId: number, - db: PrismaClient, abortController: AbortController): Promise => { - const gitHubReposResult = await getGitHubReposFromConfig(config, orgId, db, abortController.signal); + const gitHubReposResult = await getGitHubReposFromConfig(config, abortController.signal); const gitHubRepos = gitHubReposResult.repos; const warnings = gitHubReposResult.warnings; @@ -66,7 +65,7 @@ export const compileGithubConfig = async ( isPublic: isPublic, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -104,11 +103,9 @@ export const compileGithubConfig = async ( export const compileGitlabConfig = async ( config: GitlabConnectionConfig, - connectionId: number, - orgId: number, - db: PrismaClient): Promise => { + connectionId: number): Promise => { - const gitlabReposResult = await getGitLabReposFromConfig(config, orgId, db); + const gitlabReposResult = await getGitLabReposFromConfig(config); const gitlabRepos = gitlabReposResult.repos; const warnings = gitlabReposResult.warnings; @@ -144,7 +141,7 @@ export const compileGitlabConfig = async ( isArchived: !!project.archived, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -180,11 +177,9 @@ export const compileGitlabConfig = async ( export const compileGiteaConfig = async ( config: GiteaConnectionConfig, - connectionId: number, - orgId: number, - db: PrismaClient): Promise => { + connectionId: number): Promise => { - const giteaReposResult = await getGiteaReposFromConfig(config, orgId, db); + const giteaReposResult = await getGiteaReposFromConfig(config); const giteaRepos = giteaReposResult.repos; const warnings = giteaReposResult.warnings; @@ -217,7 +212,7 @@ export const compileGiteaConfig = async ( isArchived: !!repo.archived, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -251,8 +246,7 @@ export const compileGiteaConfig = async ( export const compileGerritConfig = async ( config: GerritConnectionConfig, - connectionId: number, - orgId: number): Promise => { + connectionId: number): Promise => { const gerritRepos = await getGerritReposFromConfig(config); const hostUrl = config.url; @@ -298,7 +292,7 @@ export const compileGerritConfig = async ( isArchived: false, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -332,11 +326,9 @@ export const compileGerritConfig = async ( export const compileBitbucketConfig = async ( config: BitbucketConnectionConfig, - connectionId: number, - orgId: number, - db: PrismaClient): Promise => { + connectionId: number): Promise => { - const bitbucketReposResult = await getBitbucketReposFromConfig(config, orgId, db); + const bitbucketReposResult = await getBitbucketReposFromConfig(config); const bitbucketRepos = bitbucketReposResult.repos; const warnings = bitbucketReposResult.warnings; @@ -415,7 +407,7 @@ export const compileBitbucketConfig = async ( isArchived: isArchived, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -449,15 +441,14 @@ export const compileBitbucketConfig = async ( export const compileGenericGitHostConfig = async ( config: GenericGitHostConnectionConfig, - connectionId: number, - orgId: number, + connectionId: number ): Promise => { const configUrl = new URL(config.url); if (configUrl.protocol === 'file:') { - return compileGenericGitHostConfig_file(config, orgId, connectionId); + return compileGenericGitHostConfig_file(config, connectionId); } else if (configUrl.protocol === 'http:' || configUrl.protocol === 'https:') { - return compileGenericGitHostConfig_url(config, orgId, connectionId); + return compileGenericGitHostConfig_url(config, connectionId); } else { // Schema should prevent this, but throw an error just in case. @@ -467,7 +458,6 @@ export const compileGenericGitHostConfig = async ( export const compileGenericGitHostConfig_file = async ( config: GenericGitHostConnectionConfig, - orgId: number, connectionId: number, ): Promise => { const configUrl = new URL(config.url); @@ -480,7 +470,7 @@ export const compileGenericGitHostConfig_file = async ( const repos: RepoData[] = []; const warnings: string[] = []; - + await Promise.all(repoPaths.map(async (repoPath) => { const isGitRepo = await isPathAValidGitRepoRoot({ path: repoPath, @@ -517,7 +507,7 @@ export const compileGenericGitHostConfig_file = async ( isArchived: false, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -546,7 +536,6 @@ export const compileGenericGitHostConfig_file = async ( export const compileGenericGitHostConfig_url = async ( config: GenericGitHostConnectionConfig, - orgId: number, connectionId: number, ): Promise => { const remoteUrl = new URL(config.url); @@ -581,7 +570,7 @@ export const compileGenericGitHostConfig_url = async ( isArchived: false, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { @@ -603,11 +592,9 @@ export const compileGenericGitHostConfig_url = async ( export const compileAzureDevOpsConfig = async ( config: AzureDevOpsConnectionConfig, - connectionId: number, - orgId: number, - db: PrismaClient): Promise => { + connectionId: number): Promise => { - const azureDevOpsReposResult = await getAzureDevOpsReposFromConfig(config, orgId, db); + const azureDevOpsReposResult = await getAzureDevOpsReposFromConfig(config); const azureDevOpsRepos = azureDevOpsReposResult.repos; const warnings = azureDevOpsReposResult.warnings; @@ -620,18 +607,18 @@ export const compileAzureDevOpsConfig = async ( if (!repo.project) { throw new Error(`No project found for repository ${repo.name}`); } - + const repoDisplayName = `${repo.project.name}/${repo.name}`; const repoName = path.join(repoNameRoot, repoDisplayName); const isPublic = repo.project.visibility === ProjectVisibility.Public; - + if (!repo.remoteUrl) { throw new Error(`No remoteUrl found for repository ${repoDisplayName}`); } if (!repo.id) { throw new Error(`No id found for repository ${repoDisplayName}`); } - + // Construct web URL for the repository const webUrl = repo.webUrl || `${hostUrl}/${repo.project.name}/_git/${repo.name}`; @@ -651,7 +638,7 @@ export const compileAzureDevOpsConfig = async ( isPublic: isPublic, org: { connect: { - id: orgId, + id: SINGLE_TENANT_ORG_ID, }, }, connections: { diff --git a/packages/backend/src/repoIndexManager.ts b/packages/backend/src/repoIndexManager.ts index 042ba8c7e..3b98e0e08 100644 --- a/packages/backend/src/repoIndexManager.ts +++ b/packages/backend/src/repoIndexManager.ts @@ -290,7 +290,7 @@ export class RepoIndexManager { const metadata = repoMetadataSchema.parse(repo.metadata); - const credentials = await getAuthCredentialsForRepo(repo, this.db); + const credentials = await getAuthCredentialsForRepo(repo); const cloneUrlMaybeWithToken = credentials?.cloneUrlWithToken ?? repo.cloneUrl; const authHeader = credentials?.authHeader ?? undefined; diff --git a/packages/backend/src/utils.ts b/packages/backend/src/utils.ts index 4bb18549f..3a9bace4b 100644 --- a/packages/backend/src/utils.ts +++ b/packages/backend/src/utils.ts @@ -1,7 +1,7 @@ import { Logger } from "winston"; import { RepoAuthCredentials, RepoWithConnections } from "./types.js"; import path from 'path'; -import { PrismaClient, Repo } from "@sourcebot/db"; +import { Repo } from "@sourcebot/db"; import { getTokenFromConfig } from "@sourcebot/crypto"; import * as Sentry from "@sentry/node"; import { GithubConnectionConfig, GitlabConnectionConfig, GiteaConnectionConfig, BitbucketConnectionConfig, AzureDevOpsConnectionConfig } from '@sourcebot/schemas/v3/connection.type'; @@ -110,7 +110,7 @@ export const fetchWithRetry = async ( // fetch the token here using the connections from the repo. Multiple connections could be referencing this repo, and each // may have their own token. This method will just pick the first connection that has a token (if one exists) and uses that. This // may technically cause syncing to fail if that connection's token just so happens to not have access to the repo it's referencing. -export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: PrismaClient, logger?: Logger): Promise => { +export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, logger?: Logger): Promise => { // If we have github apps configured we assume that we must use them for github service auth if (repo.external_codeHostType === 'github' && hasEntitlement('github-app') && GithubAppManager.getInstance().appsConfigured()) { logger?.debug(`Using GitHub App for service auth for repo ${repo.displayName} hosted at ${repo.external_codeHostUrl}`); @@ -139,7 +139,7 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: P if (connection.connectionType === 'github') { const config = connection.config as unknown as GithubConnectionConfig; if (config.token) { - const token = await getTokenFromConfig(config.token, connection.orgId, db); + const token = await getTokenFromConfig(config.token); return { hostUrl: config.url, token, @@ -154,7 +154,7 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: P } else if (connection.connectionType === 'gitlab') { const config = connection.config as unknown as GitlabConnectionConfig; if (config.token) { - const token = await getTokenFromConfig(config.token, connection.orgId, db); + const token = await getTokenFromConfig(config.token); return { hostUrl: config.url, token, @@ -170,7 +170,7 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: P } else if (connection.connectionType === 'gitea') { const config = connection.config as unknown as GiteaConnectionConfig; if (config.token) { - const token = await getTokenFromConfig(config.token, connection.orgId, db); + const token = await getTokenFromConfig(config.token); return { hostUrl: config.url, token, @@ -185,7 +185,7 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: P } else if (connection.connectionType === 'bitbucket') { const config = connection.config as unknown as BitbucketConnectionConfig; if (config.token) { - const token = await getTokenFromConfig(config.token, connection.orgId, db); + const token = await getTokenFromConfig(config.token); const username = config.user ?? 'x-token-auth'; return { hostUrl: config.url, @@ -202,7 +202,7 @@ export const getAuthCredentialsForRepo = async (repo: RepoWithConnections, db: P } else if (connection.connectionType === 'azuredevops') { const config = connection.config as unknown as AzureDevOpsConnectionConfig; if (config.token) { - const token = await getTokenFromConfig(config.token, connection.orgId, db); + const token = await getTokenFromConfig(config.token); // For ADO server, multiple auth schemes may be supported. If the ADO deployment supports NTLM, the git clone will default // to this over basic auth. As a result, we cannot embed the token in the clone URL and must force basic auth by passing in the token diff --git a/packages/crypto/src/tokenUtils.ts b/packages/crypto/src/tokenUtils.ts index be5a064de..b474c0e07 100644 --- a/packages/crypto/src/tokenUtils.ts +++ b/packages/crypto/src/tokenUtils.ts @@ -1,26 +1,7 @@ -import { PrismaClient } from "@sourcebot/db"; import { Token } from "@sourcebot/schemas/v3/shared.type"; -import { decrypt } from "./index.js"; -export const getTokenFromConfig = async (token: Token, orgId: number, db: PrismaClient) => { - if ('secret' in token) { - const secretKey = token.secret; - const secret = await db.secret.findUnique({ - where: { - orgId_key: { - key: secretKey, - orgId - } - } - }); - - if (!secret) { - throw new Error(`Secret with key ${secretKey} not found for org ${orgId}`); - } - - const decryptedToken = decrypt(secret.iv, secret.encryptedValue); - return decryptedToken; - } else if ('env' in token) { +export const getTokenFromConfig = async (token: Token) => { + if ('env' in token) { const envToken = process.env[token.env]; if (!envToken) { throw new Error(`Environment variable ${token.env} not found.`); diff --git a/packages/db/prisma/migrations/20251031191203_remove_secret_table/migration.sql b/packages/db/prisma/migrations/20251031191203_remove_secret_table/migration.sql new file mode 100644 index 000000000..1b2f8dc25 --- /dev/null +++ b/packages/db/prisma/migrations/20251031191203_remove_secret_table/migration.sql @@ -0,0 +1,11 @@ +/* + Warnings: + + - You are about to drop the `Secret` table. If the table is not empty, all the data it contains will be lost. + +*/ +-- DropForeignKey +ALTER TABLE "Secret" DROP CONSTRAINT "Secret_orgId_fkey"; + +-- DropTable +DROP TABLE "Secret"; diff --git a/packages/db/prisma/schema.prisma b/packages/db/prisma/schema.prisma index 93adb7171..7f2c7fae7 100644 --- a/packages/db/prisma/schema.prisma +++ b/packages/db/prisma/schema.prisma @@ -226,7 +226,6 @@ model Org { members UserToOrg[] connections Connection[] repos Repo[] - secrets Secret[] apiKeys ApiKey[] isOnboarded Boolean @default(false) imageUrl String? @@ -276,19 +275,6 @@ model UserToOrg { @@id([orgId, userId]) } -model Secret { - orgId Int - key String - encryptedValue String - iv String - - createdAt DateTime @default(now()) - - org Org @relation(fields: [orgId], references: [id], onDelete: Cascade) - - @@id([orgId, key]) -} - model ApiKey { name String hash String @id @unique diff --git a/packages/schemas/src/v2/index.schema.ts b/packages/schemas/src/v2/index.schema.ts index a37f2f3c0..a4e9c304e 100644 --- a/packages/schemas/src/v2/index.schema.ts +++ b/packages/schemas/src/v2/index.schema.ts @@ -76,7 +76,6 @@ const schema = { "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -273,7 +272,6 @@ const schema = { "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -464,7 +462,6 @@ const schema = { "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -778,7 +775,6 @@ const schema = { "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -975,7 +971,6 @@ const schema = { "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1166,7 +1161,6 @@ const schema = { "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1562,7 +1556,6 @@ const schema = { "token": { "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1759,7 +1752,6 @@ const schema = { "token": { "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } @@ -1950,7 +1942,6 @@ const schema = { "token": { "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } diff --git a/packages/schemas/src/v3/app.schema.ts b/packages/schemas/src/v3/app.schema.ts index 87a7eb27f..a6d1280c2 100644 --- a/packages/schemas/src/v3/app.schema.ts +++ b/packages/schemas/src/v3/app.schema.ts @@ -27,19 +27,6 @@ const schema = { "privateKey": { "description": "The private key of the GitHub App.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -89,19 +76,6 @@ const schema = { "privateKey": { "description": "The private key of the GitHub App.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/app.type.ts b/packages/schemas/src/v3/app.type.ts index c087a7594..d0a4e34ee 100644 --- a/packages/schemas/src/v3/app.type.ts +++ b/packages/schemas/src/v3/app.type.ts @@ -18,17 +18,10 @@ export interface GitHubAppConfig { /** * The private key of the GitHub App. */ - privateKey: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + privateKey: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } diff --git a/packages/schemas/src/v3/azuredevops.schema.ts b/packages/schemas/src/v3/azuredevops.schema.ts index 3b36fbed1..f0d560851 100644 --- a/packages/schemas/src/v3/azuredevops.schema.ts +++ b/packages/schemas/src/v3/azuredevops.schema.ts @@ -10,25 +10,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/azuredevops.type.ts b/packages/schemas/src/v3/azuredevops.type.ts index b6ef68da7..9c6c96f11 100644 --- a/packages/schemas/src/v3/azuredevops.type.ts +++ b/packages/schemas/src/v3/azuredevops.type.ts @@ -8,19 +8,12 @@ export interface AzureDevOpsConnectionConfig { /** * A Personal Access Token (PAT). */ - token: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Azure DevOps host. For Azure DevOps Cloud, use https://dev.azure.com. For Azure DevOps Server, use your server URL. */ diff --git a/packages/schemas/src/v3/bitbucket.schema.ts b/packages/schemas/src/v3/bitbucket.schema.ts index a7c857ce3..a5de1b913 100644 --- a/packages/schemas/src/v3/bitbucket.schema.ts +++ b/packages/schemas/src/v3/bitbucket.schema.ts @@ -14,25 +14,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/bitbucket.type.ts b/packages/schemas/src/v3/bitbucket.type.ts index 260d949dd..cbd8d9d81 100644 --- a/packages/schemas/src/v3/bitbucket.type.ts +++ b/packages/schemas/src/v3/bitbucket.type.ts @@ -12,19 +12,12 @@ export interface BitbucketConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Bitbucket URL */ diff --git a/packages/schemas/src/v3/connection.schema.ts b/packages/schemas/src/v3/connection.schema.ts index e0bcbc48a..64872ab15 100644 --- a/packages/schemas/src/v3/connection.schema.ts +++ b/packages/schemas/src/v3/connection.schema.ts @@ -14,25 +14,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -227,25 +209,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -434,25 +398,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -706,25 +652,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -879,25 +807,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/connection.type.ts b/packages/schemas/src/v3/connection.type.ts index df31c465c..0f62c9803 100644 --- a/packages/schemas/src/v3/connection.type.ts +++ b/packages/schemas/src/v3/connection.type.ts @@ -17,19 +17,12 @@ export interface GithubConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitHub host. Defaults to https://github.com */ @@ -106,19 +99,12 @@ export interface GitlabConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitLab host. Defaults to https://gitlab.com */ @@ -177,19 +163,12 @@ export interface GiteaConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Gitea host. Defaults to https://gitea.com */ @@ -263,19 +242,12 @@ export interface BitbucketConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Bitbucket URL */ @@ -320,19 +292,12 @@ export interface AzureDevOpsConnectionConfig { /** * A Personal Access Token (PAT). */ - token: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Azure DevOps host. For Azure DevOps Cloud, use https://dev.azure.com. For Azure DevOps Server, use your server URL. */ diff --git a/packages/schemas/src/v3/gitea.schema.ts b/packages/schemas/src/v3/gitea.schema.ts index 1e1283ee0..2e15067e3 100644 --- a/packages/schemas/src/v3/gitea.schema.ts +++ b/packages/schemas/src/v3/gitea.schema.ts @@ -10,25 +10,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/gitea.type.ts b/packages/schemas/src/v3/gitea.type.ts index ec9e3046e..afbedaf30 100644 --- a/packages/schemas/src/v3/gitea.type.ts +++ b/packages/schemas/src/v3/gitea.type.ts @@ -8,19 +8,12 @@ export interface GiteaConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Gitea host. Defaults to https://gitea.com */ diff --git a/packages/schemas/src/v3/github.schema.ts b/packages/schemas/src/v3/github.schema.ts index c29e1c08b..d32ff6fe3 100644 --- a/packages/schemas/src/v3/github.schema.ts +++ b/packages/schemas/src/v3/github.schema.ts @@ -10,25 +10,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/github.type.ts b/packages/schemas/src/v3/github.type.ts index 4cb73c9b1..980f2f9f1 100644 --- a/packages/schemas/src/v3/github.type.ts +++ b/packages/schemas/src/v3/github.type.ts @@ -8,19 +8,12 @@ export interface GithubConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitHub host. Defaults to https://github.com */ diff --git a/packages/schemas/src/v3/gitlab.schema.ts b/packages/schemas/src/v3/gitlab.schema.ts index 72d367e17..ee0cfd569 100644 --- a/packages/schemas/src/v3/gitlab.schema.ts +++ b/packages/schemas/src/v3/gitlab.schema.ts @@ -10,25 +10,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/gitlab.type.ts b/packages/schemas/src/v3/gitlab.type.ts index f25193b86..98a8d960a 100644 --- a/packages/schemas/src/v3/gitlab.type.ts +++ b/packages/schemas/src/v3/gitlab.type.ts @@ -8,19 +8,12 @@ export interface GitlabConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitLab host. Defaults to https://gitlab.com */ diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index e49d998b4..90e7c0ae9 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -297,25 +297,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -510,25 +492,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -717,25 +681,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -989,25 +935,7 @@ const schema = { }, "token": { "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1162,25 +1090,7 @@ const schema = { }, "token": { "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ], "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1452,19 +1362,6 @@ const schema = { "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1483,19 +1380,6 @@ const schema = { "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1514,19 +1398,6 @@ const schema = { "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1568,19 +1439,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1625,19 +1483,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1671,19 +1516,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1732,19 +1564,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1782,19 +1601,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1839,19 +1645,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1885,19 +1678,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1942,19 +1722,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1988,19 +1755,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2061,19 +1815,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2107,19 +1848,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2182,19 +1910,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2228,19 +1943,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2285,19 +1987,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2331,19 +2020,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2394,19 +2070,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2453,26 +2116,13 @@ const schema = { { "type": "object", "properties": { - "secret": { + "env": { "type": "string", - "description": "The name of the secret that contains the token." + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." } }, "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" + "env" ], "additionalProperties": false } @@ -2507,19 +2157,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2556,19 +2193,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2600,19 +2224,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2668,19 +2279,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2714,19 +2312,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2775,19 +2360,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2821,19 +2393,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2881,19 +2440,6 @@ const schema = { "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2912,19 +2458,6 @@ const schema = { "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2943,19 +2476,6 @@ const schema = { "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2997,19 +2517,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3054,19 +2561,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3100,19 +2594,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3161,19 +2642,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3211,19 +2679,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3268,19 +2723,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3314,19 +2756,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3371,19 +2800,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3417,19 +2833,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3490,19 +2893,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3536,19 +2926,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3611,19 +2988,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3657,19 +3021,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3714,19 +3065,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3760,19 +3098,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3823,19 +3148,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3879,19 +3191,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3936,19 +3235,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3985,19 +3271,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4029,19 +3302,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4097,19 +3357,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4143,19 +3390,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4204,19 +3438,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4250,19 +3471,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4323,19 +3531,6 @@ const schema = { }, "privateKey": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4385,19 +3580,6 @@ const schema = { }, "privateKey": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index eb2b412c9..75acc3d83 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -155,19 +155,12 @@ export interface GithubConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitHub host. Defaults to https://github.com */ @@ -244,19 +237,12 @@ export interface GitlabConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the GitLab host. Defaults to https://gitlab.com */ @@ -315,19 +301,12 @@ export interface GiteaConnectionConfig { /** * A Personal Access Token (PAT). */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Gitea host. Defaults to https://gitea.com */ @@ -401,19 +380,12 @@ export interface BitbucketConnectionConfig { /** * An authentication token. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Bitbucket URL */ @@ -458,19 +430,12 @@ export interface AzureDevOpsConnectionConfig { /** * A Personal Access Token (PAT). */ - token: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The URL of the Azure DevOps host. For Azure DevOps Cloud, use https://dev.azure.com. For Azure DevOps Server, use your server URL. */ @@ -551,51 +516,30 @@ export interface AmazonBedrockLanguageModel { /** * Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable. */ - accessKeyId?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + accessKeyId?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable. */ - accessKeySecret?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + accessKeySecret?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable. */ - sessionToken?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + sessionToken?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The AWS region. Defaults to the `AWS_REGION` environment variable. */ @@ -616,20 +560,12 @@ export interface LanguageModelHeaders { */ [k: string]: | string - | ( - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - } - ); + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } export interface AnthropicLanguageModel { /** @@ -647,19 +583,12 @@ export interface AnthropicLanguageModel { /** * Optional API key to use with the model. Defaults to the `ANTHROPIC_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -686,19 +615,12 @@ export interface AzureLanguageModel { /** * Optional API key to use with the model. Defaults to the `AZURE_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Sets a custom api version. Defaults to `preview`. */ @@ -725,19 +647,12 @@ export interface DeepSeekLanguageModel { /** * Optional API key to use with the model. Defaults to the `DEEPSEEK_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -760,19 +675,12 @@ export interface GoogleGenerativeAILanguageModel { /** * Optional API key to use with the model. Defaults to the `GOOGLE_GENERATIVE_AI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -803,19 +711,12 @@ export interface GoogleVertexAnthropicLanguageModel { /** * Optional file path to service account credentials JSON. Defaults to the `GOOGLE_APPLICATION_CREDENTIALS` environment variable or application default credentials. */ - credentials?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + credentials?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -846,19 +747,12 @@ export interface GoogleVertexLanguageModel { /** * Optional file path to service account credentials JSON. Defaults to the `GOOGLE_APPLICATION_CREDENTIALS` environment variable or application default credentials. */ - credentials?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + credentials?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -881,19 +775,12 @@ export interface MistralLanguageModel { /** * Optional API key to use with the model. Defaults to the `MISTRAL_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -916,19 +803,12 @@ export interface OpenAILanguageModel { /** * Optional API key to use with the model. Defaults to the `OPENAI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -955,19 +835,12 @@ export interface OpenAICompatibleLanguageModel { /** * Optional API key. If specified, adds an `Authorization` header to request headers with the value Bearer . */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Base URL of the OpenAI-compatible chat completions API endpoint. */ @@ -989,20 +862,12 @@ export interface LanguageModelQueryParams { */ [k: string]: | string - | ( - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - } - ); + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } export interface OpenRouterLanguageModel { /** @@ -1020,19 +885,12 @@ export interface OpenRouterLanguageModel { /** * Optional API key to use with the model. Defaults to the `OPENROUTER_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -1055,19 +913,12 @@ export interface XaiLanguageModel { /** * Optional API key to use with the model. Defaults to the `XAI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -1090,17 +941,10 @@ export interface GitHubAppConfig { /** * The private key of the GitHub App. */ - privateKey: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + privateKey: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } diff --git a/packages/schemas/src/v3/languageModel.schema.ts b/packages/schemas/src/v3/languageModel.schema.ts index 3bdb4c00d..e3f72781f 100644 --- a/packages/schemas/src/v3/languageModel.schema.ts +++ b/packages/schemas/src/v3/languageModel.schema.ts @@ -21,19 +21,6 @@ const schema = { "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -52,19 +39,6 @@ const schema = { "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -83,19 +57,6 @@ const schema = { "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -137,19 +98,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -194,19 +142,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -240,19 +175,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -301,19 +223,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -351,19 +260,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -408,19 +304,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -454,19 +337,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -511,19 +381,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -557,19 +414,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -630,19 +474,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -676,19 +507,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -751,19 +569,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -797,19 +602,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -854,19 +646,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -900,19 +679,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -963,19 +729,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1019,19 +772,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1076,19 +816,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1125,19 +852,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1169,19 +883,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1237,19 +938,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1283,19 +971,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1344,19 +1019,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1390,19 +1052,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1450,19 +1099,6 @@ const schema = { "accessKeyId": { "description": "Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1481,19 +1117,6 @@ const schema = { "accessKeySecret": { "description": "Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1512,19 +1135,6 @@ const schema = { "sessionToken": { "description": "Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable.", "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1566,19 +1176,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1623,19 +1220,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1669,19 +1253,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1730,19 +1301,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1780,19 +1338,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1837,19 +1382,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1883,19 +1415,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1940,19 +1459,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -1986,19 +1492,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2059,19 +1552,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2105,19 +1585,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2180,19 +1647,6 @@ const schema = { }, "credentials": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2226,19 +1680,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2283,19 +1724,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2329,19 +1757,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2392,19 +1807,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2448,19 +1850,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2505,19 +1894,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2554,19 +1930,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2598,19 +1961,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2666,19 +2016,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2712,19 +2049,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2773,19 +2097,6 @@ const schema = { }, "token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -2819,19 +2130,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/languageModel.type.ts b/packages/schemas/src/v3/languageModel.type.ts index 58b9aac6f..48f5b83e6 100644 --- a/packages/schemas/src/v3/languageModel.type.ts +++ b/packages/schemas/src/v3/languageModel.type.ts @@ -30,51 +30,30 @@ export interface AmazonBedrockLanguageModel { /** * Optional access key ID to use with the model. Defaults to the `AWS_ACCESS_KEY_ID` environment variable. */ - accessKeyId?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + accessKeyId?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional secret access key to use with the model. Defaults to the `AWS_SECRET_ACCESS_KEY` environment variable. */ - accessKeySecret?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + accessKeySecret?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional session token to use with the model. Defaults to the `AWS_SESSION_TOKEN` environment variable. */ - sessionToken?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + sessionToken?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * The AWS region. Defaults to the `AWS_REGION` environment variable. */ @@ -95,20 +74,12 @@ export interface LanguageModelHeaders { */ [k: string]: | string - | ( - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - } - ); + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } export interface AnthropicLanguageModel { /** @@ -126,19 +97,12 @@ export interface AnthropicLanguageModel { /** * Optional API key to use with the model. Defaults to the `ANTHROPIC_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -165,19 +129,12 @@ export interface AzureLanguageModel { /** * Optional API key to use with the model. Defaults to the `AZURE_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Sets a custom api version. Defaults to `preview`. */ @@ -204,19 +161,12 @@ export interface DeepSeekLanguageModel { /** * Optional API key to use with the model. Defaults to the `DEEPSEEK_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -239,19 +189,12 @@ export interface GoogleGenerativeAILanguageModel { /** * Optional API key to use with the model. Defaults to the `GOOGLE_GENERATIVE_AI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -282,19 +225,12 @@ export interface GoogleVertexAnthropicLanguageModel { /** * Optional file path to service account credentials JSON. Defaults to the `GOOGLE_APPLICATION_CREDENTIALS` environment variable or application default credentials. */ - credentials?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + credentials?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -325,19 +261,12 @@ export interface GoogleVertexLanguageModel { /** * Optional file path to service account credentials JSON. Defaults to the `GOOGLE_APPLICATION_CREDENTIALS` environment variable or application default credentials. */ - credentials?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + credentials?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -360,19 +289,12 @@ export interface MistralLanguageModel { /** * Optional API key to use with the model. Defaults to the `MISTRAL_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -395,19 +317,12 @@ export interface OpenAILanguageModel { /** * Optional API key to use with the model. Defaults to the `OPENAI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -434,19 +349,12 @@ export interface OpenAICompatibleLanguageModel { /** * Optional API key. If specified, adds an `Authorization` header to request headers with the value Bearer . */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Base URL of the OpenAI-compatible chat completions API endpoint. */ @@ -468,20 +376,12 @@ export interface LanguageModelQueryParams { */ [k: string]: | string - | ( - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - } - ); + | { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; } export interface OpenRouterLanguageModel { /** @@ -499,19 +399,12 @@ export interface OpenRouterLanguageModel { /** * Optional API key to use with the model. Defaults to the `OPENROUTER_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ @@ -534,19 +427,12 @@ export interface XaiLanguageModel { /** * Optional API key to use with the model. Defaults to the `XAI_API_KEY` environment variable. */ - token?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + token?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; /** * Optional base URL. */ diff --git a/packages/schemas/src/v3/shared.schema.ts b/packages/schemas/src/v3/shared.schema.ts index 5ecacd448..44238cada 100644 --- a/packages/schemas/src/v3/shared.schema.ts +++ b/packages/schemas/src/v3/shared.schema.ts @@ -5,19 +5,6 @@ const schema = { "definitions": { "Token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -85,19 +72,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -129,19 +103,6 @@ const schema = { }, { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/shared.type.ts b/packages/schemas/src/v3/shared.type.ts index 727de2be4..23113f504 100644 --- a/packages/schemas/src/v3/shared.type.ts +++ b/packages/schemas/src/v3/shared.type.ts @@ -4,19 +4,12 @@ * This interface was referenced by `Shared`'s JSON-Schema * via the `definition` "Token". */ -export type Token = - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; +export type Token = { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; +}; export interface Shared { [k: string]: unknown; diff --git a/packages/web/src/actions.ts b/packages/web/src/actions.ts index 7c3a472ab..895084e06 100644 --- a/packages/web/src/actions.ts +++ b/packages/web/src/actions.ts @@ -255,89 +255,6 @@ export const completeOnboarding = async (domain: string): Promise<{ success: boo }) )); -export const getSecrets = async (domain: string): Promise<{ createdAt: Date; key: string; }[] | ServiceError> => sew(() => - withAuth((userId) => - withOrgMembership(userId, domain, async ({ org }) => { - const secrets = await prisma.secret.findMany({ - where: { - orgId: org.id, - }, - select: { - key: true, - createdAt: true - } - }); - - return secrets.map((secret) => ({ - key: secret.key, - createdAt: secret.createdAt, - })); - }))); - -export const createSecret = async (key: string, value: string, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() => - withAuth((userId) => - withOrgMembership(userId, domain, async ({ org }) => { - const encrypted = encrypt(value); - const existingSecret = await prisma.secret.findUnique({ - where: { - orgId_key: { - orgId: org.id, - key, - } - } - }); - - if (existingSecret) { - return secretAlreadyExists(); - } - - await prisma.secret.create({ - data: { - orgId: org.id, - key, - encryptedValue: encrypted.encryptedData, - iv: encrypted.iv, - } - }); - - - return { - success: true, - } - }))); - -export const checkIfSecretExists = async (key: string, domain: string): Promise => sew(() => - withAuth((userId) => - withOrgMembership(userId, domain, async ({ org }) => { - const secret = await prisma.secret.findUnique({ - where: { - orgId_key: { - orgId: org.id, - key, - } - } - }); - - return !!secret; - }))); - -export const deleteSecret = async (key: string, domain: string): Promise<{ success: boolean } | ServiceError> => sew(() => - withAuth((userId) => - withOrgMembership(userId, domain, async ({ org }) => { - await prisma.secret.delete({ - where: { - orgId_key: { - orgId: org.id, - key, - } - } - }); - - return { - success: true, - } - }))); - export const verifyApiKey = async (apiKeyPayload: ApiKeyPayload): Promise<{ apiKey: ApiKey } | ServiceError> => sew(async () => { const parts = apiKeyPayload.apiKey.split("-"); if (parts.length !== 2 || parts[0] !== "sourcebot") { @@ -1778,21 +1695,21 @@ export const getRepoImage = async (repoId: number): Promise void; - onSecretCreated: (key: string) => void; - codeHostType: CodeHostType; -} - - -export const ImportSecretDialog = ({ open, onOpenChange, onSecretCreated, codeHostType }: ImportSecretDialogProps) => { - const [showValue, setShowValue] = useState(false); - const domain = useDomain(); - const { toast } = useToast(); - const captureEvent = useCaptureEvent(); - - const formSchema = z.object({ - key: z.string().min(1).refine(async (key) => { - const doesSecretExist = await checkIfSecretExists(key, domain); - if(!isServiceError(doesSecretExist)) { - captureEvent('wa_secret_combobox_import_secret_fail', { - type: codeHostType, - error: "A secret with this key already exists.", - }); - } - return isServiceError(doesSecretExist) || !doesSecretExist; - }, "A secret with this key already exists."), - value: z.string().min(1), - }); - - const form = useForm>({ - resolver: zodResolver(formSchema), - defaultValues: { - key: "", - value: "", - }, - }); - const { isSubmitting } = form.formState; - - const onSubmit = useCallback(async (data: z.infer) => { - const response = await createSecret(data.key, data.value, domain); - if (isServiceError(response)) { - toast({ - description: `❌ Failed to create secret. Reason: ${response.message}` - }); - captureEvent('wa_secret_combobox_import_secret_fail', { - type: codeHostType, - error: response.message, - }); - } else { - toast({ - description: `✅ Secret created successfully!` - }); - captureEvent('wa_secret_combobox_import_secret_success', { - type: codeHostType, - }); - form.reset(); - onOpenChange(false); - onSecretCreated(data.key); - } - }, [domain, toast, onOpenChange, onSecretCreated, form, codeHostType, captureEvent]); - - const codeHostSpecificStep = useMemo(() => { - switch (codeHostType) { - case 'github': - return ; - case 'gitlab': - return ; - case 'bitbucket-cloud': - return ; - case 'bitbucket-server': - return ; - case 'gitea': - return ; - case 'gerrit': - return null; - } - }, [codeHostType]); - - - return ( - - - - Import a secret - - Secrets are used to authenticate with a code host. They are encrypted at rest using AES-256-CBC. - Checkout our security docs for more information. - - - -
- { - event.stopPropagation(); - form.handleSubmit(onSubmit)(event); - }} - > - {codeHostSpecificStep} - - - ( - - Value - -
- - -
-
- - The secret value to store securely. - - -
- )} - /> -
- - - ( - - Key - - - - - A unique name to identify this secret. - - - - )} - /> - - -
- -
-
- -
-
- ) -} - -const GitHubPATCreationStep = ({ step }: { step: number }) => { - return ( - Navigate here on github.com (or your enterprise instance) and create a new personal access token. Sourcebot needs the repo scope in order to access private repositories: - > - Create a personal access token - - ) -} - -const GitLabPATCreationStep = ({ step }: { step: number }) => { - return ( - Navigate here on gitlab.com (or your self-hosted instance) and create a new personal access token. Sourcebot needs the read_api scope in order to access private projects: - > - Create a personal access token - - ) -} - -const GiteaPATCreationStep = ({ step }: { step: number }) => { - return ( - Navigate here on gitea.com (or your self-hosted instance) and create a new access token. Sourcebot needs the read:repository, read:user, and read:organization scopes: - > - Create a personal access token - - ) -} - -const BitbucketCloudPATCreationStep = ({ step }: { step: number }) => { - return ( - Please check out our docs for more information on how to create auth credentials for Bitbucket Cloud. - > - - ) -} - -const BitbucketServerPATCreationStep = ({ step }: { step: number }) => { - return ( - Please check out our docs for more information on how to create auth credentials for Bitbucket Data Center. - > - - ) -} - -interface SecretCreationStepProps { - step: number; - title: string; - description: string | React.ReactNode; - children?: React.ReactNode; -} - -const SecretCreationStep = ({ step, title, description, children }: SecretCreationStepProps) => { - return ( -
-
- {step} - -
-

- {title} -

-

- {description} -

- {children} -
- ) -} \ No newline at end of file diff --git a/packages/web/src/app/[domain]/settings/layout.tsx b/packages/web/src/app/[domain]/settings/layout.tsx index 8367a4ba5..ccac2e99e 100644 --- a/packages/web/src/app/[domain]/settings/layout.tsx +++ b/packages/web/src/app/[domain]/settings/layout.tsx @@ -106,10 +106,6 @@ export default async function SettingsLayout( isNotificationDotVisible: connectionStats.numberOfConnectionsWithFirstTimeSyncJobsInProgress > 0, } ] : []), - { - title: "Secrets", - href: `/${domain}/settings/secrets`, - }, { title: "API Keys", href: `/${domain}/settings/apiKeys`, diff --git a/packages/web/src/app/[domain]/settings/secrets/components/importSecretCard.tsx b/packages/web/src/app/[domain]/settings/secrets/components/importSecretCard.tsx deleted file mode 100644 index f92e27125..000000000 --- a/packages/web/src/app/[domain]/settings/secrets/components/importSecretCard.tsx +++ /dev/null @@ -1,66 +0,0 @@ -'use client'; - -import { CodeHostIconButton } from "@/app/[domain]/components/codeHostIconButton"; -import { Card, CardTitle, CardDescription, CardHeader, CardContent } from "@/components/ui/card"; -import { getCodeHostIcon } from "@/lib/utils"; -import { cn, CodeHostType } from "@/lib/utils"; -import { useState } from "react"; -import { ImportSecretDialog } from "@/app/[domain]/components/importSecretDialog"; -import { useRouter } from "next/navigation"; - -interface ImportSecretCardProps { - className?: string; -} - -export const ImportSecretCard = ({ className }: ImportSecretCardProps) => { - const [selectedCodeHost, setSelectedCodeHost] = useState(null); - const [isImportSecretDialogOpen, setIsImportSecretDialogOpen] = useState(false); - const router = useRouter(); - - return ( - <> - - - Import a new secret - Import a secret from a code host to allow Sourcebot to sync private repositories. - - - { - setSelectedCodeHost("github"); - setIsImportSecretDialogOpen(true); - }} - /> - { - setSelectedCodeHost("gitlab"); - setIsImportSecretDialogOpen(true); - }} - /> - { - setSelectedCodeHost("gitea"); - setIsImportSecretDialogOpen(true); - }} - /> - - - {selectedCodeHost && ( - { - router.refresh(); - }} - codeHostType={selectedCodeHost ?? "github"} - /> - )} - - ) -} \ No newline at end of file diff --git a/packages/web/src/app/[domain]/settings/secrets/components/secretsList.tsx b/packages/web/src/app/[domain]/settings/secrets/components/secretsList.tsx deleted file mode 100644 index 92ed4df7e..000000000 --- a/packages/web/src/app/[domain]/settings/secrets/components/secretsList.tsx +++ /dev/null @@ -1,158 +0,0 @@ -'use client'; - -import { Input } from "@/components/ui/input"; -import { LucideKeyRound, MoreVertical, Search, LucideTrash } from "lucide-react"; -import { useState, useMemo, useCallback } from "react"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { getFormattedDate, isServiceError } from "@/lib/utils"; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; -import { Button } from "@/components/ui/button"; -import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog"; -import { deleteSecret } from "@/actions"; -import { useDomain } from "@/hooks/useDomain"; -import { useToast } from "@/components/hooks/use-toast"; -import { useRouter } from "next/navigation"; -import { CodeSnippet } from "@/app/components/codeSnippet"; - -interface Secret { - key: string; - createdAt: Date; -} - -interface SecretsListProps { - secrets: Secret[]; -} - -export const SecretsList = ({ secrets }: SecretsListProps) => { - const [searchQuery, setSearchQuery] = useState(""); - const [dateSort, setDateSort] = useState<"newest" | "oldest">("newest"); - const [secretToDelete, setSecretToDelete] = useState(null); - const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); - const domain = useDomain(); - const { toast } = useToast(); - const router = useRouter(); - - const filteredSecrets = useMemo(() => { - return secrets - .filter((secret) => { - const searchLower = searchQuery.toLowerCase(); - const matchesSearch = secret.key.toLowerCase().includes(searchLower); - return matchesSearch; - }) - .sort((a, b) => { - return dateSort === "newest" - ? b.createdAt.getTime() - a.createdAt.getTime() - : a.createdAt.getTime() - b.createdAt.getTime() - }); - }, [secrets, searchQuery, dateSort]); - - const onDeleteSecret = useCallback(() => { - deleteSecret(secretToDelete?.key ?? "", domain) - .then((response) => { - if (isServiceError(response)) { - toast({ - description: `❌ Failed to delete secret. Reason: ${response.message}` - }) - } else { - toast({ - description: `✅ Secret deleted successfully.` - }); - router.refresh(); - } - }) - }, [domain, secretToDelete?.key, toast, router]); - - return ( -
-
-
- - setSearchQuery(e.target.value)} - /> -
- - -
- -
-
- {secrets.length === 0 || (filteredSecrets.length === 0 && searchQuery.length > 0) ? ( -
-

No Secrets Found

-

- {filteredSecrets.length === 0 && searchQuery.length > 0 ? "No secrets found matching your filters." : "Use the form above to create a new secret."} -

-
- ) : ( - filteredSecrets.map((secret) => ( -
-
- -

{secret.key}

-
-
-

- Created {getFormattedDate(secret.createdAt)} -

- - - - - - { - setSecretToDelete(secret); - setIsDeleteDialogOpen(true); - }} - > - - Delete secret - - - -
-
- )) - )} -
-
- - - - Delete Secret - - Are you sure you want to delete the secret {secretToDelete?.key}? Any connections that use this secret will fail to sync. - - - - Cancel - - Delete - - - - -
- ) -} diff --git a/packages/web/src/app/[domain]/settings/secrets/page.tsx b/packages/web/src/app/[domain]/settings/secrets/page.tsx deleted file mode 100644 index 02714f59d..000000000 --- a/packages/web/src/app/[domain]/settings/secrets/page.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { getSecrets } from "@/actions"; -import { SecretsList } from "./components/secretsList"; -import { isServiceError } from "@/lib/utils"; -import { ImportSecretCard } from "./components/importSecretCard"; -import { ServiceErrorException } from "@/lib/serviceError"; - -interface SecretsPageProps { - params: Promise<{ - domain: string; - }> -} - -export default async function SecretsPage(props: SecretsPageProps) { - const params = await props.params; - - const { - domain - } = params; - - const secrets = await getSecrets(domain); - if (isServiceError(secrets)) { - throw new ServiceErrorException(secrets); - } - - return ( -
-
-

Manage Secrets

-

These secrets grant Sourcebot access to private code.

-
- - - -
- ) -} \ No newline at end of file diff --git a/packages/web/src/app/api/(server)/chat/route.ts b/packages/web/src/app/api/(server)/chat/route.ts index d7f9368b0..8f045305e 100644 --- a/packages/web/src/app/api/(server)/chat/route.ts +++ b/packages/web/src/app/api/(server)/chat/route.ts @@ -92,7 +92,7 @@ export async function POST(req: Request) { }); } - const { model, providerOptions } = await _getAISDKLanguageModelAndOptions(languageModelConfig, org.id); + const { model, providerOptions } = await _getAISDKLanguageModelAndOptions(languageModelConfig); return createMessageStreamResponse({ messages, diff --git a/packages/web/src/features/chat/actions.ts b/packages/web/src/features/chat/actions.ts index 0e9638c41..ad4e9f123 100644 --- a/packages/web/src/features/chat/actions.ts +++ b/packages/web/src/features/chat/actions.ts @@ -21,7 +21,7 @@ import { createXai } from '@ai-sdk/xai'; import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { getTokenFromConfig } from "@sourcebot/crypto"; -import { ChatVisibility, OrgRole, Prisma, PrismaClient } from "@sourcebot/db"; +import { ChatVisibility, OrgRole, Prisma } from "@sourcebot/db"; import { LanguageModel } from "@sourcebot/schemas/v3/languageModel.type"; import { Token } from "@sourcebot/schemas/v3/shared.type"; import { loadConfig } from "@sourcebot/shared"; @@ -204,7 +204,7 @@ export const generateAndUpdateChatNameFromMessage = async ({ chatId, languageMod }); } - const { model } = await _getAISDKLanguageModelAndOptions(languageModelConfig, org.id); + const { model } = await _getAISDKLanguageModelAndOptions(languageModelConfig); const prompt = `Convert this question into a short topic title (max 50 characters). @@ -374,7 +374,7 @@ export const _getConfiguredLanguageModelsFull = async (): Promise>, }> => { @@ -386,16 +386,16 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or baseURL: config.baseUrl, region: config.region ?? env.AWS_REGION, accessKeyId: config.accessKeyId - ? await getTokenFromConfig(config.accessKeyId, orgId, prisma) + ? await getTokenFromConfig(config.accessKeyId) : env.AWS_ACCESS_KEY_ID, secretAccessKey: config.accessKeySecret - ? await getTokenFromConfig(config.accessKeySecret, orgId, prisma) + ? await getTokenFromConfig(config.accessKeySecret) : env.AWS_SECRET_ACCESS_KEY, sessionToken: config.sessionToken - ? await getTokenFromConfig(config.sessionToken, orgId, prisma) + ? await getTokenFromConfig(config.sessionToken) : env.AWS_SESSION_TOKEN, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, // Fallback to the default Node.js credential provider chain if no credentials are provided. // See: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-credential-providers/#fromnodeproviderchain @@ -412,10 +412,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const anthropic = createAnthropic({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.ANTHROPIC_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -434,11 +434,11 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or case 'azure': { const azure = createAzure({ baseURL: config.baseUrl, - apiKey: config.token ? (await getTokenFromConfig(config.token, orgId, prisma)) : env.AZURE_API_KEY, + apiKey: config.token ? (await getTokenFromConfig(config.token)) : env.AZURE_API_KEY, apiVersion: config.apiVersion, resourceName: config.resourceName ?? env.AZURE_RESOURCE_NAME, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -449,9 +449,9 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or case 'deepseek': { const deepseek = createDeepSeek({ baseURL: config.baseUrl, - apiKey: config.token ? (await getTokenFromConfig(config.token, orgId, prisma)) : env.DEEPSEEK_API_KEY, + apiKey: config.token ? (await getTokenFromConfig(config.token)) : env.DEEPSEEK_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -463,10 +463,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const google = createGoogleGenerativeAI({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.GOOGLE_GENERATIVE_AI_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -480,11 +480,11 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or location: config.region ?? env.GOOGLE_VERTEX_REGION, ...(config.credentials ? { googleAuthOptions: { - keyFilename: await getTokenFromConfig(config.credentials, orgId, prisma), + keyFilename: await getTokenFromConfig(config.credentials), } } : {}), headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -506,11 +506,11 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or location: config.region ?? env.GOOGLE_VERTEX_REGION, ...(config.credentials ? { googleAuthOptions: { - keyFilename: await getTokenFromConfig(config.credentials, orgId, prisma), + keyFilename: await getTokenFromConfig(config.credentials), } } : {}), headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -522,10 +522,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const mistral = createMistral({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.MISTRAL_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -537,10 +537,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const openai = createOpenAI({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.OPENAI_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -558,13 +558,13 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or baseURL: config.baseUrl, name: config.displayName ?? modelId, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : undefined, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, queryParams: config.queryParams - ? await extractLanguageModelKeyValuePairs(config.queryParams, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.queryParams) : undefined, }); @@ -585,10 +585,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const openrouter = createOpenRouter({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.OPENROUTER_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -600,10 +600,10 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const xai = createXai({ baseURL: config.baseUrl, apiKey: config.token - ? await getTokenFromConfig(config.token, orgId, prisma) + ? await getTokenFromConfig(config.token) : env.XAI_API_KEY, headers: config.headers - ? await extractLanguageModelKeyValuePairs(config.headers, orgId, prisma) + ? await extractLanguageModelKeyValuePairs(config.headers) : undefined, }); @@ -617,9 +617,7 @@ export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel, or const extractLanguageModelKeyValuePairs = async ( pairs: { [k: string]: string | Token; - }, - orgId: number, - db: PrismaClient, + } ): Promise> => { const resolvedPairs: Record = {}; @@ -633,7 +631,7 @@ const extractLanguageModelKeyValuePairs = async ( continue; } - const value = await getTokenFromConfig(val, orgId, db); + const value = await getTokenFromConfig(val); resolvedPairs[key] = value; } diff --git a/packages/web/src/lib/strings.ts b/packages/web/src/lib/strings.ts deleted file mode 100644 index 9fbcfd47a..000000000 --- a/packages/web/src/lib/strings.ts +++ /dev/null @@ -1,7 +0,0 @@ - -export const strings = { - connectionConfigDescription: "Configure what repositories, organizations, users, etc. you want to sync with Sourcebot. Use the quick actions below to help you configure your connection.", - createSecretDescription: "Secrets are used to authenticate with the code host, allowing Sourcebot to access private repositories.", -} - -export default strings; diff --git a/schemas/v2/index.json b/schemas/v2/index.json index 67334c2a4..0c9a79a21 100644 --- a/schemas/v2/index.json +++ b/schemas/v2/index.json @@ -76,7 +76,6 @@ "$ref": "#/definitions/Token", "description": "A Personal Access Token (PAT).", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } ] }, @@ -210,7 +209,6 @@ "$ref": "#/definitions/Token", "description": "An authentication token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } ] }, @@ -332,7 +330,6 @@ "$ref": "#/definitions/Token", "description": "An access token.", "examples": [ - "secret-token", { "env": "ENV_VAR_CONTAINING_TOKEN" } ] }, diff --git a/schemas/v3/azuredevops.json b/schemas/v3/azuredevops.json index 6cc278335..573a73350 100644 --- a/schemas/v3/azuredevops.json +++ b/schemas/v3/azuredevops.json @@ -9,12 +9,7 @@ }, "token": { "$ref": "./shared.json#/definitions/Token", - "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ] + "description": "A Personal Access Token (PAT)." }, "url": { "type": "string", diff --git a/schemas/v3/bitbucket.json b/schemas/v3/bitbucket.json index be2fdda9b..a980a17ca 100644 --- a/schemas/v3/bitbucket.json +++ b/schemas/v3/bitbucket.json @@ -13,12 +13,7 @@ }, "token": { "$ref": "./shared.json#/definitions/Token", - "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ] + "description": "An authentication token." }, "url": { "type": "string", diff --git a/schemas/v3/gitea.json b/schemas/v3/gitea.json index d5c87665a..35f38fb15 100644 --- a/schemas/v3/gitea.json +++ b/schemas/v3/gitea.json @@ -9,12 +9,7 @@ }, "token": { "$ref": "./shared.json#/definitions/Token", - "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ] + "description": "A Personal Access Token (PAT)." }, "url": { "type": "string", diff --git a/schemas/v3/github.json b/schemas/v3/github.json index ec4a9f4fd..c2002782d 100644 --- a/schemas/v3/github.json +++ b/schemas/v3/github.json @@ -9,12 +9,7 @@ }, "token": { "$ref": "./shared.json#/definitions/Token", - "description": "A Personal Access Token (PAT).", - "examples": [ - { - "secret": "SECRET_KEY" - } - ] + "description": "A Personal Access Token (PAT)." }, "url": { "type": "string", diff --git a/schemas/v3/gitlab.json b/schemas/v3/gitlab.json index ab5b4e621..9d3b1ca9f 100644 --- a/schemas/v3/gitlab.json +++ b/schemas/v3/gitlab.json @@ -9,12 +9,7 @@ }, "token": { "$ref": "./shared.json#/definitions/Token", - "description": "An authentication token.", - "examples": [ - { - "secret": "SECRET_KEY" - } - ] + "description": "An authentication token." }, "url": { "type": "string", diff --git a/schemas/v3/shared.json b/schemas/v3/shared.json index baa6dae86..a290edd15 100644 --- a/schemas/v3/shared.json +++ b/schemas/v3/shared.json @@ -4,19 +4,6 @@ "definitions": { "Token": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { From 43662bc6d17f944e418e5e41f52648597e43f822 Mon Sep 17 00:00:00 2001 From: msukkari Date: Fri, 31 Oct 2025 13:51:42 -0700 Subject: [PATCH 04/16] changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4cc114c0..aa387fdce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed issue with GitHub app token tracking and refreshing. [#583](https://github.com/sourcebot-dev/sourcebot/pull/583) - Fixed "The account is already associated with another user" errors with GitLab oauth provider. [#584](https://github.com/sourcebot-dev/sourcebot/pull/584) +## Removed +- Removed built-in secret manager. [#592](https://github.com/sourcebot-dev/sourcebot/pull/592) + ## [4.8.1] - 2025-10-29 ### Fixed From e047eb06b90c4251db4ac95b7b864b16b9181b43 Mon Sep 17 00:00:00 2001 From: msukkari Date: Fri, 31 Oct 2025 14:12:48 -0700 Subject: [PATCH 05/16] init sso from config --- .../schemas/v3/identityProvider.schema.mdx | 839 ++++++++++++++++++ docs/snippets/schemas/v3/index.schema.mdx | 476 +--------- packages/backend/src/ee/githubAppManager.ts | 2 +- .../schemas/src/v3/identityProvider.schema.ts | 838 +++++++++++++++++ .../schemas/src/v3/identityProvider.type.ts | 149 ++++ packages/schemas/src/v3/index.schema.ts | 476 +--------- packages/schemas/src/v3/index.type.ts | 346 +++----- packages/web/src/ee/features/sso/sso.ts | 55 +- 8 files changed, 1993 insertions(+), 1188 deletions(-) create mode 100644 docs/snippets/schemas/v3/identityProvider.schema.mdx create mode 100644 packages/schemas/src/v3/identityProvider.schema.ts create mode 100644 packages/schemas/src/v3/identityProvider.type.ts diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx new file mode 100644 index 000000000..905730ef1 --- /dev/null +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -0,0 +1,839 @@ +{/* THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! */} +```json +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] +} +``` diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 8e362d745..0a3af5ecf 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -3624,24 +3624,11 @@ "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3659,19 +3646,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3689,19 +3663,6 @@ }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3734,24 +3695,11 @@ "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3769,19 +3717,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3799,19 +3734,6 @@ }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3844,19 +3766,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3874,19 +3783,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3917,19 +3813,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3947,19 +3830,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3977,19 +3847,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4021,19 +3878,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4051,19 +3895,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4081,19 +3912,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4125,19 +3943,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4155,19 +3960,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4185,19 +3977,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4229,19 +4008,6 @@ }, "audience": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4274,24 +4040,11 @@ "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4309,19 +4062,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4339,19 +4079,6 @@ }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4384,24 +4111,11 @@ "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4419,19 +4133,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4449,19 +4150,6 @@ }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4494,19 +4182,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4524,19 +4199,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4567,19 +4229,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4597,19 +4246,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4627,19 +4263,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4671,19 +4294,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4701,19 +4311,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4731,19 +4328,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4775,19 +4359,6 @@ }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4805,19 +4376,6 @@ }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4835,19 +4393,6 @@ }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4879,19 +4424,6 @@ }, "audience": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/backend/src/ee/githubAppManager.ts b/packages/backend/src/ee/githubAppManager.ts index d8a72dff5..892e637bd 100644 --- a/packages/backend/src/ee/githubAppManager.ts +++ b/packages/backend/src/ee/githubAppManager.ts @@ -50,7 +50,7 @@ export class GithubAppManager { return; } - const githubApps = config.apps.filter(app => app.type === 'githubApp') as GitHubAppConfig[]; + const githubApps = config.apps.filter(app => app.type === 'github') as GitHubAppConfig[]; logger.info(`Found ${githubApps.length} GitHub apps in config`); for (const app of githubApps) { diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts new file mode 100644 index 000000000..4e849a4cd --- /dev/null +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -0,0 +1,838 @@ +// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! +const schema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "IdentityProviderConfig", + "definitions": { + "GitHubIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + "GitLabIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + "GoogleIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + "OktaIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "KeycloakIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "MicrosoftEntraIDIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + "GCPIAPIdentityProviderConfig": { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + }, + "oneOf": [ + { + "type": "object", + "properties": { + "provider": { + "const": "github" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gitlab" + }, + "purpose": { + "enum": [ + "sso", + "integration" + ] + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "baseUrl": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "purpose", + "clientId", + "clientSecret", + "baseUrl" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "google" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "okta" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "keycloak" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "microsoft-entra-id" + }, + "clientId": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "clientSecret": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + }, + "issuer": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "clientId", + "clientSecret", + "issuer" + ] + }, + { + "type": "object", + "properties": { + "provider": { + "const": "gcp-iap" + }, + "audience": { + "anyOf": [ + { + "type": "object", + "properties": { + "env": { + "type": "string", + "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + } + }, + "required": [ + "env" + ], + "additionalProperties": false + } + ] + } + }, + "required": [ + "provider", + "audience" + ] + } + ] +} as const; +export { schema as identityProviderSchema }; \ No newline at end of file diff --git a/packages/schemas/src/v3/identityProvider.type.ts b/packages/schemas/src/v3/identityProvider.type.ts new file mode 100644 index 000000000..6c45243b1 --- /dev/null +++ b/packages/schemas/src/v3/identityProvider.type.ts @@ -0,0 +1,149 @@ +// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! + +export type IdentityProviderConfig = + | GitHubIdentityProviderConfig + | GitLabIdentityProviderConfig + | GoogleIdentityProviderConfig + | OktaIdentityProviderConfig + | KeycloakIdentityProviderConfig + | MicrosoftEntraIDIdentityProviderConfig + | GCPIAPIdentityProviderConfig; + +export interface GitHubIdentityProviderConfig { + provider: "github"; + purpose: "sso" | "integration"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GitLabIdentityProviderConfig { + provider: "gitlab"; + purpose: "sso" | "integration"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GoogleIdentityProviderConfig { + provider: "google"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface OktaIdentityProviderConfig { + provider: "okta"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface KeycloakIdentityProviderConfig { + provider: "keycloak"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface MicrosoftEntraIDIdentityProviderConfig { + provider: "microsoft-entra-id"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} +export interface GCPIAPIdentityProviderConfig { + provider: "gcp-iap"; + audience: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + [k: string]: unknown; +} diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index fee632d66..bf694f2c6 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -3623,24 +3623,11 @@ const schema = { "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3658,19 +3645,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3688,19 +3662,6 @@ const schema = { }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3733,24 +3694,11 @@ const schema = { "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3768,19 +3716,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3798,19 +3733,6 @@ const schema = { }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3843,19 +3765,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3873,19 +3782,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3916,19 +3812,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3946,19 +3829,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -3976,19 +3846,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4020,19 +3877,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4050,19 +3894,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4080,19 +3911,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4124,19 +3942,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4154,19 +3959,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4184,19 +3976,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4228,19 +4007,6 @@ const schema = { }, "audience": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4273,24 +4039,11 @@ const schema = { "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4308,19 +4061,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4338,19 +4078,6 @@ const schema = { }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4383,24 +4110,11 @@ const schema = { "purpose": { "enum": [ "sso", - "identity" + "integration" ] }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4418,19 +4132,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4448,19 +4149,6 @@ const schema = { }, "baseUrl": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4493,19 +4181,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4523,19 +4198,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4566,19 +4228,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4596,19 +4245,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4626,19 +4262,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4670,19 +4293,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4700,19 +4310,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4730,19 +4327,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4774,19 +4358,6 @@ const schema = { }, "clientId": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4804,19 +4375,6 @@ const schema = { }, "clientSecret": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4834,19 +4392,6 @@ const schema = { }, "issuer": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -4878,19 +4423,6 @@ const schema = { }, "audience": { "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, { "type": "object", "properties": { diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index d0f4ef0d2..708052ca6 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -962,265 +962,139 @@ export interface GitHubAppConfig { } export interface GitHubIdentityProviderConfig { provider: "github"; - purpose: "sso" | "identity"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - baseUrl?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + purpose: "sso" | "integration"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl?: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface GitLabIdentityProviderConfig { provider: "gitlab"; - purpose: "sso" | "identity"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - baseUrl: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + purpose: "sso" | "integration"; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + baseUrl: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface GoogleIdentityProviderConfig { provider: "google"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface OktaIdentityProviderConfig { provider: "okta"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface KeycloakIdentityProviderConfig { provider: "keycloak"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface MicrosoftEntraIDIdentityProviderConfig { provider: "microsoft-entra-id"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + clientId: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + clientSecret: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; + issuer: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } export interface GCPIAPIdentityProviderConfig { provider: "gcp-iap"; - audience: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; + audience: { + /** + * The name of the environment variable that contains the token. Only supported in declarative connection configs. + */ + env: string; + }; [k: string]: unknown; } diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 0d12a5edc..8a6d88562 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -14,7 +14,7 @@ import { onCreateUser } from "@/lib/authUtils"; import { createLogger } from "@sourcebot/logger"; import { hasEntitlement, loadConfig } from "@sourcebot/shared"; import { getTokenFromConfig } from "@sourcebot/crypto"; -import { SINGLE_TENANT_ORG_ID } from "@/lib/constants"; +import { GCPIAPIdentityProviderConfig, GitHubIdentityProviderConfig, GitLabIdentityProviderConfig, GoogleIdentityProviderConfig, KeycloakIdentityProviderConfig, MicrosoftEntraIDIdentityProviderConfig, OktaIdentityProviderConfig } from "@sourcebot/schemas/v3/index.type"; const logger = createLogger('web-sso'); @@ -26,19 +26,60 @@ export const getSSOProviders = async (): Promise => { for (const identityProvider of identityProviders) { if (identityProvider.provider === "github") { - const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db); - const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db); - const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined; + const providerConfig = identityProvider as GitHubIdentityProviderConfig; + if (providerConfig.purpose !== "sso") { + continue; + } + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; providers.push(createGitHubProvider(clientId, clientSecret, baseUrl)); } if (identityProvider.provider === "gitlab") { - const clientId = await getTokenFromConfig(identityProvider.clientId, SINGLE_TENANT_ORG_ID, db); - const clientSecret = await getTokenFromConfig(identityProvider.clientSecret, SINGLE_TENANT_ORG_ID, db); - const baseUrl = identityProvider.baseUrl ? await getTokenFromConfig(identityProvider.baseUrl, SINGLE_TENANT_ORG_ID, db) : undefined; + const providerConfig = identityProvider as GitLabIdentityProviderConfig; + if (providerConfig.purpose !== "sso") { + continue; + } + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; providers.push(createGitLabProvider(clientId, clientSecret, baseUrl)); } + if (identityProvider.provider === "google") { + const providerConfig = identityProvider as GoogleIdentityProviderConfig; + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + providers.push(createGoogleProvider(clientId, clientSecret)); + } + if (identityProvider.provider === "okta") { + const providerConfig = identityProvider as OktaIdentityProviderConfig; + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + const issuer = await getTokenFromConfig(providerConfig.issuer); + providers.push(createOktaProvider(clientId, clientSecret, issuer)); + } + if (identityProvider.provider === "keycloak") { + const providerConfig = identityProvider as KeycloakIdentityProviderConfig; + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + const issuer = await getTokenFromConfig(providerConfig.issuer); + providers.push(createKeycloakProvider(clientId, clientSecret, issuer)); + } + if (identityProvider.provider === "microsoft-entra-id") { + const providerConfig = identityProvider as MicrosoftEntraIDIdentityProviderConfig; + const clientId = await getTokenFromConfig(providerConfig.clientId); + const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); + const issuer = await getTokenFromConfig(providerConfig.issuer); + providers.push(createMicrosoftEntraIDProvider(clientId, clientSecret, issuer)); + } + if (identityProvider.provider === "gcp-iap") { + const providerConfig = identityProvider as GCPIAPIdentityProviderConfig; + const audience = await getTokenFromConfig(providerConfig.audience); + providers.push(createGCPIAPProvider(audience)); + } } + // @deprecate if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { providers.push(createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL)); } From 6db7aa37ddc2ffc74b5ea47cab9a2fe543647730 Mon Sep 17 00:00:00 2001 From: msukkari Date: Sat, 1 Nov 2025 15:11:41 -0700 Subject: [PATCH 06/16] properly handle sso idps from config --- .../src/app/components/authMethodSelector.tsx | 10 +++---- packages/web/src/app/invite/page.tsx | 6 ++--- .../src/app/login/components/loginForm.tsx | 4 +-- packages/web/src/app/login/page.tsx | 4 +-- packages/web/src/app/onboard/page.tsx | 4 +-- packages/web/src/app/signup/page.tsx | 4 +-- packages/web/src/auth.ts | 23 +++++++++------- packages/web/src/ee/features/sso/sso.ts | 26 +++++++------------ packages/web/src/lib/authProviders.ts | 13 +++++----- 9 files changed, 47 insertions(+), 47 deletions(-) diff --git a/packages/web/src/app/components/authMethodSelector.tsx b/packages/web/src/app/components/authMethodSelector.tsx index 84d1228e2..9d6f2734e 100644 --- a/packages/web/src/app/components/authMethodSelector.tsx +++ b/packages/web/src/app/components/authMethodSelector.tsx @@ -8,10 +8,10 @@ import { CredentialsForm } from "@/app/login/components/credentialsForm"; import { DividerSet } from "@/app/components/dividerSet"; import { ProviderButton } from "@/app/components/providerButton"; import { AuthSecurityNotice } from "@/app/components/authSecurityNotice"; -import type { AuthProvider } from "@/lib/authProviders"; +import type { IdentityProviderMetadata } from "@/lib/authProviders"; interface AuthMethodSelectorProps { - providers: AuthProvider[]; + providers: IdentityProviderMetadata[]; callbackUrl?: string; context: "login" | "signup"; onProviderClick?: (providerId: string) => void; @@ -35,11 +35,11 @@ export const AuthMethodSelector = ({ }, [callbackUrl, onProviderClick]); // Separate OAuth providers from special auth methods - const oauthProviders = providers.filter(p => + const oauthProviders = providers.filter(p => p.purpose === "sso" && !["credentials", "nodemailer"].includes(p.id) ); - const hasCredentials = providers.some(p => p.id === "credentials"); - const hasMagicLink = providers.some(p => p.id === "nodemailer"); + const hasCredentials = providers.some(p => p.purpose === "sso" && p.id === "credentials"); + const hasMagicLink = providers.some(p => p.purpose === "sso" && p.id === "nodemailer"); return ( <> diff --git a/packages/web/src/app/invite/page.tsx b/packages/web/src/app/invite/page.tsx index 195a8d177..df284589d 100644 --- a/packages/web/src/app/invite/page.tsx +++ b/packages/web/src/app/invite/page.tsx @@ -7,7 +7,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { SourcebotLogo } from "@/app/components/sourcebotLogo"; import { AuthMethodSelector } from "@/app/components/authMethodSelector"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; -import { getAuthProviders } from "@/lib/authProviders"; +import { getIdentityProviderMetadata, IdentityProviderMetadata } from "@/lib/authProviders"; import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard"; interface InvitePageProps { @@ -30,7 +30,7 @@ export default async function InvitePage(props: InvitePageProps) { const session = await auth(); if (!session) { - const providers = getAuthProviders(); + const providers = getIdentityProviderMetadata(); return ; } @@ -57,7 +57,7 @@ export default async function InvitePage(props: InvitePageProps) { ); } -function WelcomeCard({ inviteLinkId, providers }: { inviteLinkId: string; providers: import("@/lib/authProviders").AuthProvider[] }) { +function WelcomeCard({ inviteLinkId, providers }: { inviteLinkId: string; providers: IdentityProviderMetadata[] }) { return (
diff --git a/packages/web/src/app/login/components/loginForm.tsx b/packages/web/src/app/login/components/loginForm.tsx index 1d1eb5e30..f24bb8f56 100644 --- a/packages/web/src/app/login/components/loginForm.tsx +++ b/packages/web/src/app/login/components/loginForm.tsx @@ -6,12 +6,12 @@ import { SourcebotLogo } from "@/app/components/sourcebotLogo"; import { AuthMethodSelector } from "@/app/components/authMethodSelector"; import useCaptureEvent from "@/hooks/useCaptureEvent"; import Link from "next/link"; -import type { AuthProvider } from "@/lib/authProviders"; +import type { IdentityProviderMetadata } from "@/lib/authProviders"; interface LoginFormProps { callbackUrl?: string; error?: string; - providers: AuthProvider[]; + providers: IdentityProviderMetadata[]; context: "login" | "signup"; } diff --git a/packages/web/src/app/login/page.tsx b/packages/web/src/app/login/page.tsx index 1535ec589..730ca6102 100644 --- a/packages/web/src/app/login/page.tsx +++ b/packages/web/src/app/login/page.tsx @@ -2,7 +2,7 @@ import { auth } from "@/auth"; import { LoginForm } from "./components/loginForm"; import { redirect } from "next/navigation"; import { Footer } from "@/app/components/footer"; -import { getAuthProviders } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/authProviders"; import { getOrgFromDomain } from "@/data/org"; import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; @@ -25,7 +25,7 @@ export default async function Login(props: LoginProps) { return redirect("/onboard"); } - const providers = getAuthProviders(); + const providers = getIdentityProviderMetadata(); return (
diff --git a/packages/web/src/app/onboard/page.tsx b/packages/web/src/app/onboard/page.tsx index b446c15ff..d995fa9cd 100644 --- a/packages/web/src/app/onboard/page.tsx +++ b/packages/web/src/app/onboard/page.tsx @@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button" import { AuthMethodSelector } from "@/app/components/authMethodSelector" import { SourcebotLogo } from "@/app/components/sourcebotLogo" import { auth } from "@/auth"; -import { getAuthProviders } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/authProviders"; import { OrganizationAccessSettings } from "@/app/components/organizationAccessSettings"; import { CompleteOnboardingButton } from "./components/completeOnboardingButton"; import { getOrgFromDomain } from "@/data/org"; @@ -41,7 +41,7 @@ interface ResourceCard { export default async function Onboarding(props: OnboardingProps) { const searchParams = await props.searchParams; - const providers = getAuthProviders(); + const providers = getIdentityProviderMetadata(); const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN); const session = await auth(); diff --git a/packages/web/src/app/signup/page.tsx b/packages/web/src/app/signup/page.tsx index dc9205961..8c2c76ff6 100644 --- a/packages/web/src/app/signup/page.tsx +++ b/packages/web/src/app/signup/page.tsx @@ -3,7 +3,7 @@ import { LoginForm } from "../login/components/loginForm"; import { redirect } from "next/navigation"; import { Footer } from "@/app/components/footer"; import { createLogger } from "@sourcebot/logger"; -import { getAuthProviders } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/authProviders"; import { getOrgFromDomain } from "@/data/org"; import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; @@ -29,7 +29,7 @@ export default async function Signup(props: LoginProps) { return redirect("/onboard"); } - const providers = getAuthProviders(); + const providers = getIdentityProviderMetadata(); return (
diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index 544976d00..68a2501e6 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -13,17 +13,22 @@ import { createTransport } from 'nodemailer'; import { render } from '@react-email/render'; import MagicLinkEmail from './emails/magicLinkEmail'; import bcrypt from 'bcryptjs'; -import { getSSOProviders } from '@/ee/features/sso/sso'; +import { getEEIdentityProviders } from '@/ee/features/sso/sso'; import { hasEntitlement } from '@sourcebot/shared'; import { onCreateUser } from '@/lib/authUtils'; import { getAuditService } from '@/ee/features/audit/factory'; import { SINGLE_TENANT_ORG_ID } from './lib/constants'; const auditService = getAuditService(); -const ssoProviders = hasEntitlement("sso") ? await getSSOProviders() : []; +const eeIdentityProviders = hasEntitlement("sso") ? await getEEIdentityProviders() : []; export const runtime = 'nodejs'; +export type IdentityProvider = { + provider: Provider; + purpose: "sso" | "integration"; +} + declare module 'next-auth' { interface Session { user: { @@ -33,16 +38,16 @@ declare module 'next-auth' { } declare module 'next-auth/jwt' { - interface JWT { + interface JWT { userId: string } } export const getProviders = () => { - const providers: Provider[] = ssoProviders; + const providers: IdentityProvider[] = eeIdentityProviders; if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') { - providers.push(EmailProvider({ + providers.push({ provider: EmailProvider({ server: env.SMTP_CONNECTION_URL, from: env.EMAIL_FROM_ADDRESS, maxAge: 60 * 10, @@ -66,11 +71,11 @@ export const getProviders = () => { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } } - })); + }), purpose: "sso"}); } if (env.AUTH_CREDENTIALS_LOGIN_ENABLED === 'true') { - providers.push(Credentials({ + providers.push({ provider: Credentials({ credentials: { email: {}, password: {} @@ -123,7 +128,7 @@ export const getProviders = () => { }; } } - })); + }), purpose: "sso"}); } return providers; @@ -193,7 +198,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ return session; }, }, - providers: getProviders(), + providers: getProviders().map((provider) => provider.provider), pages: { signIn: "/login", // We set redirect to false in signInOptions so we can pass the email is as a param diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 8a6d88562..550920320 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -1,4 +1,3 @@ -import type { Provider } from "next-auth/providers"; import { env } from "@/env.mjs"; import GitHub from "next-auth/providers/github"; import Google from "next-auth/providers/google"; @@ -14,12 +13,13 @@ import { onCreateUser } from "@/lib/authUtils"; import { createLogger } from "@sourcebot/logger"; import { hasEntitlement, loadConfig } from "@sourcebot/shared"; import { getTokenFromConfig } from "@sourcebot/crypto"; +import type { IdentityProvider } from "@/auth"; import { GCPIAPIdentityProviderConfig, GitHubIdentityProviderConfig, GitLabIdentityProviderConfig, GoogleIdentityProviderConfig, KeycloakIdentityProviderConfig, MicrosoftEntraIDIdentityProviderConfig, OktaIdentityProviderConfig } from "@sourcebot/schemas/v3/index.type"; const logger = createLogger('web-sso'); -export const getSSOProviders = async (): Promise => { - const providers: Provider[] = []; +export const getEEIdentityProviders = async (): Promise => { + const providers: IdentityProvider[] = []; const config = env.CONFIG_PATH ? await loadConfig(env.CONFIG_PATH) : undefined; const identityProviders = config?.identityProviders ?? []; @@ -27,55 +27,49 @@ export const getSSOProviders = async (): Promise => { for (const identityProvider of identityProviders) { if (identityProvider.provider === "github") { const providerConfig = identityProvider as GitHubIdentityProviderConfig; - if (providerConfig.purpose !== "sso") { - continue; - } const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push(createGitHubProvider(clientId, clientSecret, baseUrl)); + providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose }); } if (identityProvider.provider === "gitlab") { const providerConfig = identityProvider as GitLabIdentityProviderConfig; - if (providerConfig.purpose !== "sso") { - continue; - } const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push(createGitLabProvider(clientId, clientSecret, baseUrl)); + providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose }); } if (identityProvider.provider === "google") { const providerConfig = identityProvider as GoogleIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); - providers.push(createGoogleProvider(clientId, clientSecret)); + providers.push({ provider: createGoogleProvider(clientId, clientSecret), purpose: "sso"}); } if (identityProvider.provider === "okta") { const providerConfig = identityProvider as OktaIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push(createOktaProvider(clientId, clientSecret, issuer)); + providers.push({ provider: createOktaProvider(clientId, clientSecret, issuer), purpose: "sso"}); } if (identityProvider.provider === "keycloak") { const providerConfig = identityProvider as KeycloakIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push(createKeycloakProvider(clientId, clientSecret, issuer)); + providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: "sso"}); } if (identityProvider.provider === "microsoft-entra-id") { const providerConfig = identityProvider as MicrosoftEntraIDIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push(createMicrosoftEntraIDProvider(clientId, clientSecret, issuer)); + providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: "sso"}); } if (identityProvider.provider === "gcp-iap") { const providerConfig = identityProvider as GCPIAPIdentityProviderConfig; const audience = await getTokenFromConfig(providerConfig.audience); - providers.push(createGCPIAPProvider(audience)); + providers.push({ provider: createGCPIAPProvider(audience), purpose: "sso"}); } } diff --git a/packages/web/src/lib/authProviders.ts b/packages/web/src/lib/authProviders.ts index ca2a66971..efcb54ffe 100644 --- a/packages/web/src/lib/authProviders.ts +++ b/packages/web/src/lib/authProviders.ts @@ -1,18 +1,19 @@ import { getProviders } from "@/auth"; -export interface AuthProvider { +export interface IdentityProviderMetadata { id: string; name: string; + purpose: "sso" | "integration"; } -export const getAuthProviders = (): AuthProvider[] => { +export const getIdentityProviderMetadata = (): IdentityProviderMetadata[] => { const providers = getProviders(); return providers.map((provider) => { - if (typeof provider === "function") { - const providerInfo = provider(); - return { id: providerInfo.id, name: providerInfo.name }; + if (typeof provider.provider === "function") { + const providerInfo = provider.provider(); + return { id: providerInfo.id, name: providerInfo.name, purpose: provider.purpose }; } else { - return { id: provider.id, name: provider.name }; + return { id: provider.provider.id, name: provider.provider.name, purpose: provider.purpose }; } }); }; \ No newline at end of file From b1259c564fae19d95c2c1858b6e5ec083650f5d4 Mon Sep 17 00:00:00 2001 From: msukkari Date: Sun, 2 Nov 2025 16:11:48 -0800 Subject: [PATCH 07/16] add logic for account link onboarding --- .../schemas/v3/identityProvider.schema.mdx | 16 ++ docs/snippets/schemas/v3/index.schema.mdx | 16 ++ .../schemas/src/v3/identityProvider.schema.ts | 16 ++ .../schemas/src/v3/identityProvider.type.ts | 2 + packages/schemas/src/v3/index.schema.ts | 16 ++ packages/schemas/src/v3/index.type.ts | 2 + packages/shared/src/utils.ts | 6 +- packages/web/src/actions.ts | 4 +- packages/web/src/app/[domain]/layout.tsx | 47 +++++- .../web/src/app/[domain]/settings/layout.tsx | 9 + .../permission-syncing/linkButton.tsx | 30 ++++ .../settings/permission-syncing/page.tsx | 20 +++ .../src/app/components/authMethodSelector.tsx | 2 +- packages/web/src/app/invite/page.tsx | 2 +- .../src/app/login/components/loginForm.tsx | 2 +- packages/web/src/app/login/page.tsx | 2 +- packages/web/src/app/onboard/page.tsx | 2 +- packages/web/src/app/signup/page.tsx | 2 +- packages/web/src/auth.ts | 1 + .../ee/features/permissionSyncing/actions.ts | 119 +++++++++++++ .../components/providerBadge.tsx | 16 ++ .../components/providerIcon.tsx | 48 ++++++ .../components/providerInfo.tsx | 24 +++ .../permissionSyncing/linkAccounts.tsx | 118 +++++++++++++ .../features/permissionSyncing/linkButton.tsx | 31 ++++ .../linkedAccountsSettings.tsx | 159 ++++++++++++++++++ .../permissionSyncing/unlinkButton.tsx | 75 +++++++++ packages/web/src/ee/features/sso/sso.ts | 27 +-- packages/web/src/features/chat/actions.ts | 17 +- packages/web/src/initialize.ts | 42 +++-- packages/web/src/lib/constants.ts | 1 + ...{authProviders.ts => identityProviders.ts} | 1 + schemas/v3/identityProvider.json | 8 + 33 files changed, 825 insertions(+), 58 deletions(-) create mode 100644 packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx create mode 100644 packages/web/src/app/[domain]/settings/permission-syncing/page.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/actions.ts create mode 100644 packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/linkButton.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/linkedAccountsSettings.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/unlinkButton.tsx rename packages/web/src/lib/{authProviders.ts => identityProviders.ts} (96%) diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index 905730ef1..5105f3f15 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -66,6 +66,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -137,6 +141,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -482,6 +490,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -553,6 +565,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 0a3af5ecf..5d043b955 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -3677,6 +3677,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -3748,6 +3752,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -4093,6 +4101,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -4164,6 +4176,10 @@ "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts index 4e849a4cd..1d351539c 100644 --- a/packages/schemas/src/v3/identityProvider.schema.ts +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -65,6 +65,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -136,6 +140,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -481,6 +489,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -552,6 +564,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ diff --git a/packages/schemas/src/v3/identityProvider.type.ts b/packages/schemas/src/v3/identityProvider.type.ts index 6c45243b1..5cac3a744 100644 --- a/packages/schemas/src/v3/identityProvider.type.ts +++ b/packages/schemas/src/v3/identityProvider.type.ts @@ -30,6 +30,7 @@ export interface GitHubIdentityProviderConfig { */ env: string; }; + required?: boolean; [k: string]: unknown; } export interface GitLabIdentityProviderConfig { @@ -53,6 +54,7 @@ export interface GitLabIdentityProviderConfig { */ env: string; }; + required?: boolean; [k: string]: unknown; } export interface GoogleIdentityProviderConfig { diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index bf694f2c6..3133915e4 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -3676,6 +3676,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -3747,6 +3751,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -4092,6 +4100,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ @@ -4163,6 +4175,10 @@ const schema = { "additionalProperties": false } ] + }, + "required": { + "type": "boolean", + "default": true } }, "required": [ diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index 708052ca6..e7ab4ee4f 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -981,6 +981,7 @@ export interface GitHubIdentityProviderConfig { */ env: string; }; + required?: boolean; [k: string]: unknown; } export interface GitLabIdentityProviderConfig { @@ -1004,6 +1005,7 @@ export interface GitLabIdentityProviderConfig { */ env: string; }; + required?: boolean; [k: string]: unknown; } export interface GoogleIdentityProviderConfig { diff --git a/packages/shared/src/utils.ts b/packages/shared/src/utils.ts index f7c1b56e0..4eb454bdb 100644 --- a/packages/shared/src/utils.ts +++ b/packages/shared/src/utils.ts @@ -81,7 +81,11 @@ export const loadJsonFile = async ( } } -export const loadConfig = async (configPath: string): Promise => { +export const loadConfig = async (configPath?: string): Promise => { + if (!configPath) { + throw new Error('CONFIG_PATH is required but not provided'); + } + const configContent = await (async () => { if (isRemotePath(configPath)) { const response = await fetch(configPath); diff --git a/packages/web/src/actions.ts b/packages/web/src/actions.ts index 895084e06..4ebfd552a 100644 --- a/packages/web/src/actions.ts +++ b/packages/web/src/actions.ts @@ -4,12 +4,12 @@ import { getAuditService } from "@/ee/features/audit/factory"; import { env } from "@/env.mjs"; import { addUserToOrganization, orgHasAvailability } from "@/lib/authUtils"; import { ErrorCode } from "@/lib/errorCodes"; -import { notAuthenticated, notFound, orgNotFound, secretAlreadyExists, ServiceError, ServiceErrorException, unexpectedError } from "@/lib/serviceError"; +import { notAuthenticated, notFound, orgNotFound, ServiceError, ServiceErrorException, unexpectedError } from "@/lib/serviceError"; import { getOrgMetadata, isHttpError, isServiceError } from "@/lib/utils"; import { prisma } from "@/prisma"; import { render } from "@react-email/components"; import * as Sentry from '@sentry/nextjs'; -import { encrypt, generateApiKey, getTokenFromConfig, hashSecret } from "@sourcebot/crypto"; +import { generateApiKey, getTokenFromConfig, hashSecret } from "@sourcebot/crypto"; import { ApiKey, ConnectionSyncJobStatus, Org, OrgRole, Prisma, RepoIndexingJobStatus, RepoIndexingJobType, StripeSubscriptionStatus } from "@sourcebot/db"; import { createLogger } from "@sourcebot/logger"; import { GiteaConnectionConfig } from "@sourcebot/schemas/v3/gitea.type"; diff --git a/packages/web/src/app/[domain]/layout.tsx b/packages/web/src/app/[domain]/layout.tsx index b60a50a64..05f910068 100644 --- a/packages/web/src/app/[domain]/layout.tsx +++ b/packages/web/src/app/[domain]/layout.tsx @@ -7,7 +7,7 @@ import { UpgradeGuard } from "./components/upgradeGuard"; import { cookies, headers } from "next/headers"; import { getSelectorsByUserAgent } from "react-device-detect"; import { MobileUnsupportedSplashScreen } from "./components/mobileUnsupportedSplashScreen"; -import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME } from "@/lib/constants"; +import { MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME, OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME } from "@/lib/constants"; import { SyntaxReferenceGuide } from "./components/syntaxReferenceGuide"; import { SyntaxGuideProvider } from "./components/syntaxGuideProvider"; import { IS_BILLING_ENABLED } from "@/ee/features/billing/stripe"; @@ -23,6 +23,8 @@ import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; import { GitHubStarToast } from "./components/githubStarToast"; import { UpgradeToast } from "./components/upgradeToast"; +import { getUnlinkedIntegrationProviders, userNeedsToLinkIdentityProvider } from "@/ee/features/permissionSyncing/actions"; +import { LinkAccounts } from "@/ee/features/permissionSyncing/linkAccounts"; interface LayoutProps { children: React.ReactNode, @@ -123,6 +125,49 @@ export default async function Layout(props: LayoutProps) { ) } + if (hasEntitlement("permission-syncing")) { + const unlinkedAccounts = await getUnlinkedIntegrationProviders(); + if (isServiceError(unlinkedAccounts)) { + return ( +
+ +
+

An error occurred

+

+ {typeof unlinkedAccounts.message === 'string' + ? unlinkedAccounts.message + : "A server error occurred while checking your account status. Please try again or contact support."} +

+
+
+ ) + } + + if (unlinkedAccounts.length > 0) { + // Separate required and optional providers + const requiredProviders = unlinkedAccounts.filter(p => p.required !== false); + const hasRequiredProviders = requiredProviders.length > 0; + + // Check if user has skipped optional providers + const cookieStore = await cookies(); + const hasSkippedOptional = cookieStore.has(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); + + // Show LinkAccounts if: + // 1. There are required providers, OR + // 2. There are only optional providers AND user hasn't skipped yet + const shouldShowLinkAccounts = hasRequiredProviders || !hasSkippedOptional; + + if (shouldShowLinkAccounts) { + return ( +
+ + +
+ ) + } + } + } + if (IS_BILLING_ENABLED) { const subscription = await getSubscriptionInfo(domain); if ( diff --git a/packages/web/src/app/[domain]/settings/layout.tsx b/packages/web/src/app/[domain]/settings/layout.tsx index ccac2e99e..b0aa8f5b6 100644 --- a/packages/web/src/app/[domain]/settings/layout.tsx +++ b/packages/web/src/app/[domain]/settings/layout.tsx @@ -11,6 +11,7 @@ import { ServiceErrorException } from "@/lib/serviceError"; import { getOrgFromDomain } from "@/data/org"; import { OrgRole } from "@prisma/client"; import { env } from "@/env.mjs"; +import { hasEntitlement } from "@sourcebot/shared"; interface LayoutProps { children: React.ReactNode; @@ -68,6 +69,8 @@ export default async function SettingsLayout( throw new ServiceErrorException(connectionStats); } + const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing"); + const sidebarNavItems: SidebarNavItem[] = [ { title: "General", @@ -114,6 +117,12 @@ export default async function SettingsLayout( title: "Analytics", href: `/${domain}/settings/analytics`, }, + ...(hasPermissionSyncingEntitlement ? [ + { + title: "Linked Accounts", + href: `/${domain}/settings/permission-syncing`, + } + ] : []), ...(env.NEXT_PUBLIC_SOURCEBOT_CLOUD_ENVIRONMENT === undefined ? [ { title: "License", diff --git a/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx b/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx new file mode 100644 index 000000000..49750a3a7 --- /dev/null +++ b/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx @@ -0,0 +1,30 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { Link2 } from "lucide-react"; +import { signIn } from "next-auth/react"; + +interface LinkButtonProps { + provider: string; + providerName: string; + callbackUrl: string; +} + +export const LinkButton = ({ provider, providerName, callbackUrl }: LinkButtonProps) => { + const handleLink = () => { + signIn(provider, { + redirectTo: callbackUrl + }); + }; + + return ( + + ); +}; diff --git a/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx new file mode 100644 index 000000000..a3cc04f20 --- /dev/null +++ b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx @@ -0,0 +1,20 @@ +import { hasEntitlement } from "@sourcebot/shared"; +import { notFound } from "@/lib/serviceError"; +import { LinkedAccountsSettings } from "@/ee/features/permissionSyncing/linkedAccountsSettings"; + +interface PermissionSyncingPageProps { + params: Promise<{ + domain: string; + }> +} + +export default async function PermissionSyncingPage(props: PermissionSyncingPageProps) { + const params = await props.params; + + const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing"); + if (!hasPermissionSyncingEntitlement) { + notFound(); + } + + return ; +} diff --git a/packages/web/src/app/components/authMethodSelector.tsx b/packages/web/src/app/components/authMethodSelector.tsx index 9d6f2734e..442fb919a 100644 --- a/packages/web/src/app/components/authMethodSelector.tsx +++ b/packages/web/src/app/components/authMethodSelector.tsx @@ -8,7 +8,7 @@ import { CredentialsForm } from "@/app/login/components/credentialsForm"; import { DividerSet } from "@/app/components/dividerSet"; import { ProviderButton } from "@/app/components/providerButton"; import { AuthSecurityNotice } from "@/app/components/authSecurityNotice"; -import type { IdentityProviderMetadata } from "@/lib/authProviders"; +import type { IdentityProviderMetadata } from "@/lib/identityProviders"; interface AuthMethodSelectorProps { providers: IdentityProviderMetadata[]; diff --git a/packages/web/src/app/invite/page.tsx b/packages/web/src/app/invite/page.tsx index df284589d..539bf781a 100644 --- a/packages/web/src/app/invite/page.tsx +++ b/packages/web/src/app/invite/page.tsx @@ -7,7 +7,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { SourcebotLogo } from "@/app/components/sourcebotLogo"; import { AuthMethodSelector } from "@/app/components/authMethodSelector"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; -import { getIdentityProviderMetadata, IdentityProviderMetadata } from "@/lib/authProviders"; +import { getIdentityProviderMetadata, IdentityProviderMetadata } from "@/lib/identityProviders"; import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard"; interface InvitePageProps { diff --git a/packages/web/src/app/login/components/loginForm.tsx b/packages/web/src/app/login/components/loginForm.tsx index f24bb8f56..b13e19fb6 100644 --- a/packages/web/src/app/login/components/loginForm.tsx +++ b/packages/web/src/app/login/components/loginForm.tsx @@ -6,7 +6,7 @@ import { SourcebotLogo } from "@/app/components/sourcebotLogo"; import { AuthMethodSelector } from "@/app/components/authMethodSelector"; import useCaptureEvent from "@/hooks/useCaptureEvent"; import Link from "next/link"; -import type { IdentityProviderMetadata } from "@/lib/authProviders"; +import type { IdentityProviderMetadata } from "@/lib/identityProviders"; interface LoginFormProps { callbackUrl?: string; diff --git a/packages/web/src/app/login/page.tsx b/packages/web/src/app/login/page.tsx index 730ca6102..2ce955c5e 100644 --- a/packages/web/src/app/login/page.tsx +++ b/packages/web/src/app/login/page.tsx @@ -2,7 +2,7 @@ import { auth } from "@/auth"; import { LoginForm } from "./components/loginForm"; import { redirect } from "next/navigation"; import { Footer } from "@/app/components/footer"; -import { getIdentityProviderMetadata } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/identityProviders"; import { getOrgFromDomain } from "@/data/org"; import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; diff --git a/packages/web/src/app/onboard/page.tsx b/packages/web/src/app/onboard/page.tsx index d995fa9cd..33077a9be 100644 --- a/packages/web/src/app/onboard/page.tsx +++ b/packages/web/src/app/onboard/page.tsx @@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button" import { AuthMethodSelector } from "@/app/components/authMethodSelector" import { SourcebotLogo } from "@/app/components/sourcebotLogo" import { auth } from "@/auth"; -import { getIdentityProviderMetadata } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/identityProviders"; import { OrganizationAccessSettings } from "@/app/components/organizationAccessSettings"; import { CompleteOnboardingButton } from "./components/completeOnboardingButton"; import { getOrgFromDomain } from "@/data/org"; diff --git a/packages/web/src/app/signup/page.tsx b/packages/web/src/app/signup/page.tsx index 8c2c76ff6..fd00c87df 100644 --- a/packages/web/src/app/signup/page.tsx +++ b/packages/web/src/app/signup/page.tsx @@ -3,7 +3,7 @@ import { LoginForm } from "../login/components/loginForm"; import { redirect } from "next/navigation"; import { Footer } from "@/app/components/footer"; import { createLogger } from "@sourcebot/logger"; -import { getIdentityProviderMetadata } from "@/lib/authProviders"; +import { getIdentityProviderMetadata } from "@/lib/identityProviders"; import { getOrgFromDomain } from "@/data/org"; import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index 68a2501e6..1cb0c6dcc 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -27,6 +27,7 @@ export const runtime = 'nodejs'; export type IdentityProvider = { provider: Provider; purpose: "sso" | "integration"; + required?: boolean; } declare module 'next-auth' { diff --git a/packages/web/src/ee/features/permissionSyncing/actions.ts b/packages/web/src/ee/features/permissionSyncing/actions.ts new file mode 100644 index 000000000..29762de12 --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/actions.ts @@ -0,0 +1,119 @@ +'use server'; + +import { sew } from "@/actions"; +import { createLogger } from "@sourcebot/logger"; +import { withAuthV2, withMinimumOrgRole } from "@/withAuthV2"; +import { loadConfig } from "@sourcebot/shared"; +import { env } from "@/env.mjs"; +import { OrgRole } from "@sourcebot/db"; +import { cookies } from "next/headers"; +import { OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME } from "@/lib/constants"; + +const logger = createLogger('web-ee-permission-syncing-actions'); + +export const userNeedsToLinkIdentityProvider = async () => sew(() => + withAuthV2(async ({ prisma, role, user }) => + withMinimumOrgRole(role, OrgRole.MEMBER, async () => { + const config = await loadConfig(env.CONFIG_PATH); + const identityProviders = config.identityProviders ?? []; + + for (const identityProvider of identityProviders) { + if (identityProvider.purpose === "integration") { + // Only check required providers (default to true if not specified) + const isRequired = 'required' in identityProvider ? identityProvider.required : true; + + if (!isRequired) { + continue; + } + + const linkedAccount = await prisma.account.findFirst({ + where: { + provider: identityProvider.provider, + userId: user.id, + }, + }); + + if (!linkedAccount) { + logger.info(`Required integration identity provider ${identityProvider.provider} account info not found for user ${user.id}`); + return true; + } + } + } + + return false; + }) + ) +); + +export const getUnlinkedIntegrationProviders = async () => sew(() => + withAuthV2(async ({ prisma, role, user }) => + withMinimumOrgRole(role, OrgRole.MEMBER, async () => { + const config = await loadConfig(env.CONFIG_PATH); + const identityProviders = config.identityProviders ?? []; + const unlinkedProviders = []; + + for (const identityProvider of identityProviders) { + if (identityProvider.purpose === "integration") { + const linkedAccount = await prisma.account.findFirst({ + where: { + provider: identityProvider.provider, + userId: user.id, + }, + }); + + if (!linkedAccount) { + const isRequired = 'required' in identityProvider ? identityProvider.required as boolean : true; + logger.info(`Integration identity provider ${identityProvider.provider} not linked for user ${user.id}`); + unlinkedProviders.push({ + id: identityProvider.provider, + name: identityProvider.provider, + purpose: "integration" as const, + required: isRequired, + }); + } + } + } + + return unlinkedProviders; + }) + ) +); + +export const unlinkIntegrationProvider = async (provider: string) => sew(() => + withAuthV2(async ({ prisma, role, user }) => + withMinimumOrgRole(role, OrgRole.MEMBER, async () => { + const config = await loadConfig(env.CONFIG_PATH); + const identityProviders = config.identityProviders ?? []; + + // Verify this is an integration provider + const isIntegrationProvider = identityProviders.some( + idp => idp.provider === provider && idp.purpose === "integration" + ); + + if (!isIntegrationProvider) { + throw new Error("Provider is not an integration provider"); + } + + // Delete the account + const result = await prisma.account.deleteMany({ + where: { + provider, + userId: user.id, + }, + }); + + logger.info(`Unlinked integration provider ${provider} for user ${user.id}. Deleted ${result.count} account(s).`); + + return { success: true, count: result.count }; + }) + ) +); + +export const skipOptionalProvidersLink = async () => sew(async () => { + const cookieStore = await cookies(); + cookieStore.set(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME, 'true', { + httpOnly: false, // Allow client-side access + maxAge: 365 * 24 * 60 * 60, // 1 year in seconds + }); + return true; +}); \ No newline at end of file diff --git a/packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx b/packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx new file mode 100644 index 000000000..522da946a --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/components/providerBadge.tsx @@ -0,0 +1,16 @@ +import { Badge } from "@/components/ui/badge"; + +interface ProviderBadgeProps { + required: boolean; +} + +export function ProviderBadge({ required }: ProviderBadgeProps) { + return ( + + {required ? "Required" : "Optional"} + + ); +} diff --git a/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx b/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx new file mode 100644 index 000000000..3a23d1d56 --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx @@ -0,0 +1,48 @@ +import Image from "next/image"; +import { ShieldCheck } from "lucide-react"; + +interface ProviderIconProps { + icon?: { + src: string; + className?: string; + } | null; + displayName: string; + size?: "sm" | "md" | "lg"; +} + +const sizeClasses = { + sm: { + container: "h-8 w-8", + icon: "h-4 w-4" + }, + md: { + container: "h-10 w-10", + icon: "h-5 w-5" + }, + lg: { + container: "h-12 w-12", + icon: "h-6 w-6" + } +}; + +export function ProviderIcon({ icon, displayName, size = "md" }: ProviderIconProps) { + const sizes = sizeClasses[size]; + + if (icon) { + return ( +
+ {displayName} +
+ ); + } + + return ( +
+ +
+ ); +} diff --git a/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx b/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx new file mode 100644 index 000000000..143075069 --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx @@ -0,0 +1,24 @@ +import { getAuthProviderInfo } from "@/lib/utils"; +import { ProviderIcon } from "./providerIcon"; +import { ProviderBadge } from "./providerBadge"; + +interface ProviderInfoProps { + providerId: string; + required: boolean; + showBadge?: boolean; +} + +export function ProviderInfo({ providerId, required, showBadge = true }: ProviderInfoProps) { + const providerInfo = getAuthProviderInfo(providerId); + + return ( + <> +
+ + {providerInfo.displayName} + + {showBadge && } +
+ + ); +} diff --git a/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx b/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx new file mode 100644 index 000000000..cad1d435e --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx @@ -0,0 +1,118 @@ +'use client'; + +import { signIn } from "next-auth/react"; +import { getAuthProviderInfo } from "@/lib/utils"; +import type { IdentityProviderMetadata } from "@/lib/identityProviders"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { ArrowRight } from "lucide-react"; +import { skipOptionalProvidersLink } from "./actions"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { ProviderIcon } from "./components/providerIcon"; +import { ProviderInfo } from "./components/providerInfo"; + +interface LinkAccountsProps { + unlinkedAccounts: IdentityProviderMetadata[]; + callbackUrl?: string; +} + +export const LinkAccounts = ({ unlinkedAccounts, callbackUrl }: LinkAccountsProps) => { + const router = useRouter(); + const [isSkipping, setIsSkipping] = useState(false); + + const handleSignIn = (providerId: string) => { + signIn(providerId, { + redirectTo: callbackUrl ?? "/" + }); + }; + + const handleSkip = async () => { + setIsSkipping(true); + try { + await skipOptionalProvidersLink(); + router.refresh(); + } catch (error) { + console.error("Failed to skip optional providers:", error); + setIsSkipping(false); + } + }; + + // Separate required and optional providers + const requiredProviders = unlinkedAccounts.filter(p => p.required !== false); + const optionalProviders = unlinkedAccounts.filter(p => p.required === false); + const hasOnlyOptionalProviders = requiredProviders.length === 0 && optionalProviders.length > 0; + + const renderProviderButton = (provider: IdentityProviderMetadata) => { + const providerInfo = getAuthProviderInfo(provider.id); + const isRequired = provider.required !== false; + + return ( + + ); + }; + + return ( + + + Connect Your Accounts + + {hasOnlyOptionalProviders ? ( + <> + The following optional accounts can be linked to enhance your experience. +
+ You can link them now or skip and manage them later in Settings → Linked Accounts. + + ) : ( + <> + Link the following accounts to enable permission syncing and access all features. +
+ You can manage your linked accounts later in Settings → Linked Accounts. + + )} +
+
+ +
+ {requiredProviders.map(renderProviderButton)} + {optionalProviders.map(renderProviderButton)} +
+ {hasOnlyOptionalProviders && ( + + )} +
+
+ ); +}; diff --git a/packages/web/src/ee/features/permissionSyncing/linkButton.tsx b/packages/web/src/ee/features/permissionSyncing/linkButton.tsx new file mode 100644 index 000000000..1b3788e43 --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/linkButton.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { Button } from "@/components/ui/button"; +import { Link2 } from "lucide-react"; +import { signIn } from "next-auth/react"; + +interface LinkButtonProps { + provider: string; + providerName: string; + callbackUrl: string; +} + +export const LinkButton = ({ provider, providerName, callbackUrl }: LinkButtonProps) => { + const handleLink = () => { + signIn(provider, { + redirectTo: callbackUrl + }); + }; + + return ( + + ); +}; diff --git a/packages/web/src/ee/features/permissionSyncing/linkedAccountsSettings.tsx b/packages/web/src/ee/features/permissionSyncing/linkedAccountsSettings.tsx new file mode 100644 index 000000000..d5b5ca86b --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/linkedAccountsSettings.tsx @@ -0,0 +1,159 @@ +import { withAuthV2 } from "@/withAuthV2"; +import { sew } from "@/actions"; +import { isServiceError, getAuthProviderInfo } from "@/lib/utils"; +import { loadConfig } from "@sourcebot/shared"; +import { env } from "@/env.mjs"; +import { Check, X, ShieldCheck } from "lucide-react"; +import { getUnlinkedIntegrationProviders } from "./actions"; +import { UnlinkButton } from "./unlinkButton"; +import { LinkButton } from "./linkButton"; +import { ServiceErrorException } from "@/lib/serviceError"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { ProviderIcon } from "./components/providerIcon"; +import { ProviderInfo } from "./components/providerInfo"; + +interface LinkedAccountsSettingsProps { + domain: string; +} + +export async function LinkedAccountsSettings({ domain }: LinkedAccountsSettingsProps) { + const config = await loadConfig(env.CONFIG_PATH); + const integrationProviders = (config.identityProviders ?? []) + .filter(provider => provider.purpose === "integration"); + + // Get user's linked accounts + const getLinkedAccounts = async () => sew(() => + withAuthV2(async ({ prisma, user }) => { + const accounts = await prisma.account.findMany({ + where: { + userId: user.id, + provider: { + in: integrationProviders.map(p => p.provider) + } + }, + select: { + provider: true, + providerAccountId: true, + } + }); + return accounts; + }) + ); + + const linkedAccountsResult = await getLinkedAccounts(); + if (isServiceError(linkedAccountsResult)) { + throw new ServiceErrorException(linkedAccountsResult); + } + + const linkedAccounts = linkedAccountsResult; + + const unlinkedProvidersResult = await getUnlinkedIntegrationProviders(); + if (isServiceError(unlinkedProvidersResult)) { + throw new ServiceErrorException(unlinkedProvidersResult); + } + + return ( +
+
+

Linked Accounts

+

+ Manage your linked integration accounts for permission syncing and code host access. +

+
+ + {/* Show linked accounts as separate cards */} + {integrationProviders.length === 0 ? ( + + +
+ +
+

No integration providers configured

+

+ Contact your administrator to configure integration providers for your organization. +

+
+
+ ) : ( +
+ {integrationProviders.map((provider) => { + const providerInfo = getAuthProviderInfo(provider.provider); + const linkedAccount = linkedAccounts.find( + account => account.provider === provider.provider + ); + const isLinked = !!linkedAccount; + const isRequired = 'required' in provider ? (provider.required as boolean) : true; + + return ( + + +
+
+
+ +
+
+ + + + + {isLinked ? ( +
+
+ + + Connected + +
+ {linkedAccount.providerAccountId && ( + <> + + + {linkedAccount.providerAccountId} + + + )} +
+ ) : ( +
+ + + Not connected + +
+ )} +
+
+
+
+ {isLinked ? ( + + ) : ( + + )} +
+
+
+
+ ); + })} +
+ )} +
+ ); +} diff --git a/packages/web/src/ee/features/permissionSyncing/unlinkButton.tsx b/packages/web/src/ee/features/permissionSyncing/unlinkButton.tsx new file mode 100644 index 000000000..5e61e71ae --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/unlinkButton.tsx @@ -0,0 +1,75 @@ +'use client'; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { Unlink, Loader2 } from "lucide-react"; +import { unlinkIntegrationProvider } from "./actions"; +import { isServiceError } from "@/lib/utils"; +import { useRouter } from "next/navigation"; +import { useToast } from "@/components/hooks/use-toast"; + +interface UnlinkButtonProps { + provider: string; + providerName: string; +} + +export const UnlinkButton = ({ provider, providerName }: UnlinkButtonProps) => { + const [isUnlinking, setIsUnlinking] = useState(false); + const router = useRouter(); + const { toast } = useToast(); + + const handleUnlink = async () => { + if (!confirm(`Are you sure you want to disconnect your ${providerName} account?`)) { + return; + } + + setIsUnlinking(true); + try { + const result = await unlinkIntegrationProvider(provider); + + if (isServiceError(result)) { + toast({ + description: `❌ Failed to disconnect account. ${result.message}`, + variant: "destructive", + }); + setIsUnlinking(false); + return; + } + + toast({ + description: `✅ ${providerName} account disconnected successfully.`, + }); + + // Refresh the page to show updated state + router.refresh(); + } catch (error) { + toast({ + description: `❌ Failed to disconnect account. ${error instanceof Error ? error.message : "Unknown error"}`, + variant: "destructive", + }); + setIsUnlinking(false); + } + }; + + return ( + + ); +}; diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 550920320..579f7ceb9 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -9,6 +9,7 @@ import { prisma } from "@/prisma"; import { OAuth2Client } from "google-auth-library"; import Credentials from "next-auth/providers/credentials"; import type { User as AuthJsUser } from "next-auth"; +import type { Provider } from "next-auth/providers"; import { onCreateUser } from "@/lib/authUtils"; import { createLogger } from "@sourcebot/logger"; import { hasEntitlement, loadConfig } from "@sourcebot/shared"; @@ -21,7 +22,7 @@ const logger = createLogger('web-sso'); export const getEEIdentityProviders = async (): Promise => { const providers: IdentityProvider[] = []; - const config = env.CONFIG_PATH ? await loadConfig(env.CONFIG_PATH) : undefined; + const config = await loadConfig(env.CONFIG_PATH); const identityProviders = config?.identityProviders ?? []; for (const identityProvider of identityProviders) { @@ -30,14 +31,14 @@ export const getEEIdentityProviders = async (): Promise => { const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose }); + providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? true }); } if (identityProvider.provider === "gitlab") { const providerConfig = identityProvider as GitLabIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose }); + providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? true }); } if (identityProvider.provider === "google") { const providerConfig = identityProvider as GoogleIdentityProviderConfig; @@ -57,49 +58,49 @@ export const getEEIdentityProviders = async (): Promise => { const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: "sso"}); + providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: "sso" }); } if (identityProvider.provider === "microsoft-entra-id") { const providerConfig = identityProvider as MicrosoftEntraIDIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: "sso"}); + providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: "sso" }); } if (identityProvider.provider === "gcp-iap") { const providerConfig = identityProvider as GCPIAPIdentityProviderConfig; const audience = await getTokenFromConfig(providerConfig.audience); - providers.push({ provider: createGCPIAPProvider(audience), purpose: "sso"}); + providers.push({ provider: createGCPIAPProvider(audience), purpose: "sso" }); } } // @deprecate if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { - providers.push(createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL)); + providers.push({ provider: createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL), purpose: "sso" }); } if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) { - providers.push(createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL)); + providers.push({ provider: createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL), purpose: "sso" }); } if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) { - providers.push(createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET)); + providers.push({ provider: createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET), purpose: "sso" }); } if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) { - providers.push(createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER)); + providers.push({ provider: createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER), purpose: "sso" }); } if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) { - providers.push(createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER)); + providers.push({ provider: createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER), purpose: "sso" }); } if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) { - providers.push(createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER)); + providers.push({ provider: createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER), purpose: "sso" }); } if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { - providers.push(createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE)); + providers.push({ provider: createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE), purpose: "sso" }); } return providers; diff --git a/packages/web/src/features/chat/actions.ts b/packages/web/src/features/chat/actions.ts index ad4e9f123..40d62cab2 100644 --- a/packages/web/src/features/chat/actions.ts +++ b/packages/web/src/features/chat/actions.ts @@ -24,8 +24,8 @@ import { getTokenFromConfig } from "@sourcebot/crypto"; import { ChatVisibility, OrgRole, Prisma } from "@sourcebot/db"; import { LanguageModel } from "@sourcebot/schemas/v3/languageModel.type"; import { Token } from "@sourcebot/schemas/v3/shared.type"; -import { loadConfig } from "@sourcebot/shared"; import { generateText, JSONValue, extractReasoningMiddleware, wrapLanguageModel } from "ai"; +import { loadConfig } from "@sourcebot/shared"; import fs from 'fs'; import { StatusCodes } from "http-status-codes"; import path from 'path'; @@ -355,22 +355,13 @@ export const getConfiguredLanguageModelsInfo = async (): Promise => { - if (!env.CONFIG_PATH) { - return []; - } - - try { - const config = await loadConfig(env.CONFIG_PATH); - return config.models ?? []; - } catch (error) { - console.error(`Failed to load config file ${env.CONFIG_PATH}: ${error}`); - return []; - } + const config = await loadConfig(env.CONFIG_PATH); + return config.models ?? []; } diff --git a/packages/web/src/initialize.ts b/packages/web/src/initialize.ts index 63eb6a473..b08685b2b 100644 --- a/packages/web/src/initialize.ts +++ b/packages/web/src/initialize.ts @@ -65,30 +65,28 @@ const initSingleTenancy = async () => { } // Sync anonymous access config from the config file - if (env.CONFIG_PATH) { - const config = await loadConfig(env.CONFIG_PATH); - const forceEnableAnonymousAccess = config.settings?.enablePublicAccess ?? env.FORCE_ENABLE_ANONYMOUS_ACCESS === 'true'; + const config = await loadConfig(env.CONFIG_PATH); + const forceEnableAnonymousAccess = config.settings?.enablePublicAccess ?? env.FORCE_ENABLE_ANONYMOUS_ACCESS === 'true'; - if (forceEnableAnonymousAccess) { - if (!hasAnonymousAccessEntitlement) { - logger.warn(`FORCE_ENABLE_ANONYMOUS_ACCESS env var is set to true but anonymous access entitlement is not available. Setting will be ignored.`); - } else { - const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN); - if (org) { - const currentMetadata = getOrgMetadata(org); - const mergedMetadata = { - ...(currentMetadata ?? {}), - anonymousAccessEnabled: true, - }; + if (forceEnableAnonymousAccess) { + if (!hasAnonymousAccessEntitlement) { + logger.warn(`FORCE_ENABLE_ANONYMOUS_ACCESS env var is set to true but anonymous access entitlement is not available. Setting will be ignored.`); + } else { + const org = await getOrgFromDomain(SINGLE_TENANT_ORG_DOMAIN); + if (org) { + const currentMetadata = getOrgMetadata(org); + const mergedMetadata = { + ...(currentMetadata ?? {}), + anonymousAccessEnabled: true, + }; - await prisma.org.update({ - where: { id: org.id }, - data: { - metadata: mergedMetadata, - }, - }); - logger.info(`Anonymous access enabled via FORCE_ENABLE_ANONYMOUS_ACCESS environment variable`); - } + await prisma.org.update({ + where: { id: org.id }, + data: { + metadata: mergedMetadata, + }, + }); + logger.info(`Anonymous access enabled via FORCE_ENABLE_ANONYMOUS_ACCESS environment variable`); } } } diff --git a/packages/web/src/lib/constants.ts b/packages/web/src/lib/constants.ts index 3cd6e2588..21bb97d54 100644 --- a/packages/web/src/lib/constants.ts +++ b/packages/web/src/lib/constants.ts @@ -24,6 +24,7 @@ export const TEAM_FEATURES = [ export const MOBILE_UNSUPPORTED_SPLASH_SCREEN_DISMISSED_COOKIE_NAME = 'sb.mobile-unsupported-splash-screen-dismissed'; export const AGENTIC_SEARCH_TUTORIAL_DISMISSED_COOKIE_NAME = 'sb.agentic-search-tutorial-dismissed'; +export const OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME = 'sb.optional-providers-link-skipped'; // NOTE: changing SOURCEBOT_GUEST_USER_ID may break backwards compatibility since this value is used // to detect old guest users in the DB. If you change this value ensure it doesn't break upgrade flows diff --git a/packages/web/src/lib/authProviders.ts b/packages/web/src/lib/identityProviders.ts similarity index 96% rename from packages/web/src/lib/authProviders.ts rename to packages/web/src/lib/identityProviders.ts index efcb54ffe..792e3fec3 100644 --- a/packages/web/src/lib/authProviders.ts +++ b/packages/web/src/lib/identityProviders.ts @@ -4,6 +4,7 @@ export interface IdentityProviderMetadata { id: string; name: string; purpose: "sso" | "integration"; + required: boolean; } export const getIdentityProviderMetadata = (): IdentityProviderMetadata[] => { diff --git a/schemas/v3/identityProvider.json b/schemas/v3/identityProvider.json index 76e6c6ae6..6216d2707 100644 --- a/schemas/v3/identityProvider.json +++ b/schemas/v3/identityProvider.json @@ -19,6 +19,10 @@ }, "baseUrl": { "$ref": "./shared.json#/definitions/Token" + }, + "required": { + "type": "boolean", + "default": true } }, "required": ["provider", "purpose", "clientId", "clientSecret"] @@ -40,6 +44,10 @@ }, "baseUrl": { "$ref": "./shared.json#/definitions/Token" + }, + "required": { + "type": "boolean", + "default": true } }, "required": ["provider", "purpose", "clientId", "clientSecret", "baseUrl"] From 0ada9bbce324b2ba2da108971363798817b9232d Mon Sep 17 00:00:00 2001 From: msukkari Date: Sun, 2 Nov 2025 16:20:25 -0800 Subject: [PATCH 08/16] fix merge conflict --- .../schemas/v3/identityProvider.schema.mdx | 540 ++++++++++++++++-- packages/backend/src/repoCompileUtils.ts | 7 - 2 files changed, 504 insertions(+), 43 deletions(-) diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index 5105f3f15..f96ad1350 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -23,13 +23,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -40,13 +53,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -57,13 +83,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -98,13 +137,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -115,13 +167,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -132,13 +197,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -168,13 +246,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -185,13 +276,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -215,13 +319,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -232,13 +349,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -249,13 +379,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -280,13 +423,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -297,13 +453,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -314,13 +483,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -345,13 +527,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -362,13 +557,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -379,13 +587,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -410,13 +631,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -447,13 +681,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -464,13 +711,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -481,13 +741,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -522,13 +795,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -539,13 +825,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -556,13 +855,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -592,13 +904,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -609,13 +934,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -639,13 +977,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -656,13 +1007,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -673,13 +1037,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -704,13 +1081,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -721,13 +1111,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -738,13 +1141,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -769,13 +1185,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -786,13 +1215,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] }, @@ -803,13 +1245,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } @@ -834,13 +1289,26 @@ "properties": { "env": { "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." + "description": "The name of the environment variable that contains the token." } }, "required": [ "env" ], "additionalProperties": false + }, + { + "type": "object", + "properties": { + "googleCloudSecret": { + "type": "string", + "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" + } + }, + "required": [ + "googleCloudSecret" + ], + "additionalProperties": false } ] } diff --git a/packages/backend/src/repoCompileUtils.ts b/packages/backend/src/repoCompileUtils.ts index 9ae3403c1..04a8b3b5d 100644 --- a/packages/backend/src/repoCompileUtils.ts +++ b/packages/backend/src/repoCompileUtils.ts @@ -20,10 +20,7 @@ import assert from 'assert'; import GitUrlParse from 'git-url-parse'; import { RepoMetadata } from '@sourcebot/shared'; import { SINGLE_TENANT_ORG_ID } from './constants.js'; -<<<<<<< HEAD -======= import pLimit from 'p-limit'; ->>>>>>> main export type RepoData = WithRequired; @@ -481,11 +478,7 @@ export const compileGenericGitHostConfig_file = async ( const repos: RepoData[] = []; const warnings: string[] = []; -<<<<<<< HEAD - await Promise.all(repoPaths.map(async (repoPath) => { -======= await Promise.all(repoPaths.map((repoPath) => gitOperationLimit(async () => { ->>>>>>> main const isGitRepo = await isPathAValidGitRepoRoot({ path: repoPath, }); From 9676088cb0e16b4a5beb42823bcea0336f8b7fa4 Mon Sep 17 00:00:00 2001 From: msukkari Date: Mon, 3 Nov 2025 14:41:00 -0800 Subject: [PATCH 09/16] fix build --- packages/web/src/lib/identityProviders.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/web/src/lib/identityProviders.ts b/packages/web/src/lib/identityProviders.ts index 792e3fec3..dace28aad 100644 --- a/packages/web/src/lib/identityProviders.ts +++ b/packages/web/src/lib/identityProviders.ts @@ -12,9 +12,19 @@ export const getIdentityProviderMetadata = (): IdentityProviderMetadata[] => { return providers.map((provider) => { if (typeof provider.provider === "function") { const providerInfo = provider.provider(); - return { id: providerInfo.id, name: providerInfo.name, purpose: provider.purpose }; + return { + id: providerInfo.id, + name: providerInfo.name, + purpose: provider.purpose, + required: provider.required ?? true, + }; } else { - return { id: provider.provider.id, name: provider.provider.name, purpose: provider.purpose }; + return { + id: provider.provider.id, + name: provider.provider.name, + purpose: provider.purpose, + required: provider.required ?? true, + }; } }); }; \ No newline at end of file From 6cc9d0b2677f7fd871e5d3ee9acf6ceeb3b7e4de Mon Sep 17 00:00:00 2001 From: msukkari Date: Mon, 3 Nov 2025 17:21:04 -0800 Subject: [PATCH 10/16] refactor ui --- .../schemas/v3/identityProvider.schema.mdx | 6 +- docs/snippets/schemas/v3/index.schema.mdx | 6 +- .../schemas/src/v3/identityProvider.schema.ts | 6 +- .../schemas/src/v3/identityProvider.type.ts | 2 +- packages/schemas/src/v3/index.schema.ts | 6 +- packages/schemas/src/v3/index.type.ts | 2 +- packages/web/src/app/[domain]/layout.tsx | 27 ++- .../permission-syncing/linkButton.tsx | 30 ---- .../settings/permission-syncing/page.tsx | 12 +- .../ee/features/permissionSyncing/actions.ts | 101 +++++------ .../components/providerInfo.tsx | 1 - .../integrationProviderCard.tsx | 90 ++++++++++ .../permissionSyncing/linkAccounts.tsx | 92 +++------- .../features/permissionSyncing/linkButton.tsx | 3 +- .../linkedAccountsSettings.tsx | 164 ++++-------------- .../ee/features/permissionSyncing/types.ts | 6 + schemas/v3/identityProvider.json | 2 +- 17 files changed, 214 insertions(+), 342 deletions(-) delete mode 100644 packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/integrationProviderCard.tsx create mode 100644 packages/web/src/ee/features/permissionSyncing/types.ts diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index f96ad1350..c0cbab9ed 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -229,8 +229,7 @@ "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, "GoogleIdentityProviderConfig": { @@ -887,8 +886,7 @@ "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, { diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 06f02825a..0bc6281b0 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -4633,8 +4633,7 @@ "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, "GoogleIdentityProviderConfig": { @@ -5291,8 +5290,7 @@ "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, { diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts index 10cd44872..9a3b93731 100644 --- a/packages/schemas/src/v3/identityProvider.schema.ts +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -228,8 +228,7 @@ const schema = { "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, "GoogleIdentityProviderConfig": { @@ -886,8 +885,7 @@ const schema = { "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, { diff --git a/packages/schemas/src/v3/identityProvider.type.ts b/packages/schemas/src/v3/identityProvider.type.ts index 2a180b4f7..541f0ca76 100644 --- a/packages/schemas/src/v3/identityProvider.type.ts +++ b/packages/schemas/src/v3/identityProvider.type.ts @@ -83,7 +83,7 @@ export interface GitLabIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl: + baseUrl?: | { /** * The name of the environment variable that contains the token. diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index 1d58a4a65..4da1b5e9a 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -4632,8 +4632,7 @@ const schema = { "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, "GoogleIdentityProviderConfig": { @@ -5290,8 +5289,7 @@ const schema = { "provider", "purpose", "clientId", - "clientSecret", - "baseUrl" + "clientSecret" ] }, { diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index 9c9365cb8..aef3e6acb 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -1190,7 +1190,7 @@ export interface GitLabIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl: + baseUrl?: | { /** * The name of the environment variable that contains the token. diff --git a/packages/web/src/app/[domain]/layout.tsx b/packages/web/src/app/[domain]/layout.tsx index 05f910068..bfc530c13 100644 --- a/packages/web/src/app/[domain]/layout.tsx +++ b/packages/web/src/app/[domain]/layout.tsx @@ -23,7 +23,7 @@ import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; import { GitHubStarToast } from "./components/githubStarToast"; import { UpgradeToast } from "./components/upgradeToast"; -import { getUnlinkedIntegrationProviders, userNeedsToLinkIdentityProvider } from "@/ee/features/permissionSyncing/actions"; +import { getIntegrationProviderStates } from "@/ee/features/permissionSyncing/actions"; import { LinkAccounts } from "@/ee/features/permissionSyncing/linkAccounts"; interface LayoutProps { @@ -126,16 +126,16 @@ export default async function Layout(props: LayoutProps) { } if (hasEntitlement("permission-syncing")) { - const unlinkedAccounts = await getUnlinkedIntegrationProviders(); - if (isServiceError(unlinkedAccounts)) { + const integrationProviderStates = await getIntegrationProviderStates(); + if (isServiceError(integrationProviderStates)) { return (

An error occurred

- {typeof unlinkedAccounts.message === 'string' - ? unlinkedAccounts.message + {typeof integrationProviderStates.message === 'string' + ? integrationProviderStates.message : "A server error occurred while checking your account status. Please try again or contact support."}

@@ -143,25 +143,18 @@ export default async function Layout(props: LayoutProps) { ) } - if (unlinkedAccounts.length > 0) { - // Separate required and optional providers - const requiredProviders = unlinkedAccounts.filter(p => p.required !== false); - const hasRequiredProviders = requiredProviders.length > 0; - - // Check if user has skipped optional providers + const hasUnlinkedProviders = integrationProviderStates.some(state => state.isLinked === false); + if (hasUnlinkedProviders) { const cookieStore = await cookies(); const hasSkippedOptional = cookieStore.has(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); - // Show LinkAccounts if: - // 1. There are required providers, OR - // 2. There are only optional providers AND user hasn't skipped yet - const shouldShowLinkAccounts = hasRequiredProviders || !hasSkippedOptional; - + const hasUnlinkedRequiredProviders = integrationProviderStates.some(state => state.required && !state.isLinked) + const shouldShowLinkAccounts = hasUnlinkedRequiredProviders || !hasSkippedOptional; if (shouldShowLinkAccounts) { return (
- +
) } diff --git a/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx b/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx deleted file mode 100644 index 49750a3a7..000000000 --- a/packages/web/src/app/[domain]/settings/permission-syncing/linkButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -'use client'; - -import { Button } from "@/components/ui/button"; -import { Link2 } from "lucide-react"; -import { signIn } from "next-auth/react"; - -interface LinkButtonProps { - provider: string; - providerName: string; - callbackUrl: string; -} - -export const LinkButton = ({ provider, providerName, callbackUrl }: LinkButtonProps) => { - const handleLink = () => { - signIn(provider, { - redirectTo: callbackUrl - }); - }; - - return ( - - ); -}; diff --git a/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx index a3cc04f20..54f6c6637 100644 --- a/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx +++ b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx @@ -2,19 +2,11 @@ import { hasEntitlement } from "@sourcebot/shared"; import { notFound } from "@/lib/serviceError"; import { LinkedAccountsSettings } from "@/ee/features/permissionSyncing/linkedAccountsSettings"; -interface PermissionSyncingPageProps { - params: Promise<{ - domain: string; - }> -} - -export default async function PermissionSyncingPage(props: PermissionSyncingPageProps) { - const params = await props.params; - +export default async function PermissionSyncingPage() { const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing"); if (!hasPermissionSyncingEntitlement) { notFound(); } - return ; + return ; } diff --git a/packages/web/src/ee/features/permissionSyncing/actions.ts b/packages/web/src/ee/features/permissionSyncing/actions.ts index 29762de12..ded042711 100644 --- a/packages/web/src/ee/features/permissionSyncing/actions.ts +++ b/packages/web/src/ee/features/permissionSyncing/actions.ts @@ -8,89 +8,60 @@ import { env } from "@/env.mjs"; import { OrgRole } from "@sourcebot/db"; import { cookies } from "next/headers"; import { OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME } from "@/lib/constants"; +import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types"; const logger = createLogger('web-ee-permission-syncing-actions'); -export const userNeedsToLinkIdentityProvider = async () => sew(() => +export const getIntegrationProviderStates = async () => sew(() => withAuthV2(async ({ prisma, role, user }) => withMinimumOrgRole(role, OrgRole.MEMBER, async () => { const config = await loadConfig(env.CONFIG_PATH); - const identityProviders = config.identityProviders ?? []; - - for (const identityProvider of identityProviders) { - if (identityProvider.purpose === "integration") { - // Only check required providers (default to true if not specified) - const isRequired = 'required' in identityProvider ? identityProvider.required : true; - - if (!isRequired) { - continue; - } - - const linkedAccount = await prisma.account.findFirst({ - where: { - provider: identityProvider.provider, - userId: user.id, - }, - }); - - if (!linkedAccount) { - logger.info(`Required integration identity provider ${identityProvider.provider} account info not found for user ${user.id}`); - return true; + const integrationProviderConfigs = config.identityProviders ?? []; + const linkedAccounts = await prisma.account.findMany({ + where: { + userId: user.id, + provider: { + in: integrationProviderConfigs.map(p => p.provider) } + }, + select: { + provider: true, + providerAccountId: true } - } - - return false; - }) - ) -); - -export const getUnlinkedIntegrationProviders = async () => sew(() => - withAuthV2(async ({ prisma, role, user }) => - withMinimumOrgRole(role, OrgRole.MEMBER, async () => { - const config = await loadConfig(env.CONFIG_PATH); - const identityProviders = config.identityProviders ?? []; - const unlinkedProviders = []; - - for (const identityProvider of identityProviders) { - if (identityProvider.purpose === "integration") { - const linkedAccount = await prisma.account.findFirst({ - where: { - provider: identityProvider.provider, - userId: user.id, - }, - }); + }); - if (!linkedAccount) { - const isRequired = 'required' in identityProvider ? identityProvider.required as boolean : true; - logger.info(`Integration identity provider ${identityProvider.provider} not linked for user ${user.id}`); - unlinkedProviders.push({ - id: identityProvider.provider, - name: identityProvider.provider, - purpose: "integration" as const, - required: isRequired, - }); - } + const integrationProviderState: IntegrationIdentityProviderState[] = []; + for (const integrationProviderConfig of integrationProviderConfigs) { + if (integrationProviderConfig.purpose === "integration") { + const linkedAccount = linkedAccounts.find( + account => account.provider === integrationProviderConfig.provider + ); + + const isLinked = !!linkedAccount; + const isRequired = integrationProviderConfig.required ?? true; + integrationProviderState.push({ + id: integrationProviderConfig.provider, + required: isRequired, + isLinked, + linkedAccountId: linkedAccount?.providerAccountId + } as IntegrationIdentityProviderState); } } - return unlinkedProviders; + return integrationProviderState; }) ) ); + export const unlinkIntegrationProvider = async (provider: string) => sew(() => withAuthV2(async ({ prisma, role, user }) => withMinimumOrgRole(role, OrgRole.MEMBER, async () => { const config = await loadConfig(env.CONFIG_PATH); const identityProviders = config.identityProviders ?? []; - // Verify this is an integration provider - const isIntegrationProvider = identityProviders.some( - idp => idp.provider === provider && idp.purpose === "integration" - ); - - if (!isIntegrationProvider) { + const providerConfig = identityProviders.find(idp => idp.provider === provider) + if (!providerConfig || !('purpose' in providerConfig) || providerConfig.purpose !== "integration") { throw new Error("Provider is not an integration provider"); } @@ -104,6 +75,14 @@ export const unlinkIntegrationProvider = async (provider: string) => sew(() => logger.info(`Unlinked integration provider ${provider} for user ${user.id}. Deleted ${result.count} account(s).`); + // If we're unlinking a required identity provider then we want to wipe the optional skip cookie if it exists so that we give the + // user the option of linking optional providers in the same link accounts screen + const isRequired = providerConfig.required ?? true; + if (isRequired) { + const cookieStore = await cookies(); + cookieStore.delete(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); + } + return { success: true, count: result.count }; }) ) diff --git a/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx b/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx index 143075069..3d1d83393 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/providerInfo.tsx @@ -1,5 +1,4 @@ import { getAuthProviderInfo } from "@/lib/utils"; -import { ProviderIcon } from "./providerIcon"; import { ProviderBadge } from "./providerBadge"; interface ProviderInfoProps { diff --git a/packages/web/src/ee/features/permissionSyncing/integrationProviderCard.tsx b/packages/web/src/ee/features/permissionSyncing/integrationProviderCard.tsx new file mode 100644 index 000000000..43e948b18 --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/integrationProviderCard.tsx @@ -0,0 +1,90 @@ +import { getAuthProviderInfo } from "@/lib/utils"; +import { Check, X } from "lucide-react"; +import { Card, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { ProviderIcon } from "./components/providerIcon"; +import { ProviderInfo } from "./components/providerInfo"; +import { UnlinkButton } from "./unlinkButton"; +import { LinkButton } from "./linkButton"; +import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types" +import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; + +interface IntegrationProviderCardProps { + integrationProviderState: IntegrationIdentityProviderState; + callbackUrl?: string; +} + +export function IntegrationProviderCard({ + integrationProviderState, + callbackUrl, +}: IntegrationProviderCardProps) { + const providerInfo = getAuthProviderInfo(integrationProviderState.id); + const defaultCallbackUrl = `/${SINGLE_TENANT_ORG_DOMAIN}/settings/permission-syncing`; + + return ( + + +
+
+
+ +
+
+ + + + + {integrationProviderState.isLinked? ( +
+
+ + + Connected + +
+ {integrationProviderState.linkedAccountId && ( + <> + + + {integrationProviderState.linkedAccountId} + + + )} +
+ ) : ( +
+ + + Not connected + +
+ )} +
+
+
+
+ {integrationProviderState.isLinked? ( + + ) : ( + + )} +
+
+
+
+ ); +} + diff --git a/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx b/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx index cad1d435e..52859269c 100644 --- a/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx +++ b/packages/web/src/ee/features/permissionSyncing/linkAccounts.tsx @@ -1,108 +1,58 @@ 'use client'; -import { signIn } from "next-auth/react"; -import { getAuthProviderInfo } from "@/lib/utils"; -import type { IdentityProviderMetadata } from "@/lib/identityProviders"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { ArrowRight } from "lucide-react"; -import { skipOptionalProvidersLink } from "./actions"; +import { skipOptionalProvidersLink } from "@/ee/features/permissionSyncing/actions"; import { useRouter } from "next/navigation"; import { useState } from "react"; -import { ProviderIcon } from "./components/providerIcon"; -import { ProviderInfo } from "./components/providerInfo"; +import { IntegrationProviderCard } from "./integrationProviderCard"; +import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types"; interface LinkAccountsProps { - unlinkedAccounts: IdentityProviderMetadata[]; + integrationProviderStates: IntegrationIdentityProviderState[] callbackUrl?: string; } -export const LinkAccounts = ({ unlinkedAccounts, callbackUrl }: LinkAccountsProps) => { +export const LinkAccounts = ({ integrationProviderStates, callbackUrl }: LinkAccountsProps) => { const router = useRouter(); const [isSkipping, setIsSkipping] = useState(false); - const handleSignIn = (providerId: string) => { - signIn(providerId, { - redirectTo: callbackUrl ?? "/" - }); - }; - const handleSkip = async () => { setIsSkipping(true); try { await skipOptionalProvidersLink(); - router.refresh(); } catch (error) { console.error("Failed to skip optional providers:", error); + } finally { setIsSkipping(false); + router.refresh() } }; - // Separate required and optional providers - const requiredProviders = unlinkedAccounts.filter(p => p.required !== false); - const optionalProviders = unlinkedAccounts.filter(p => p.required === false); - const hasOnlyOptionalProviders = requiredProviders.length === 0 && optionalProviders.length > 0; - - const renderProviderButton = (provider: IdentityProviderMetadata) => { - const providerInfo = getAuthProviderInfo(provider.id); - const isRequired = provider.required !== false; - - return ( - - ); - }; - + const canSkip = !integrationProviderStates.some(state => state.required && !state.isLinked); return ( Connect Your Accounts - {hasOnlyOptionalProviders ? ( - <> - The following optional accounts can be linked to enhance your experience. -
- You can link them now or skip and manage them later in Settings → Linked Accounts. - - ) : ( - <> - Link the following accounts to enable permission syncing and access all features. -
- You can manage your linked accounts later in Settings → Linked Accounts. - - )} + Link the following accounts to enable permission syncing and access all features. +
+ You can manage your linked accounts later in Settings → Linked Accounts.
- {requiredProviders.map(renderProviderButton)} - {optionalProviders.map(renderProviderButton)} + {integrationProviderStates + .sort((a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0)) + .map(state => ( + + ))}
- {hasOnlyOptionalProviders && ( + {canSkip && (
diff --git a/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts b/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts new file mode 100644 index 000000000..dcb94d2ae --- /dev/null +++ b/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts @@ -0,0 +1,158 @@ +import { loadConfig } from "@sourcebot/shared"; +import { env } from "@/env.mjs"; +import { createLogger } from "@sourcebot/logger"; +import { getTokenFromConfig } from '@sourcebot/crypto'; +import { GitHubIdentityProviderConfig, GitLabIdentityProviderConfig } from "@sourcebot/schemas/v3/index.type"; + +const logger = createLogger('web-ee-token-refresh'); + +export type IntegrationToken = { + accessToken: string; + refreshToken: string; + expiresAt: number; + error?: string; +}; + +export type IntegrationTokensMap = Record; + +export async function refreshIntegrationTokens( + currentTokens: IntegrationTokensMap | undefined, + userId: string +): Promise { + if (!currentTokens) { + return {}; + } + + const now = Math.floor(Date.now() / 1000); + const bufferTimeS = 5 * 60; // 5 minutes + + const updatedTokens: IntegrationTokensMap = { ...currentTokens }; + + // Refresh tokens for each integration provider + await Promise.all( + Object.entries(currentTokens).map(async ([provider, tokenData]) => { + if (provider !== 'github' && provider !== 'gitlab') { + return; + } + + if (tokenData.expiresAt && now >= (tokenData.expiresAt - bufferTimeS)) { + try { + logger.info(`Refreshing token for provider: ${provider}`); + const refreshedTokens = await refreshOAuthToken( + provider, + tokenData.refreshToken, + userId + ); + + if (refreshedTokens) { + updatedTokens[provider] = { + accessToken: refreshedTokens.accessToken, + refreshToken: refreshedTokens.refreshToken ?? tokenData.refreshToken, + expiresAt: refreshedTokens.expiresAt, + }; + logger.info(`Successfully refreshed token for provider: ${provider}`); + } else { + logger.error(`Failed to refresh token for provider: ${provider}`); + updatedTokens[provider] = { + ...tokenData, + error: 'RefreshTokenError', + }; + } + } catch (error) { + logger.error(`Error refreshing token for provider ${provider}:`, error); + updatedTokens[provider] = { + ...tokenData, + error: 'RefreshTokenError', + }; + } + } + }) + ); + + return updatedTokens; +} + +export async function refreshOAuthToken( + provider: string, + refreshToken: string, + userId: string +): Promise<{ accessToken: string; refreshToken: string | null; expiresAt: number } | null> { + try { + const config = await loadConfig(env.CONFIG_PATH); + const identityProviders = config?.identityProviders ?? []; + + const providerConfig = identityProviders.find(idp => idp.provider === provider); + if (!providerConfig) { + logger.error(`Provider config not found or invalid for: ${provider}`); + return null; + } + + // Get client credentials from config + const integrationProviderConfig = providerConfig as GitHubIdentityProviderConfig | GitLabIdentityProviderConfig + const clientId = await getTokenFromConfig(integrationProviderConfig.clientId); + const clientSecret = await getTokenFromConfig(integrationProviderConfig.clientSecret); + const baseUrl = 'baseUrl' in integrationProviderConfig && integrationProviderConfig.baseUrl + ? await getTokenFromConfig(integrationProviderConfig.baseUrl) + : undefined; + + let url: string; + if (baseUrl) { + url = provider === 'github' + ? `${baseUrl}/login/oauth/access_token` + : `${baseUrl}/oauth/token`; + } else if (provider === 'github') { + url = 'https://github.com/login/oauth/access_token'; + } else if (provider === 'gitlab') { + url = 'https://gitlab.com/oauth/token'; + } else { + logger.error(`Unsupported provider for token refresh: ${provider}`); + return null; + } + + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + }, + body: new URLSearchParams({ + client_id: clientId, + client_secret: clientSecret, + grant_type: 'refresh_token', + refresh_token: refreshToken, + }), + }); + + if (!response.ok) { + const errorText = await response.text(); + logger.error(`Failed to refresh ${provider} token: ${response.status} ${errorText}`); + return null; + } + + const data = await response.json(); + + const result = { + accessToken: data.access_token, + refreshToken: data.refresh_token ?? null, + expiresAt: data.expires_in ? Math.floor(Date.now() / 1000) + data.expires_in : 0, + }; + + const { prisma } = await import('@/prisma'); + await prisma.account.updateMany({ + where: { + userId: userId, + provider: provider, + }, + data: { + access_token: result.accessToken, + refresh_token: result.refreshToken, + expires_at: result.expiresAt, + }, + }); + + return result; + } catch (error) { + logger.error(`Error refreshing ${provider} token:`, error); + return null; + } +} diff --git a/packages/web/src/ee/features/permissionSyncing/types.ts b/packages/web/src/ee/features/permissionSyncing/types.ts index 01cac3ade..3bdb87c79 100644 --- a/packages/web/src/ee/features/permissionSyncing/types.ts +++ b/packages/web/src/ee/features/permissionSyncing/types.ts @@ -3,4 +3,5 @@ export type IntegrationIdentityProviderState = { required: boolean; isLinked: boolean; linkedAccountId?: string; + error?: string; }; \ No newline at end of file From f781447a0bc1d2a1c848372ec7e2dac300711d3f Mon Sep 17 00:00:00 2001 From: msukkari Date: Mon, 3 Nov 2025 20:59:21 -0800 Subject: [PATCH 13/16] wip started idp docs --- docs/docs.json | 1 + docs/docs/configuration/idp.mdx | 125 ++++++++++++++++++++++++++++++++ docs/docs/license-key.mdx | 5 +- 3 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 docs/docs/configuration/idp.mdx diff --git a/docs/docs.json b/docs/docs.json index 3a2cb43f6..441f4139a 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -79,6 +79,7 @@ ] }, "docs/configuration/language-model-providers", + "docs/configuration/idp", { "group": "Authentication", "pages": [ diff --git a/docs/docs/configuration/idp.mdx b/docs/docs/configuration/idp.mdx new file mode 100644 index 000000000..f8edb8110 --- /dev/null +++ b/docs/docs/configuration/idp.mdx @@ -0,0 +1,125 @@ +--- +title: External Identity Providers +sidebarTitle: External identity providers +--- + +import LicenseKeyRequired from '/snippets/license-key-required.mdx' + + + +You can connect Sourcebot to various **external identity providers** to associate a Sourcebot user with one or more external service accounts (ex. Google, GitHub, etc). + +External identity providers can be used for [authentication](/docs/configuration/auth) and/or [permission syncing](/docs/features/permission-syncing). They're defined in the +[config file](/docs/configuration/config-file) in the top-level `identityProviders` object: + +```json wrap icon="code" Example config with both google and github identity providers defined +{ + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "github", + "purpose": "integration", + "required": true, +/* +Secrets are provided through environment variables. Set the secret into +an env var and provide the name here to tell Sourcebot where to get +the value +*/ + "clientId": { + "env": "GITHUB_IDENTITY_PROVIDER_CLIENT_ID" + }, + "clientSecret": { + "env": "GITHUB_IDENTITY_PROVIDER_CLIENT_SECRET" + } + }, + { + "provider": "google", + "clientId": { + "env": "GOOGLE_IDENTITY_PROVIDER_CLIENT_ID" + }, + "clientSecret": { + "env": "GOOGLE_IDENTITY_PROVIDER_CLIENT_SECRET" + } + } + ] +} +``` + +# Supported External Identity Providers + +Sourcebot uses [Auth.js](https://authjs.dev/) to connect to external identity providers. If there's a provider supported by Auth.js that you don't see below, please submit a +[feature request](https://github.com/sourcebot-dev/sourcebot/issues) to have it added. + +### GitHub + +[Auth.js GitHub Provider Docs](https://authjs.dev/getting-started/providers/github) + +A GitHub connection can be used for either [authentication](/docs/configuration/auth) or [permission syncing](/docs/features/permission-syncing). This is controlled using the `purpose` field +in the GitHub identity provider config. + + + + + To begin, you must register an Oauth client in GitHub to faciliate the identity provider connection. You can do this by creating a **GitHub App** or a **GitHub OAuth App**. Either + one works, but the **GitHub App** is the [modern way](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps). + + + The result of registering an OAuth client is a `CLIENT_ID` and `CLIENT_SECRET` which you'll provide to Sourcebot. + + + You don't need to install the app to use it as an external identity provider + Follow [this guide](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app) to register a new GitHub App. + + When asked to provide a callback url, provide `/api/auth/callback/github` (ex. https://sourcebot.coolcorp.com/api/auth/callback/github) + + Set the following fine-grained permissions in the GitHub App: + - `“Email addresses” account permissions (read)` + + + Follow [this guide](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) by GitHub to create an OAuth App. + + When asked to provide a callback url, provide `/api/auth/callback/github` (ex. https://sourcebot.coolcorp.com/api/auth/callback/github) + + + + + To provide Sourcebot the client id and secret for your OAuth client you must set them as environment variables. These can be named whatever you like + (ex. `GITHUB_IDENTITY_PROVIDER_CLIENT_ID` and `GITHUB_IDENTITY_PROVIDER_CLIENT_SECRET`) + + + Finally, pass the client id and secret to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "github", + // "sso" for auth + perm sync, "integration" for only perm sync + "purpose": "integration", + // if purpose == "integration" this controls if a user must connect to the IdP + "required": true, + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + } + } + ] + } + ``` + + + + +### GitLab + +### Google + +### Okta + +### Keycloak + +### Microsoft Entra ID + diff --git a/docs/docs/license-key.mdx b/docs/docs/license-key.mdx index 272eab625..4b13fcaf3 100644 --- a/docs/docs/license-key.mdx +++ b/docs/docs/license-key.mdx @@ -7,7 +7,7 @@ sidebarTitle: License key If you'd like a trial license, [reach out](https://www.sourcebot.dev/contact) and we'll send one over within 24 hours -All core Sourcebot features are available [FSL licensed](https://github.com/sourcebot-dev/sourcebot/blob/main/LICENSE.md#functional-source-license-version-11-alv2-future-license) without any limits. Some additional features require a license key. See the [pricing page](https://www.sourcebot.dev/pricing) for more details. +All core Sourcebot features are available under the [FSL license](https://github.com/sourcebot-dev/sourcebot/blob/main/LICENSE.md#functional-source-license-version-11-alv2-future-license). Some additional features require a license key. See the [pricing page](https://www.sourcebot.dev/pricing) for more details. ## Activating a license key @@ -25,7 +25,7 @@ docker run \ ## Feature availability --- -| Feature | OSS | Licensed | +| Feature | [FSL](https://github.com/sourcebot-dev/sourcebot/blob/main/LICENSE.md#functional-source-license-version-11-alv2-future-license) | [Enterprise](https://github.com/sourcebot-dev/sourcebot/blob/main/ee/LICENSE) | |:---------|:-----|:----------| | [Search](/docs/features/search/syntax-reference) | ✅ | ✅ | | [Full code host support](/docs/connections/overview) | ✅ | ✅ | @@ -34,6 +34,7 @@ docker run \ | [Login with credentials](/docs/configuration/auth/overview) | ✅ | ✅ | | [Login with email codes](/docs/configuration/auth/overview) | ✅ | ✅ | | [Login with SSO](/docs/configuration/auth/overview#enterprise-authentication-providers) | 🛑 | ✅ | +| [Permission syncing](/docs/features/permission-syncing) | 🛑 | ✅ | | [Code navigation](/docs/features/code-navigation) | 🛑 | ✅ | | [Search contexts](/docs/features/search/search-contexts) | 🛑 | ✅ | | [Audit logs](/docs/configuration/audit-logs) | 🛑 | ✅ | From 8e7bcc6459a3fbeb59cd2f1c0abaa4c574b1b7c2 Mon Sep 17 00:00:00 2001 From: msukkari Date: Mon, 3 Nov 2025 21:42:35 -0800 Subject: [PATCH 14/16] default required to false --- docs/snippets/schemas/v3/identityProvider.schema.mdx | 8 ++++---- docs/snippets/schemas/v3/index.schema.mdx | 8 ++++---- packages/schemas/src/v3/identityProvider.schema.ts | 8 ++++---- packages/schemas/src/v3/index.schema.ts | 8 ++++---- packages/web/src/ee/features/permissionSyncing/actions.ts | 4 ++-- packages/web/src/ee/features/sso/sso.ts | 4 ++-- packages/web/src/lib/identityProviders.ts | 4 ++-- schemas/v3/identityProvider.json | 4 ++-- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index c0cbab9ed..988cffcb9 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -108,7 +108,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -222,7 +222,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -765,7 +765,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -879,7 +879,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index 0bc6281b0..d43562fa8 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -4512,7 +4512,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -4626,7 +4626,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -5169,7 +5169,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -5283,7 +5283,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts index 9a3b93731..0dd3ddc4b 100644 --- a/packages/schemas/src/v3/identityProvider.schema.ts +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -107,7 +107,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -221,7 +221,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -764,7 +764,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -878,7 +878,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index 4da1b5e9a..a6bdd2f62 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -4511,7 +4511,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -4625,7 +4625,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -5168,7 +5168,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ @@ -5282,7 +5282,7 @@ const schema = { }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": [ diff --git a/packages/web/src/ee/features/permissionSyncing/actions.ts b/packages/web/src/ee/features/permissionSyncing/actions.ts index 59ac61c48..08779d692 100644 --- a/packages/web/src/ee/features/permissionSyncing/actions.ts +++ b/packages/web/src/ee/features/permissionSyncing/actions.ts @@ -43,7 +43,7 @@ export const getIntegrationProviderStates = async () => sew(() => ); const isLinked = !!linkedAccount; - const isRequired = integrationProviderConfig.required ?? true; + const isRequired = integrationProviderConfig.required ?? false; const providerError = providerErrors?.[integrationProviderConfig.provider]; integrationProviderState.push({ @@ -85,7 +85,7 @@ export const unlinkIntegrationProvider = async (provider: string) => sew(() => // If we're unlinking a required identity provider then we want to wipe the optional skip cookie if it exists so that we give the // user the option of linking optional providers in the same link accounts screen - const isRequired = providerConfig.required ?? true; + const isRequired = providerConfig.required ?? false; if (isRequired) { const cookieStore = await cookies(); cookieStore.delete(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 579f7ceb9..2e925f185 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -31,14 +31,14 @@ export const getEEIdentityProviders = async (): Promise => { const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? true }); + providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? false}); } if (identityProvider.provider === "gitlab") { const providerConfig = identityProvider as GitLabIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? true }); + providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? false}); } if (identityProvider.provider === "google") { const providerConfig = identityProvider as GoogleIdentityProviderConfig; diff --git a/packages/web/src/lib/identityProviders.ts b/packages/web/src/lib/identityProviders.ts index dace28aad..d35cd2db7 100644 --- a/packages/web/src/lib/identityProviders.ts +++ b/packages/web/src/lib/identityProviders.ts @@ -16,14 +16,14 @@ export const getIdentityProviderMetadata = (): IdentityProviderMetadata[] => { id: providerInfo.id, name: providerInfo.name, purpose: provider.purpose, - required: provider.required ?? true, + required: provider.required ?? false, }; } else { return { id: provider.provider.id, name: provider.provider.name, purpose: provider.purpose, - required: provider.required ?? true, + required: provider.required ?? false, }; } }); diff --git a/schemas/v3/identityProvider.json b/schemas/v3/identityProvider.json index 2c46f8c2f..3eeeef969 100644 --- a/schemas/v3/identityProvider.json +++ b/schemas/v3/identityProvider.json @@ -22,7 +22,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": ["provider", "purpose", "clientId", "clientSecret"] @@ -47,7 +47,7 @@ }, "required": { "type": "boolean", - "default": true + "default": false } }, "required": ["provider", "purpose", "clientId", "clientSecret"] From 822c57af3fe161a2f3e36f556c1245c370731589 Mon Sep 17 00:00:00 2001 From: msukkari Date: Tue, 4 Nov 2025 19:55:25 -0800 Subject: [PATCH 15/16] feedback --- CHANGELOG.md | 3 - docs/docs/configuration/auth/providers.mdx | 94 +- docs/docs/configuration/idp.mdx | 260 +++- docs/docs/features/permission-syncing.mdx | 12 +- .../schemas/v3/authProvider.schema.mdx | 1307 ----------------- .../schemas/v3/identityProvider.schema.mdx | 218 ++- docs/snippets/schemas/v3/index.schema.mdx | 218 ++- .../schemas/src/v3/authProvider.schema.ts | 1306 ---------------- packages/schemas/src/v3/authProvider.type.ts | 275 ---- .../schemas/src/v3/identityProvider.schema.ts | 218 ++- .../schemas/src/v3/identityProvider.type.ts | 54 +- packages/schemas/src/v3/index.schema.ts | 218 ++- packages/schemas/src/v3/index.type.ts | 54 +- packages/web/src/app/[domain]/layout.tsx | 16 +- .../settings/permission-syncing/page.tsx | 4 +- packages/web/src/auth.ts | 54 +- .../ee/features/permissionSyncing/actions.ts | 40 +- .../components/linkAccounts.tsx | 16 +- ...Card.tsx => linkedAccountProviderCard.tsx} | 32 +- .../components/linkedAccountsSettings.tsx | 20 +- .../components/providerIcon.tsx | 9 + .../components/unlinkButton.tsx | 4 +- .../permissionSyncing/tokenRefresh.ts | 179 +-- .../ee/features/permissionSyncing/types.ts | 2 +- packages/web/src/ee/features/sso/sso.ts | 86 +- packages/web/src/features/chat/actions.ts | 13 +- packages/web/src/lib/identityProviders.ts | 2 +- schemas/v3/identityProvider.json | 66 +- 28 files changed, 993 insertions(+), 3787 deletions(-) delete mode 100644 docs/snippets/schemas/v3/authProvider.schema.mdx delete mode 100644 packages/schemas/src/v3/authProvider.schema.ts delete mode 100644 packages/schemas/src/v3/authProvider.type.ts rename packages/web/src/ee/features/permissionSyncing/components/{integrationProviderCard.tsx => linkedAccountProviderCard.tsx} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3397dc81d..24e03b1ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,9 +21,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Removed - Removed built-in secret manager. [#592](https://github.com/sourcebot-dev/sourcebot/pull/592) -## Removed -- Removed built-in secret manager. [#592](https://github.com/sourcebot-dev/sourcebot/pull/592) - ## [4.8.1] - 2025-10-29 ### Fixed diff --git a/docs/docs/configuration/auth/providers.mdx b/docs/docs/configuration/auth/providers.mdx index c3d54363f..91328b373 100644 --- a/docs/docs/configuration/auth/providers.mdx +++ b/docs/docs/configuration/auth/providers.mdx @@ -26,95 +26,5 @@ See [transactional emails](/docs/configuration/transactional-emails) for more de # Enterprise Authentication Providers -The following authentication providers require an [enterprise license](/docs/license-key) to be enabled. - -### GitHub ---- - -[Auth.js GitHub Provider Docs](https://authjs.dev/getting-started/providers/github) - -Authentication using both a **GitHub OAuth App** and a **GitHub App** is supported. In both cases, you must provide Sourcebot the `CLIENT_ID` and `SECRET_ID` and configure the -callback URL correctly (more info in Auth.js docs). - -When using a **GitHub App** for auth, enable the following permissions: -- `“Email addresses” account permissions (read)` -- `"Metadata" repository permissions (read)` (only needed if enabling [permission syncing](/docs/features/permission-syncing)) - -**Required environment variables:** -- `AUTH_EE_GITHUB_CLIENT_ID` -- `AUTH_EE_GITHUB_CLIENT_SECRET` - -Optional environment variables: -- `AUTH_EE_GITHUB_BASE_URL` - Base URL for GitHub Enterprise (defaults to https://github.com) - -### GitLab ---- - -[Auth.js GitLab Provider Docs](https://authjs.dev/getting-started/providers/gitlab) - -Authentication using GitLab is supported via a [OAuth2.0 app](https://docs.gitlab.com/integration/oauth_provider/#create-an-instance-wide-application) installed on the GitLab instance. Follow the instructions in the [GitLab docs](https://docs.gitlab.com/integration/oauth_provider/) to create an app. The callback URL should be configurd to `/api/auth/callback/gitlab`, and the following scopes need to be set: - -| Scope | Required | Notes | -|------------|----------|----------------------------------------------------------------------------------------------------| -| read_user | Yes | Allows Sourcebot to read basic user information required for authentication. | -| read_api | Conditional | Required **only** when [permission syncing](/docs/features/permission-syncing) is enabled. Enables Sourcebot to list all repositories and projects for the authenticated user. | - - -**Required environment variables:** -- `AUTH_EE_GITLAB_CLIENT_ID` -- `AUTH_EE_GITLAB_CLIENT_SECRET` - -Optional environment variables: -- `AUTH_EE_GITLAB_BASE_URL` - Base URL for GitLab instance (defaults to https://gitlab.com) - -### Google ---- - -[Auth.js Google Provider Docs](https://authjs.dev/getting-started/providers/google) - -**Required environment variables:** -- `AUTH_EE_GOOGLE_CLIENT_ID` -- `AUTH_EE_GOOGLE_CLIENT_SECRET` - -### GCP IAP ---- - -If you're running Sourcebot in an environment that blocks egress, make sure you allow the [IAP IP ranges](https://www.gstatic.com/ipranges/goog.json) - -Custom provider built to enable automatic Sourcebot account registration/login when using GCP IAP. - -**Required environment variables** -- `AUTH_EE_GCP_IAP_ENABLED` -- `AUTH_EE_GCP_IAP_AUDIENCE` - - This can be found by selecting the ⋮ icon next to the IAP-enabled backend service and pressing `Get JWT audience code` - -### Okta ---- - -[Auth.js Okta Provider Docs](https://authjs.dev/getting-started/providers/okta) - -**Required environment variables:** -- `AUTH_EE_OKTA_CLIENT_ID` -- `AUTH_EE_OKTA_CLIENT_SECRET` -- `AUTH_EE_OKTA_ISSUER` - -### Keycloak ---- - -[Auth.js Keycloak Provider Docs](https://authjs.dev/getting-started/providers/keycloak) - -**Required environment variables:** -- `AUTH_EE_KEYCLOAK_CLIENT_ID` -- `AUTH_EE_KEYCLOAK_CLIENT_SECRET` -- `AUTH_EE_KEYCLOAK_ISSUER` - -### Microsoft Entra ID - -[Auth.js Microsoft Entra ID Provider Docs](https://authjs.dev/getting-started/providers/microsoft-entra-id) - -**Required environment variables:** -- `AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID` -- `AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET` -- `AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER` - ---- \ No newline at end of file +Sourcebot supports authentication using several different [external identity providers](/docs/configuration/idp) as well. These identity providers require an +[enterprise license](/docs/license-key) \ No newline at end of file diff --git a/docs/docs/configuration/idp.mdx b/docs/docs/configuration/idp.mdx index f8edb8110..af4f8e053 100644 --- a/docs/docs/configuration/idp.mdx +++ b/docs/docs/configuration/idp.mdx @@ -18,8 +18,8 @@ External identity providers can be used for [authentication](/docs/configuration "identityProviders": [ { "provider": "github", - "purpose": "integration", - "required": true, + "purpose": "account_linking", + "accountLinkingRequired": true, /* Secrets are provided through environment variables. Set the secret into an env var and provide the name here to tell Sourcebot where to get @@ -61,7 +61,7 @@ in the GitHub identity provider config. To begin, you must register an Oauth client in GitHub to faciliate the identity provider connection. You can do this by creating a **GitHub App** or a **GitHub OAuth App**. Either - one works, but the **GitHub App** is the [modern way](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps). + one works, but the **GitHub App** is the [recommended mechanism](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/differences-between-github-apps-and-oauth-apps). The result of registering an OAuth client is a `CLIENT_ID` and `CLIENT_SECRET` which you'll provide to Sourcebot. @@ -74,6 +74,7 @@ in the GitHub identity provider config. Set the following fine-grained permissions in the GitHub App: - `“Email addresses” account permissions (read)` + - `"Metadata" repository permissions (read)` (only needed if using permission syncing) Follow [this guide](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) by GitHub to create an OAuth App. @@ -95,10 +96,10 @@ in the GitHub identity provider config. "identityProviders": [ { "provider": "github", - // "sso" for auth + perm sync, "integration" for only perm sync - "purpose": "integration", - // if purpose == "integration" this controls if a user must connect to the IdP - "required": true, + // "sso" for auth + perm sync, "account_linking" for only perm sync + "purpose": "account_linking", + // if purpose == "account_linking" this controls if a user must connect to the IdP + "accountLinkingRequired": true, "clientId": { "env": "YOUR_CLIENT_ID_ENV_VAR" }, @@ -115,11 +116,256 @@ in the GitHub identity provider config. ### GitLab +[Auth.js GitLab Provider Docs](https://authjs.dev/getting-started/providers/gitlab) + +A GitLab connection can be used for either [authentication](/docs/configuration/auth) or [permission syncing](/docs/features/permission-syncing). This is controlled using the `purpose` field +in the GitLab identity provider config. + + + + + To begin, you must register an OAuth application in GitLab to facilitate the identity provider connection. + + Follow [this guide](https://docs.gitlab.com/integration/oauth_provider/) by GitLab to create an OAuth application. + + When configuring your application: + - Set the callback URL to `/api/auth/callback/gitlab` (ex. https://sourcebot.coolcorp.com/api/auth/callback/gitlab) + - Enable the `read_user` scope + - If using for permission syncing, also enable the `read_api` scope + + The result of registering an OAuth application is an `APPLICATION_ID` (`CLIENT_ID`) and `SECRET` (`CLIENT_SECRET`) which you'll provide to Sourcebot. + + + To provide Sourcebot the client id and secret for your OAuth application you must set them as environment variables. These can be named whatever you like + (ex. `GITLAB_IDENTITY_PROVIDER_CLIENT_ID` and `GITLAB_IDENTITY_PROVIDER_CLIENT_SECRET`) + + + Finally, pass the client id and secret to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "gitlab", + // "sso" for auth + perm sync, "account_linking" for only perm sync + "purpose": "account_linking", + // if purpose == "account_linking" this controls if a user must connect to the IdP + "accountLinkingRequired": true, + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + }, + // Optional: for self-hosted GitLab instances + "baseUrl": "https://gitlab.example.com" + } + ] + } + ``` + + + + ### Google +[Auth.js Google Provider Docs](https://authjs.dev/getting-started/providers/google) + +A Google connection can be used for [authentication](/docs/configuration/auth). + + + + + To begin, you must register an OAuth client in Google Cloud Console to facilitate the identity provider connection. + + Follow [this guide](https://support.google.com/cloud/answer/6158849) by Google to create OAuth 2.0 credentials. + + When configuring your OAuth client: + - Set the application type to "Web application" + - Add `/api/auth/callback/google` to the authorized redirect URIs (ex. https://sourcebot.coolcorp.com/api/auth/callback/google) + + The result of creating OAuth credentials is a `CLIENT_ID` and `CLIENT_SECRET` which you'll provide to Sourcebot. + + + To provide Sourcebot the client id and secret for your OAuth client you must set them as environment variables. These can be named whatever you like + (ex. `GOOGLE_IDENTITY_PROVIDER_CLIENT_ID` and `GOOGLE_IDENTITY_PROVIDER_CLIENT_SECRET`) + + + Finally, pass the client id and secret to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "google", + "purpose": "sso", + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + } + } + ] + } + ``` + + + + ### Okta +[Auth.js Okta Provider Docs](https://authjs.dev/getting-started/providers/okta) + +An Okta connection can be used for [authentication](/docs/configuration/auth). + + + + + To begin, you must register an OAuth application in Okta to facilitate the identity provider connection. + + Follow [this guide](https://developer.okta.com/docs/guides/implement-oauth-for-okta/main/) by Okta to create an OAuth application. + + When configuring your application: + - Set the application type to "Web Application" + - Add `/api/auth/callback/okta` to the sign-in redirect URIs (ex. https://sourcebot.coolcorp.com/api/auth/callback/okta) + + The result of creating an OAuth application is a `CLIENT_ID`, `CLIENT_SECRET`, and `ISSUER` URL which you'll provide to Sourcebot. + + + To provide Sourcebot the client id, client secret, and issuer for your OAuth application you must set them as environment variables. These can be named whatever you like + (ex. `OKTA_IDENTITY_PROVIDER_CLIENT_ID`, `OKTA_IDENTITY_PROVIDER_CLIENT_SECRET`, and `OKTA_IDENTITY_PROVIDER_ISSUER`) + + + Finally, pass the client id, client secret, and issuer to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "okta", + "purpose": "sso", + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + }, + "issuer": { + "env": "YOUR_ISSUER_ENV_VAR" + } + } + ] + } + ``` + + + + ### Keycloak +[Auth.js Keycloak Provider Docs](https://authjs.dev/getting-started/providers/keycloak) + +A Keycloak connection can be used for [authentication](/docs/configuration/auth). + + + + + To begin, you must register an OAuth client in Keycloak to facilitate the identity provider connection. + + Follow [this guide](https://www.keycloak.org/docs/latest/server_admin/#_oidc_clients) by Keycloak to create an OpenID Connect client. + + When configuring your client: + - Set the client protocol to "openid-connect" + - Set the access type to "confidential" + - Add `/api/auth/callback/keycloak` to the valid redirect URIs (ex. https://sourcebot.coolcorp.com/api/auth/callback/keycloak) + + The result of creating an OAuth client is a `CLIENT_ID`, `CLIENT_SECRET`, and an `ISSUER` URL (typically in the format `https:///realms/`) which you'll provide to Sourcebot. + + + To provide Sourcebot the client id, client secret, and issuer for your OAuth client you must set them as environment variables. These can be named whatever you like + (ex. `KEYCLOAK_IDENTITY_PROVIDER_CLIENT_ID`, `KEYCLOAK_IDENTITY_PROVIDER_CLIENT_SECRET`, and `KEYCLOAK_IDENTITY_PROVIDER_ISSUER`) + + + Finally, pass the client id, client secret, and issuer to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "keycloak", + "purpose": "sso", + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + }, + "issuer": { + "env": "YOUR_ISSUER_ENV_VAR" + } + } + ] + } + ``` + + + + ### Microsoft Entra ID +[Auth.js Microsoft Entra ID Provider Docs](https://authjs.dev/getting-started/providers/microsoft-entra-id) + +A Microsoft Entra ID connection can be used for [authentication](/docs/configuration/auth). + + + + + To begin, you must register an OAuth application in Microsoft Entra ID (formerly Azure Active Directory) to facilitate the identity provider connection. + + Follow [this guide](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) by Microsoft to register an application. + + When configuring your application: + - Under "Authentication", add a platform and select "Web" + - Set the redirect URI to `/api/auth/callback/microsoft-entra-id` (ex. https://sourcebot.coolcorp.com/api/auth/callback/microsoft-entra-id) + - Under "Certificates & secrets", create a new client secret + + The result of registering an application is a `CLIENT_ID` (Application ID), `CLIENT_SECRET`, and `TENANT_ID` which you'll use to construct the issuer URL. + + + To provide Sourcebot the client id, client secret, and issuer for your OAuth application you must set them as environment variables. These can be named whatever you like + (ex. `MICROSOFT_ENTRA_ID_IDENTITY_PROVIDER_CLIENT_ID`, `MICROSOFT_ENTRA_ID_IDENTITY_PROVIDER_CLIENT_SECRET`, and `MICROSOFT_ENTRA_ID_IDENTITY_PROVIDER_ISSUER`) + + The issuer URL should be in the format: `https://login.microsoftonline.com//v2.0` + + + Finally, pass the client id, client secret, and issuer to Sourcebot by defining a `identityProvider` object in the [config file](/docs/configuration/config-file): + + ```json wrap icon="code" + { + "$schema": "https://raw.githubusercontent.com/sourcebot-dev/sourcebot/main/schemas/v3/index.json", + "identityProviders": [ + { + "provider": "microsoft-entra-id", + "purpose": "sso", + "clientId": { + "env": "YOUR_CLIENT_ID_ENV_VAR" + }, + "clientSecret": { + "env": "YOUR_CLIENT_SECRET_ENV_VAR" + }, + "issuer": { + "env": "YOUR_ISSUER_ENV_VAR" + } + } + ] + } + ``` + + + + diff --git a/docs/docs/features/permission-syncing.mdx b/docs/docs/features/permission-syncing.mdx index ee6a96e70..403f534f1 100644 --- a/docs/docs/features/permission-syncing.mdx +++ b/docs/docs/features/permission-syncing.mdx @@ -12,10 +12,12 @@ import ExperimentalFeatureWarning from '/snippets/experimental-feature-warning.m # Overview -Permission syncing allows you to sync Access Permission Lists (ACLs) from a code host to Sourcebot. When configured, users signed into Sourcebot (via the code host's OAuth provider) will only be able to access repositories that they have access to on the code host. Practically, this means: +Permission syncing allows you to sync Access Permission Lists (ACLs) from a code host to Sourcebot. When configured, users signed into Sourcebot will only be able to access repositories +that they have access to on the code host. Practically, this means: - Code Search results will only include repositories that the user has access to. - Code navigation results will only include repositories that the user has access to. +- MCP results will only include results from repositories the user has access to. - Ask Sourcebot (and the underlying LLM) will only have access to repositories that the user has access to. - File browsing is scoped to the repositories that the user has access to. @@ -46,7 +48,7 @@ We are actively working on supporting more code hosts. If you'd like to see a sp ## GitHub -Prerequisite: [Add GitHub as an OAuth provider](/docs/configuration/auth/providers#github). +Prerequisite: Configure GitHub as an [external identity provider](/docs/configuration/idp). Permission syncing works with **GitHub.com**, **GitHub Enterprise Cloud**, and **GitHub Enterprise Server**. For organization-owned repositories, users that have **read-only** access (or above) via the following methods will have their access synced to Sourcebot: - Outside collaborators @@ -56,18 +58,18 @@ Permission syncing works with **GitHub.com**, **GitHub Enterprise Cloud**, and * - Organization owners. **Notes:** -- A GitHub OAuth provider must be configured to (1) correlate a Sourcebot user with a GitHub user, and (2) to list repositories that the user has access to for [User driven syncing](/docs/features/permission-syncing#how-it-works). +- A GitHub [external identity provider](/docs/configuration/idp) must be configured to (1) correlate a Sourcebot user with a GitHub user, and (2) to list repositories that the user has access to for [User driven syncing](/docs/features/permission-syncing#how-it-works). - OAuth tokens must assume the `repo` scope in order to use the [List repositories for the authenticated user API](https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-the-authenticated-user) during [User driven syncing](/docs/features/permission-syncing#how-it-works). Sourcebot **will only** use this token for **reads**. ## GitLab -Prerequisite: [Add GitLab as an OAuth provider](/docs/configuration/auth/providers#gitlab). +Prerequisite: Configure GitLab as an [external identity provider](/docs/configuration/idp). Permission syncing works with **GitLab Self-managed** and **GitLab Cloud**. Users with **Guest** role or above with membership to a group or project will have their access synced to Sourcebot. Both direct and indirect membership to a group or project will be synced with Sourcebot. For more details, see the [GitLab docs](https://docs.gitlab.com/user/project/members/#membership-types). **Notes:** -- A GitLab OAuth provider must be configured to (1) correlate a Sourcebot user with a GitLab user, and (2) to list repositories that the user has access to for [User driven syncing](/docs/features/permission-syncing#how-it-works). +- A GitLab [external identity provider](/docs/configuration/idp) must be configured to (1) correlate a Sourcebot user with a GitLab user, and (2) to list repositories that the user has access to for [User driven syncing](/docs/features/permission-syncing#how-it-works). - OAuth tokens require the `read_api` scope in order to use the [List projects for the authenticated user API](https://docs.gitlab.com/ee/api/projects.html#list-all-projects) during [User driven syncing](/docs/features/permission-syncing#how-it-works). diff --git a/docs/snippets/schemas/v3/authProvider.schema.mdx b/docs/snippets/schemas/v3/authProvider.schema.mdx deleted file mode 100644 index 0ebf9eb19..000000000 --- a/docs/snippets/schemas/v3/authProvider.schema.mdx +++ /dev/null @@ -1,1307 +0,0 @@ -{/* THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! */} -```json -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "IdentityProviderConfig", - "definitions": { - "GitHubIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "github" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret" - ] - }, - "GitLabIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "gitlab" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret", - "baseUrl" - ] - }, - "GoogleIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "google" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret" - ] - }, - "OktaIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "okta" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "KeycloakIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "keycloak" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "MicrosoftEntraIDIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "microsoft-entra-id" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "GCPIAPIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "gcp-iap" - }, - "audience": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "audience" - ] - } - }, - "oneOf": [ - { - "type": "object", - "properties": { - "provider": { - "const": "github" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "gitlab" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret", - "baseUrl" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "google" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "okta" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "keycloak" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "microsoft-entra-id" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "gcp-iap" - }, - "audience": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "audience" - ] - } - ] -} -``` diff --git a/docs/snippets/schemas/v3/identityProvider.schema.mdx b/docs/snippets/schemas/v3/identityProvider.schema.mdx index 988cffcb9..30c172bed 100644 --- a/docs/snippets/schemas/v3/identityProvider.schema.mdx +++ b/docs/snippets/schemas/v3/identityProvider.schema.mdx @@ -6,6 +6,7 @@ "definitions": { "GitHubIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -13,7 +14,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -77,36 +78,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -120,6 +102,7 @@ }, "GitLabIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -127,7 +110,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -191,36 +174,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -234,10 +198,14 @@ }, "GoogleIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -301,16 +269,21 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, "OktaIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -404,6 +377,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -411,10 +385,14 @@ }, "KeycloakIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -508,6 +486,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -515,10 +494,14 @@ }, "MicrosoftEntraIDIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -612,6 +595,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -619,10 +603,14 @@ }, "GCPIAPIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -656,6 +644,7 @@ }, "required": [ "provider", + "purpose", "audience" ] } @@ -663,6 +652,7 @@ "oneOf": [ { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -670,7 +660,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -734,36 +724,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -777,6 +748,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -784,7 +756,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -848,36 +820,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -891,10 +844,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -958,16 +915,21 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1061,6 +1023,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1068,10 +1031,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1165,6 +1132,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1172,10 +1140,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1269,6 +1241,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1276,10 +1249,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -1313,6 +1290,7 @@ }, "required": [ "provider", + "purpose", "audience" ] } diff --git a/docs/snippets/schemas/v3/index.schema.mdx b/docs/snippets/schemas/v3/index.schema.mdx index d43562fa8..615c058a8 100644 --- a/docs/snippets/schemas/v3/index.schema.mdx +++ b/docs/snippets/schemas/v3/index.schema.mdx @@ -4410,6 +4410,7 @@ "definitions": { "GitHubIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -4417,7 +4418,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -4481,36 +4482,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -4524,6 +4506,7 @@ }, "GitLabIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -4531,7 +4514,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -4595,36 +4578,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -4638,10 +4602,14 @@ }, "GoogleIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4705,16 +4673,21 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, "OktaIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4808,6 +4781,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -4815,10 +4789,14 @@ }, "KeycloakIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4912,6 +4890,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -4919,10 +4898,14 @@ }, "MicrosoftEntraIDIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5016,6 +4999,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5023,10 +5007,14 @@ }, "GCPIAPIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -5060,6 +5048,7 @@ }, "required": [ "provider", + "purpose", "audience" ] } @@ -5067,6 +5056,7 @@ "oneOf": [ { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -5074,7 +5064,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -5138,36 +5128,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -5181,6 +5152,7 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -5188,7 +5160,7 @@ "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -5252,36 +5224,17 @@ ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -5295,10 +5248,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5362,16 +5319,21 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5465,6 +5427,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5472,10 +5435,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5569,6 +5536,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5576,10 +5544,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5673,6 +5645,7 @@ }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5680,10 +5653,14 @@ }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -5717,6 +5694,7 @@ }, "required": [ "provider", + "purpose", "audience" ] } diff --git a/packages/schemas/src/v3/authProvider.schema.ts b/packages/schemas/src/v3/authProvider.schema.ts deleted file mode 100644 index 32a0bc46d..000000000 --- a/packages/schemas/src/v3/authProvider.schema.ts +++ /dev/null @@ -1,1306 +0,0 @@ -// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! -const schema = { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "IdentityProviderConfig", - "definitions": { - "GitHubIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "github" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret" - ] - }, - "GitLabIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "gitlab" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret", - "baseUrl" - ] - }, - "GoogleIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "google" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret" - ] - }, - "OktaIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "okta" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "KeycloakIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "keycloak" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "MicrosoftEntraIDIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "microsoft-entra-id" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - "GCPIAPIdentityProviderConfig": { - "type": "object", - "properties": { - "provider": { - "const": "gcp-iap" - }, - "audience": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "audience" - ] - } - }, - "oneOf": [ - { - "type": "object", - "properties": { - "provider": { - "const": "github" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "gitlab" - }, - "purpose": { - "enum": [ - "sso", - "identity" - ] - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "purpose", - "clientId", - "clientSecret", - "baseUrl" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "google" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "okta" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "keycloak" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "microsoft-entra-id" - }, - "clientId": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "clientSecret": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - }, - "issuer": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "clientId", - "clientSecret", - "issuer" - ] - }, - { - "type": "object", - "properties": { - "provider": { - "const": "gcp-iap" - }, - "audience": { - "anyOf": [ - { - "type": "object", - "properties": { - "secret": { - "type": "string", - "description": "The name of the secret that contains the token." - } - }, - "required": [ - "secret" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token. Only supported in declarative connection configs." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - } - ] - } - }, - "required": [ - "provider", - "audience" - ] - } - ] -} as const; -export { schema as authProviderSchema }; \ No newline at end of file diff --git a/packages/schemas/src/v3/authProvider.type.ts b/packages/schemas/src/v3/authProvider.type.ts deleted file mode 100644 index 5cea9cf45..000000000 --- a/packages/schemas/src/v3/authProvider.type.ts +++ /dev/null @@ -1,275 +0,0 @@ -// THIS IS A AUTO-GENERATED FILE. DO NOT MODIFY MANUALLY! - -export type IdentityProviderConfig = - | GitHubIdentityProviderConfig - | GitLabIdentityProviderConfig - | GoogleIdentityProviderConfig - | OktaIdentityProviderConfig - | KeycloakIdentityProviderConfig - | MicrosoftEntraIDIdentityProviderConfig - | GCPIAPIdentityProviderConfig; - -export interface GitHubIdentityProviderConfig { - provider: "github"; - purpose: "sso" | "identity"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - baseUrl?: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface GitLabIdentityProviderConfig { - provider: "gitlab"; - purpose: "sso" | "identity"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - baseUrl: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface GoogleIdentityProviderConfig { - provider: "google"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface OktaIdentityProviderConfig { - provider: "okta"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface KeycloakIdentityProviderConfig { - provider: "keycloak"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface MicrosoftEntraIDIdentityProviderConfig { - provider: "microsoft-entra-id"; - clientId: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - clientSecret: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - issuer: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} -export interface GCPIAPIdentityProviderConfig { - provider: "gcp-iap"; - audience: - | { - /** - * The name of the secret that contains the token. - */ - secret: string; - } - | { - /** - * The name of the environment variable that contains the token. Only supported in declarative connection configs. - */ - env: string; - }; - [k: string]: unknown; -} diff --git a/packages/schemas/src/v3/identityProvider.schema.ts b/packages/schemas/src/v3/identityProvider.schema.ts index 0dd3ddc4b..708c3b4cd 100644 --- a/packages/schemas/src/v3/identityProvider.schema.ts +++ b/packages/schemas/src/v3/identityProvider.schema.ts @@ -5,6 +5,7 @@ const schema = { "definitions": { "GitHubIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -12,7 +13,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -76,36 +77,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -119,6 +101,7 @@ const schema = { }, "GitLabIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -126,7 +109,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -190,36 +173,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -233,10 +197,14 @@ const schema = { }, "GoogleIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -300,16 +268,21 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, "OktaIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -403,6 +376,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -410,10 +384,14 @@ const schema = { }, "KeycloakIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -507,6 +485,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -514,10 +493,14 @@ const schema = { }, "MicrosoftEntraIDIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -611,6 +594,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -618,10 +602,14 @@ const schema = { }, "GCPIAPIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -655,6 +643,7 @@ const schema = { }, "required": [ "provider", + "purpose", "audience" ] } @@ -662,6 +651,7 @@ const schema = { "oneOf": [ { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -669,7 +659,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -733,36 +723,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -776,6 +747,7 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -783,7 +755,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -847,36 +819,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -890,10 +843,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -957,16 +914,21 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1060,6 +1022,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1067,10 +1030,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1164,6 +1131,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1171,10 +1139,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -1268,6 +1240,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -1275,10 +1248,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -1312,6 +1289,7 @@ const schema = { }, "required": [ "provider", + "purpose", "audience" ] } diff --git a/packages/schemas/src/v3/identityProvider.type.ts b/packages/schemas/src/v3/identityProvider.type.ts index 541f0ca76..31d7a9a8c 100644 --- a/packages/schemas/src/v3/identityProvider.type.ts +++ b/packages/schemas/src/v3/identityProvider.type.ts @@ -11,7 +11,7 @@ export type IdentityProviderConfig = export interface GitHubIdentityProviderConfig { provider: "github"; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; clientId: | { /** @@ -38,25 +38,15 @@ export interface GitHubIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl?: - | { - /** - * The name of the environment variable that contains the token. - */ - env: string; - } - | { - /** - * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets - */ - googleCloudSecret: string; - }; - required?: boolean; - [k: string]: unknown; + /** + * The URL of the GitHub host. Defaults to https://github.com + */ + baseUrl?: string; + accountLinkingRequired?: boolean; } export interface GitLabIdentityProviderConfig { provider: "gitlab"; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; clientId: | { /** @@ -83,24 +73,15 @@ export interface GitLabIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl?: - | { - /** - * The name of the environment variable that contains the token. - */ - env: string; - } - | { - /** - * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets - */ - googleCloudSecret: string; - }; - required?: boolean; - [k: string]: unknown; + /** + * The URL of the GitLab host. Defaults to https://gitlab.com + */ + baseUrl?: string; + accountLinkingRequired?: boolean; } export interface GoogleIdentityProviderConfig { provider: "google"; + purpose: "sso"; clientId: | { /** @@ -127,10 +108,10 @@ export interface GoogleIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface OktaIdentityProviderConfig { provider: "okta"; + purpose: "sso"; clientId: | { /** @@ -170,10 +151,10 @@ export interface OktaIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface KeycloakIdentityProviderConfig { provider: "keycloak"; + purpose: "sso"; clientId: | { /** @@ -213,10 +194,10 @@ export interface KeycloakIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface MicrosoftEntraIDIdentityProviderConfig { provider: "microsoft-entra-id"; + purpose: "sso"; clientId: | { /** @@ -256,10 +237,10 @@ export interface MicrosoftEntraIDIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface GCPIAPIdentityProviderConfig { provider: "gcp-iap"; + purpose: "sso"; audience: | { /** @@ -273,5 +254,4 @@ export interface GCPIAPIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } diff --git a/packages/schemas/src/v3/index.schema.ts b/packages/schemas/src/v3/index.schema.ts index a6bdd2f62..ee0452435 100644 --- a/packages/schemas/src/v3/index.schema.ts +++ b/packages/schemas/src/v3/index.schema.ts @@ -4409,6 +4409,7 @@ const schema = { "definitions": { "GitHubIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -4416,7 +4417,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -4480,36 +4481,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -4523,6 +4505,7 @@ const schema = { }, "GitLabIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -4530,7 +4513,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -4594,36 +4577,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -4637,10 +4601,14 @@ const schema = { }, "GoogleIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4704,16 +4672,21 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, "OktaIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4807,6 +4780,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -4814,10 +4788,14 @@ const schema = { }, "KeycloakIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -4911,6 +4889,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -4918,10 +4897,14 @@ const schema = { }, "MicrosoftEntraIDIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5015,6 +4998,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5022,10 +5006,14 @@ const schema = { }, "GCPIAPIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -5059,6 +5047,7 @@ const schema = { }, "required": [ "provider", + "purpose", "audience" ] } @@ -5066,6 +5055,7 @@ const schema = { "oneOf": [ { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" @@ -5073,7 +5063,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -5137,36 +5127,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -5180,6 +5151,7 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" @@ -5187,7 +5159,7 @@ const schema = { "purpose": { "enum": [ "sso", - "integration" + "account_linking" ] }, "clientId": { @@ -5251,36 +5223,17 @@ const schema = { ] }, "baseUrl": { - "anyOf": [ - { - "type": "object", - "properties": { - "env": { - "type": "string", - "description": "The name of the environment variable that contains the token." - } - }, - "required": [ - "env" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "googleCloudSecret": { - "type": "string", - "description": "The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets" - } - }, - "required": [ - "googleCloudSecret" - ], - "additionalProperties": false - } - ] + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" }, - "required": { + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -5294,10 +5247,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5361,16 +5318,21 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret" ] }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5464,6 +5426,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5471,10 +5434,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5568,6 +5535,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5575,10 +5543,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "anyOf": [ { @@ -5672,6 +5644,7 @@ const schema = { }, "required": [ "provider", + "purpose", "clientId", "clientSecret", "issuer" @@ -5679,10 +5652,14 @@ const schema = { }, { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "anyOf": [ { @@ -5716,6 +5693,7 @@ const schema = { }, "required": [ "provider", + "purpose", "audience" ] } diff --git a/packages/schemas/src/v3/index.type.ts b/packages/schemas/src/v3/index.type.ts index aef3e6acb..0e88d8ab7 100644 --- a/packages/schemas/src/v3/index.type.ts +++ b/packages/schemas/src/v3/index.type.ts @@ -1118,7 +1118,7 @@ export interface GitHubAppConfig { } export interface GitHubIdentityProviderConfig { provider: "github"; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; clientId: | { /** @@ -1145,25 +1145,15 @@ export interface GitHubIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl?: - | { - /** - * The name of the environment variable that contains the token. - */ - env: string; - } - | { - /** - * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets - */ - googleCloudSecret: string; - }; - required?: boolean; - [k: string]: unknown; + /** + * The URL of the GitHub host. Defaults to https://github.com + */ + baseUrl?: string; + accountLinkingRequired?: boolean; } export interface GitLabIdentityProviderConfig { provider: "gitlab"; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; clientId: | { /** @@ -1190,24 +1180,15 @@ export interface GitLabIdentityProviderConfig { */ googleCloudSecret: string; }; - baseUrl?: - | { - /** - * The name of the environment variable that contains the token. - */ - env: string; - } - | { - /** - * The resource name of a Google Cloud secret. Must be in the format `projects//secrets//versions/`. See https://cloud.google.com/secret-manager/docs/creating-and-accessing-secrets - */ - googleCloudSecret: string; - }; - required?: boolean; - [k: string]: unknown; + /** + * The URL of the GitLab host. Defaults to https://gitlab.com + */ + baseUrl?: string; + accountLinkingRequired?: boolean; } export interface GoogleIdentityProviderConfig { provider: "google"; + purpose: "sso"; clientId: | { /** @@ -1234,10 +1215,10 @@ export interface GoogleIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface OktaIdentityProviderConfig { provider: "okta"; + purpose: "sso"; clientId: | { /** @@ -1277,10 +1258,10 @@ export interface OktaIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface KeycloakIdentityProviderConfig { provider: "keycloak"; + purpose: "sso"; clientId: | { /** @@ -1320,10 +1301,10 @@ export interface KeycloakIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface MicrosoftEntraIDIdentityProviderConfig { provider: "microsoft-entra-id"; + purpose: "sso"; clientId: | { /** @@ -1363,10 +1344,10 @@ export interface MicrosoftEntraIDIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } export interface GCPIAPIdentityProviderConfig { provider: "gcp-iap"; + purpose: "sso"; audience: | { /** @@ -1380,5 +1361,4 @@ export interface GCPIAPIdentityProviderConfig { */ googleCloudSecret: string; }; - [k: string]: unknown; } diff --git a/packages/web/src/app/[domain]/layout.tsx b/packages/web/src/app/[domain]/layout.tsx index 38935953e..a3079d7f0 100644 --- a/packages/web/src/app/[domain]/layout.tsx +++ b/packages/web/src/app/[domain]/layout.tsx @@ -23,7 +23,7 @@ import { JoinOrganizationCard } from "@/app/components/joinOrganizationCard"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; import { GitHubStarToast } from "./components/githubStarToast"; import { UpgradeToast } from "./components/upgradeToast"; -import { getIntegrationProviderStates } from "@/ee/features/permissionSyncing/actions"; +import { getLinkedAccountProviderStates } from "@/ee/features/permissionSyncing/actions"; import { LinkAccounts } from "@/ee/features/permissionSyncing/components/linkAccounts"; interface LayoutProps { @@ -126,16 +126,16 @@ export default async function Layout(props: LayoutProps) { } if (hasEntitlement("permission-syncing")) { - const integrationProviderStates = await getIntegrationProviderStates(); - if (isServiceError(integrationProviderStates)) { + const linkedAccountProviderStates = await getLinkedAccountProviderStates(); + if (isServiceError(linkedAccountProviderStates)) { return (

An error occurred

- {typeof integrationProviderStates.message === 'string' - ? integrationProviderStates.message + {typeof linkedAccountProviderStates.message === 'string' + ? linkedAccountProviderStates.message : "A server error occurred while checking your account status. Please try again or contact support."}

@@ -143,18 +143,18 @@ export default async function Layout(props: LayoutProps) { ) } - const hasUnlinkedProviders = integrationProviderStates.some(state => state.isLinked === false); + const hasUnlinkedProviders = linkedAccountProviderStates.some(state => state.isLinked === false); if (hasUnlinkedProviders) { const cookieStore = await cookies(); const hasSkippedOptional = cookieStore.has(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); - const hasUnlinkedRequiredProviders = integrationProviderStates.some(state => state.required && !state.isLinked) + const hasUnlinkedRequiredProviders = linkedAccountProviderStates.some(state => state.required && !state.isLinked) const shouldShowLinkAccounts = hasUnlinkedRequiredProviders || !hasSkippedOptional; if (shouldShowLinkAccounts) { return (
- +
) } diff --git a/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx index 948171b14..d9c136c9c 100644 --- a/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx +++ b/packages/web/src/app/[domain]/settings/permission-syncing/page.tsx @@ -1,11 +1,11 @@ import { hasEntitlement } from "@sourcebot/shared"; -import { notFound } from "@/lib/serviceError"; +import { notFound } from "next/navigation" import { LinkedAccountsSettings } from "@/ee/features/permissionSyncing/components/linkedAccountsSettings"; export default async function PermissionSyncingPage() { const hasPermissionSyncingEntitlement = await hasEntitlement("permission-syncing"); if (!hasPermissionSyncingEntitlement) { - notFound(); + return notFound(); } return ; diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts index d9cfeb88b..64dab588f 100644 --- a/packages/web/src/auth.ts +++ b/packages/web/src/auth.ts @@ -18,7 +18,7 @@ import { hasEntitlement } from '@sourcebot/shared'; import { onCreateUser } from '@/lib/authUtils'; import { getAuditService } from '@/ee/features/audit/factory'; import { SINGLE_TENANT_ORG_ID } from './lib/constants'; -import { refreshIntegrationTokens } from '@/ee/features/permissionSyncing/tokenRefresh'; +import { refreshLinkedAccountTokens } from '@/ee/features/permissionSyncing/tokenRefresh'; const auditService = getAuditService(); const eeIdentityProviders = hasEntitlement("sso") ? await getEEIdentityProviders() : []; @@ -27,29 +27,32 @@ export const runtime = 'nodejs'; export type IdentityProvider = { provider: Provider; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; required?: boolean; } +export type LinkedAccountToken = { + provider: string; + accessToken: string; + refreshToken: string; + expiresAt: number; + error?: string; +}; +export type LinkedAccountTokensMap = Record; + declare module 'next-auth' { interface Session { user: { id: string; } & DefaultSession['user']; - integrationProviderErrors?: Record; + linkedAccountProviderErrors?: Record; } } declare module 'next-auth/jwt' { interface JWT { userId: string; - integrationTokens?: Record; - error?: string; + linkedAccountTokens?: LinkedAccountTokensMap; } } @@ -196,24 +199,20 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ token.userId = user.id; } - // When a user links a new account, store the tokens if it's an integration provider - if (account && hasEntitlement('permission-syncing')) { - if (account.access_token && account.refresh_token && account.expires_at) { - token.integrationTokens = token.integrationTokens || {}; - token.integrationTokens[account.provider] = { + if (hasEntitlement('permission-syncing')) { + if (account && account.access_token && account.refresh_token && account.expires_at) { + token.linkedAccountTokens = token.linkedAccountTokens || {}; + token.linkedAccountTokens[account.providerAccountId] = { + provider: account.provider, accessToken: account.access_token, refreshToken: account.refresh_token, expiresAt: account.expires_at, }; } - } - // Refresh all integration provider tokens that are about to expire - if (hasEntitlement('permission-syncing') && token.integrationTokens) { - token.integrationTokens = await refreshIntegrationTokens( - token.integrationTokens, - token.userId - ); + if (token.linkedAccountTokens) { + token.linkedAccountTokens = await refreshLinkedAccountTokens(token.linkedAccountTokens); + } } return token; @@ -226,16 +225,17 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ // Propagate the userId to the session. id: token.userId, } - // Pass only integration provider errors to the session (not sensitive tokens) - if (token.integrationTokens) { + + // Pass only linked account provider errors to the session (not sensitive tokens) + if (token.linkedAccountTokens) { const errors: Record = {}; - for (const [provider, tokenData] of Object.entries(token.integrationTokens)) { + for (const [providerAccountId, tokenData] of Object.entries(token.linkedAccountTokens)) { if (tokenData.error) { - errors[provider] = tokenData.error; + errors[providerAccountId] = tokenData.error; } } if (Object.keys(errors).length > 0) { - session.integrationProviderErrors = errors; + session.linkedAccountProviderErrors = errors; } } return session; diff --git a/packages/web/src/ee/features/permissionSyncing/actions.ts b/packages/web/src/ee/features/permissionSyncing/actions.ts index 08779d692..956670271 100644 --- a/packages/web/src/ee/features/permissionSyncing/actions.ts +++ b/packages/web/src/ee/features/permissionSyncing/actions.ts @@ -8,21 +8,21 @@ import { env } from "@/env.mjs"; import { OrgRole } from "@sourcebot/db"; import { cookies } from "next/headers"; import { OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME } from "@/lib/constants"; -import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types"; +import { LinkedAccountProviderState } from "@/ee/features/permissionSyncing/types"; import { auth } from "@/auth"; const logger = createLogger('web-ee-permission-syncing-actions'); -export const getIntegrationProviderStates = async () => sew(() => +export const getLinkedAccountProviderStates = async () => sew(() => withAuthV2(async ({ prisma, role, user }) => withMinimumOrgRole(role, OrgRole.MEMBER, async () => { const config = await loadConfig(env.CONFIG_PATH); - const integrationProviderConfigs = config.identityProviders ?? []; + const linkedAccountProviderConfigs = config.identityProviders ?? []; const linkedAccounts = await prisma.account.findMany({ where: { userId: user.id, provider: { - in: integrationProviderConfigs.map(p => p.provider) + in: linkedAccountProviderConfigs.map(p => p.provider) } }, select: { @@ -33,44 +33,44 @@ export const getIntegrationProviderStates = async () => sew(() => // Fetch the session to get token errors const session = await auth(); - const providerErrors = session?.integrationProviderErrors; + const providerErrors = session?.linkedAccountProviderErrors; - const integrationProviderState: IntegrationIdentityProviderState[] = []; - for (const integrationProviderConfig of integrationProviderConfigs) { - if (integrationProviderConfig.purpose === "integration") { + const linkedAccountProviderState: LinkedAccountProviderState[] = []; + for (const linkedAccountProviderConfig of linkedAccountProviderConfigs) { + if (linkedAccountProviderConfig.purpose === "account_linking") { const linkedAccount = linkedAccounts.find( - account => account.provider === integrationProviderConfig.provider + account => account.provider === linkedAccountProviderConfig.provider ); const isLinked = !!linkedAccount; - const isRequired = integrationProviderConfig.required ?? false; - const providerError = providerErrors?.[integrationProviderConfig.provider]; + const isRequired = linkedAccountProviderConfig.accountLinkingRequired ?? false; + const providerError = linkedAccount ? providerErrors?.[linkedAccount.providerAccountId] : undefined; - integrationProviderState.push({ - id: integrationProviderConfig.provider, + linkedAccountProviderState.push({ + id: linkedAccountProviderConfig.provider, required: isRequired, isLinked, linkedAccountId: linkedAccount?.providerAccountId, error: providerError - } as IntegrationIdentityProviderState); + } as LinkedAccountProviderState); } } - return integrationProviderState; + return linkedAccountProviderState; }) ) ); -export const unlinkIntegrationProvider = async (provider: string) => sew(() => +export const unlinkLinkedAccountProvider = async (provider: string) => sew(() => withAuthV2(async ({ prisma, role, user }) => withMinimumOrgRole(role, OrgRole.MEMBER, async () => { const config = await loadConfig(env.CONFIG_PATH); const identityProviders = config.identityProviders ?? []; const providerConfig = identityProviders.find(idp => idp.provider === provider) - if (!providerConfig || !('purpose' in providerConfig) || providerConfig.purpose !== "integration") { - throw new Error("Provider is not an integration provider"); + if (!providerConfig || providerConfig.purpose !== "account_linking") { + throw new Error("Provider is not a linked account provider"); } // Delete the account @@ -81,11 +81,11 @@ export const unlinkIntegrationProvider = async (provider: string) => sew(() => }, }); - logger.info(`Unlinked integration provider ${provider} for user ${user.id}. Deleted ${result.count} account(s).`); + logger.info(`Unlinked account provider ${provider} for user ${user.id}. Deleted ${result.count} account(s).`); // If we're unlinking a required identity provider then we want to wipe the optional skip cookie if it exists so that we give the // user the option of linking optional providers in the same link accounts screen - const isRequired = providerConfig.required ?? false; + const isRequired = providerConfig.accountLinkingRequired ?? false; if (isRequired) { const cookieStore = await cookies(); cookieStore.delete(OPTIONAL_PROVIDERS_LINK_SKIPPED_COOKIE_NAME); diff --git a/packages/web/src/ee/features/permissionSyncing/components/linkAccounts.tsx b/packages/web/src/ee/features/permissionSyncing/components/linkAccounts.tsx index 52859269c..dd3aa531b 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/linkAccounts.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/linkAccounts.tsx @@ -5,15 +5,15 @@ import { Button } from "@/components/ui/button"; import { skipOptionalProvidersLink } from "@/ee/features/permissionSyncing/actions"; import { useRouter } from "next/navigation"; import { useState } from "react"; -import { IntegrationProviderCard } from "./integrationProviderCard"; -import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types"; +import { LinkedAccountProviderCard } from "./linkedAccountProviderCard"; +import { LinkedAccountProviderState } from "@/ee/features/permissionSyncing/types"; interface LinkAccountsProps { - integrationProviderStates: IntegrationIdentityProviderState[] + linkedAccountProviderStates: LinkedAccountProviderState[] callbackUrl?: string; } -export const LinkAccounts = ({ integrationProviderStates, callbackUrl }: LinkAccountsProps) => { +export const LinkAccounts = ({ linkedAccountProviderStates, callbackUrl }: LinkAccountsProps) => { const router = useRouter(); const [isSkipping, setIsSkipping] = useState(false); @@ -29,7 +29,7 @@ export const LinkAccounts = ({ integrationProviderStates, callbackUrl }: LinkAcc } }; - const canSkip = !integrationProviderStates.some(state => state.required && !state.isLinked); + const canSkip = !linkedAccountProviderStates.some(state => state.required && !state.isLinked); return ( @@ -42,12 +42,12 @@ export const LinkAccounts = ({ integrationProviderStates, callbackUrl }: LinkAcc
- {integrationProviderStates + {linkedAccountProviderStates .sort((a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0)) .map(state => ( - ))} diff --git a/packages/web/src/ee/features/permissionSyncing/components/integrationProviderCard.tsx b/packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx similarity index 79% rename from packages/web/src/ee/features/permissionSyncing/components/integrationProviderCard.tsx rename to packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx index 855227125..766784dde 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/integrationProviderCard.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/linkedAccountProviderCard.tsx @@ -5,19 +5,19 @@ import { ProviderIcon } from "./providerIcon"; import { ProviderInfo } from "./providerInfo"; import { UnlinkButton } from "./unlinkButton"; import { LinkButton } from "./linkButton"; -import { IntegrationIdentityProviderState } from "@/ee/features/permissionSyncing/types" +import { LinkedAccountProviderState } from "@/ee/features/permissionSyncing/types" import { SINGLE_TENANT_ORG_DOMAIN } from "@/lib/constants"; -interface IntegrationProviderCardProps { - integrationProviderState: IntegrationIdentityProviderState; +interface LinkedAccountProviderCardProps { + linkedAccountProviderState: LinkedAccountProviderState; callbackUrl?: string; } -export function IntegrationProviderCard({ - integrationProviderState, +export function LinkedAccountProviderCard({ + linkedAccountProviderState, callbackUrl, -}: IntegrationProviderCardProps) { - const providerInfo = getAuthProviderInfo(integrationProviderState.id); +}: LinkedAccountProviderCardProps) { + const providerInfo = getAuthProviderInfo(linkedAccountProviderState.id); const defaultCallbackUrl = `/${SINGLE_TENANT_ORG_DOMAIN}/settings/permission-syncing`; return ( @@ -35,14 +35,14 @@ export function IntegrationProviderCard({
- {integrationProviderState.isLinked? ( + {linkedAccountProviderState.isLinked? (
@@ -50,11 +50,11 @@ export function IntegrationProviderCard({ Connected
- {integrationProviderState.linkedAccountId && ( + {linkedAccountProviderState.linkedAccountId && ( <> - {integrationProviderState.linkedAccountId} + {linkedAccountProviderState.linkedAccountId} )} @@ -67,7 +67,7 @@ export function IntegrationProviderCard({
)} - {integrationProviderState.error && ( + {linkedAccountProviderState.error && (
@@ -80,14 +80,14 @@ export function IntegrationProviderCard({
- {integrationProviderState.isLinked? ( + {linkedAccountProviderState.isLinked? ( ) : ( )} diff --git a/packages/web/src/ee/features/permissionSyncing/components/linkedAccountsSettings.tsx b/packages/web/src/ee/features/permissionSyncing/components/linkedAccountsSettings.tsx index 3b7fff882..8b326bdfd 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/linkedAccountsSettings.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/linkedAccountsSettings.tsx @@ -1,20 +1,20 @@ import { ShieldCheck } from "lucide-react"; -import { getIntegrationProviderStates } from "@/ee/features/permissionSyncing/actions" +import { getLinkedAccountProviderStates } from "@/ee/features/permissionSyncing/actions" import { Card, CardContent } from "@/components/ui/card"; -import { IntegrationProviderCard } from "./integrationProviderCard"; +import { LinkedAccountProviderCard } from "./linkedAccountProviderCard"; import { LogoutEscapeHatch } from "@/app/components/logoutEscapeHatch"; import { isServiceError } from "@/lib/utils"; export async function LinkedAccountsSettings() { - const integrationProviderStates = await getIntegrationProviderStates(); - if (isServiceError(integrationProviderStates)) { + const linkedAccountProviderStates = await getLinkedAccountProviderStates(); + if (isServiceError(linkedAccountProviderStates)) { return

An error occurred

- {typeof integrationProviderStates.message === 'string' - ? integrationProviderStates.message + {typeof linkedAccountProviderStates.message === 'string' + ? linkedAccountProviderStates.message : "A server error occurred while checking your account status. Please try again or contact support."}

@@ -30,7 +30,7 @@ export async function LinkedAccountsSettings() {

- {integrationProviderStates.length === 0 ? ( + {linkedAccountProviderStates.length === 0 ? (
@@ -44,13 +44,13 @@ export async function LinkedAccountsSettings() { ) : (
- {integrationProviderStates + {linkedAccountProviderStates .sort((a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0)) .map((state) => { return ( - ); })} diff --git a/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx b/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx index 3a23d1d56..fa4394738 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/providerIcon.tsx @@ -25,8 +25,15 @@ const sizeClasses = { } }; +const sizeDimensions = { + sm: { width: 16, height: 16 }, + md: { width: 20, height: 20 }, + lg: { width: 24, height: 24 } +}; + export function ProviderIcon({ icon, displayName, size = "md" }: ProviderIconProps) { const sizes = sizeClasses[size]; + const dimensions = sizeDimensions[size]; if (icon) { return ( @@ -34,6 +41,8 @@ export function ProviderIcon({ icon, displayName, size = "md" }: ProviderIconPro {displayName}
diff --git a/packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx b/packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx index 9a7a65cb6..ebd05ab9c 100644 --- a/packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx +++ b/packages/web/src/ee/features/permissionSyncing/components/unlinkButton.tsx @@ -3,7 +3,7 @@ import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Unlink, Loader2 } from "lucide-react"; -import { unlinkIntegrationProvider } from "../actions"; +import { unlinkLinkedAccountProvider } from "../actions"; import { isServiceError } from "@/lib/utils"; import { useRouter } from "next/navigation"; import { useToast } from "@/components/hooks/use-toast"; @@ -25,7 +25,7 @@ export const UnlinkButton = ({ provider, providerName }: UnlinkButtonProps) => { setIsUnlinking(true); try { - const result = await unlinkIntegrationProvider(provider); + const result = await unlinkLinkedAccountProvider(provider); if (isServiceError(result)) { toast({ diff --git a/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts b/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts index dcb94d2ae..f6ebef067 100644 --- a/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts +++ b/packages/web/src/ee/features/permissionSyncing/tokenRefresh.ts @@ -3,22 +3,14 @@ import { env } from "@/env.mjs"; import { createLogger } from "@sourcebot/logger"; import { getTokenFromConfig } from '@sourcebot/crypto'; import { GitHubIdentityProviderConfig, GitLabIdentityProviderConfig } from "@sourcebot/schemas/v3/index.type"; +import { LinkedAccountTokensMap } from "@/auth" +const { prisma } = await import('@/prisma'); const logger = createLogger('web-ee-token-refresh'); -export type IntegrationToken = { - accessToken: string; - refreshToken: string; - expiresAt: number; - error?: string; -}; - -export type IntegrationTokensMap = Record; - -export async function refreshIntegrationTokens( - currentTokens: IntegrationTokensMap | undefined, - userId: string -): Promise { +export async function refreshLinkedAccountTokens( + currentTokens: LinkedAccountTokensMap | undefined +): Promise { if (!currentTokens) { return {}; } @@ -26,26 +18,40 @@ export async function refreshIntegrationTokens( const now = Math.floor(Date.now() / 1000); const bufferTimeS = 5 * 60; // 5 minutes - const updatedTokens: IntegrationTokensMap = { ...currentTokens }; + const updatedTokens: LinkedAccountTokensMap = { ...currentTokens }; - // Refresh tokens for each integration provider await Promise.all( - Object.entries(currentTokens).map(async ([provider, tokenData]) => { + Object.entries(currentTokens).map(async ([providerAccountId, tokenData]) => { + const provider = tokenData.provider; if (provider !== 'github' && provider !== 'gitlab') { return; } if (tokenData.expiresAt && now >= (tokenData.expiresAt - bufferTimeS)) { try { - logger.info(`Refreshing token for provider: ${provider}`); + logger.info(`Refreshing token for providerAccountId: ${providerAccountId} (${tokenData.provider})`); const refreshedTokens = await refreshOAuthToken( provider, - tokenData.refreshToken, - userId + tokenData.refreshToken ); if (refreshedTokens) { - updatedTokens[provider] = { + await prisma.account.update({ + where: { + provider_providerAccountId: { + provider: provider, + providerAccountId: providerAccountId + } + }, + data: { + access_token: refreshedTokens.accessToken, + refresh_token: refreshedTokens.refreshToken, + expires_at: refreshedTokens.expiresAt, + }, + }); + + updatedTokens[providerAccountId] = { + provider: tokenData.provider, accessToken: refreshedTokens.accessToken, refreshToken: refreshedTokens.refreshToken ?? tokenData.refreshToken, expiresAt: refreshedTokens.expiresAt, @@ -53,14 +59,14 @@ export async function refreshIntegrationTokens( logger.info(`Successfully refreshed token for provider: ${provider}`); } else { logger.error(`Failed to refresh token for provider: ${provider}`); - updatedTokens[provider] = { + updatedTokens[providerAccountId] = { ...tokenData, error: 'RefreshTokenError', }; } } catch (error) { logger.error(`Error refreshing token for provider ${provider}:`, error); - updatedTokens[provider] = { + updatedTokens[providerAccountId] = { ...tokenData, error: 'RefreshTokenError', }; @@ -75,82 +81,83 @@ export async function refreshIntegrationTokens( export async function refreshOAuthToken( provider: string, refreshToken: string, - userId: string ): Promise<{ accessToken: string; refreshToken: string | null; expiresAt: number } | null> { try { const config = await loadConfig(env.CONFIG_PATH); const identityProviders = config?.identityProviders ?? []; - const providerConfig = identityProviders.find(idp => idp.provider === provider); - if (!providerConfig) { + const providerConfigs = identityProviders.filter(idp => idp.provider === provider); + if (providerConfigs.length === 0) { logger.error(`Provider config not found or invalid for: ${provider}`); return null; } - // Get client credentials from config - const integrationProviderConfig = providerConfig as GitHubIdentityProviderConfig | GitLabIdentityProviderConfig - const clientId = await getTokenFromConfig(integrationProviderConfig.clientId); - const clientSecret = await getTokenFromConfig(integrationProviderConfig.clientSecret); - const baseUrl = 'baseUrl' in integrationProviderConfig && integrationProviderConfig.baseUrl - ? await getTokenFromConfig(integrationProviderConfig.baseUrl) - : undefined; - - let url: string; - if (baseUrl) { - url = provider === 'github' - ? `${baseUrl}/login/oauth/access_token` - : `${baseUrl}/oauth/token`; - } else if (provider === 'github') { - url = 'https://github.com/login/oauth/access_token'; - } else if (provider === 'gitlab') { - url = 'https://gitlab.com/oauth/token'; - } else { - logger.error(`Unsupported provider for token refresh: ${provider}`); - return null; - } + // Loop through all provider configs and return on first successful fetch + // + // The reason we have to do this is because 1) we might have multiple providers of the same type (ex. we're connecting to multiple gitlab instances) and 2) there isn't + // a trivial way to map a provider config to the associated Account object in the DB. The reason the config is involved at all here is because we need the client + // id/secret in order to refresh the token, and that info is in the config. We could in theory bypass this by storing the client id/secret for the provider in the + // Account table but we decided not to do that since these are secret. Instead, we simply try all of the client/id secrets for the associated provider type. This is safe + // to do because only the correct client id/secret will work since we're using a specific refresh token. + for (const providerConfig of providerConfigs) { + try { + // Get client credentials from config + const linkedAccountProviderConfig = providerConfig as GitHubIdentityProviderConfig | GitLabIdentityProviderConfig + const clientId = await getTokenFromConfig(linkedAccountProviderConfig.clientId); + const clientSecret = await getTokenFromConfig(linkedAccountProviderConfig.clientSecret); + const baseUrl = linkedAccountProviderConfig.baseUrl + + let url: string; + if (baseUrl) { + url = provider === 'github' + ? `${baseUrl}/login/oauth/access_token` + : `${baseUrl}/oauth/token`; + } else if (provider === 'github') { + url = 'https://github.com/login/oauth/access_token'; + } else if (provider === 'gitlab') { + url = 'https://gitlab.com/oauth/token'; + } else { + logger.error(`Unsupported provider for token refresh: ${provider}`); + continue; + } - const response = await fetch(url, { - method: 'POST', - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'application/json', - }, - body: new URLSearchParams({ - client_id: clientId, - client_secret: clientSecret, - grant_type: 'refresh_token', - refresh_token: refreshToken, - }), - }); - - if (!response.ok) { - const errorText = await response.text(); - logger.error(`Failed to refresh ${provider} token: ${response.status} ${errorText}`); - return null; + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + }, + body: new URLSearchParams({ + client_id: clientId, + client_secret: clientSecret, + grant_type: 'refresh_token', + refresh_token: refreshToken, + }), + }); + + if (!response.ok) { + const errorText = await response.text(); + logger.debug(`Failed to refresh ${provider} token with config: ${response.status} ${errorText}`); + continue; + } + + const data = await response.json(); + + const result = { + accessToken: data.access_token, + refreshToken: data.refresh_token ?? null, + expiresAt: data.expires_in ? Math.floor(Date.now() / 1000) + data.expires_in : 0, + }; + + return result; + } catch (configError) { + logger.debug(`Error trying provider config for ${provider}:`, configError); + continue; + } } - const data = await response.json(); - - const result = { - accessToken: data.access_token, - refreshToken: data.refresh_token ?? null, - expiresAt: data.expires_in ? Math.floor(Date.now() / 1000) + data.expires_in : 0, - }; - - const { prisma } = await import('@/prisma'); - await prisma.account.updateMany({ - where: { - userId: userId, - provider: provider, - }, - data: { - access_token: result.accessToken, - refresh_token: result.refreshToken, - expires_at: result.expiresAt, - }, - }); - - return result; + logger.error(`All provider configs failed for: ${provider}`); + return null; } catch (error) { logger.error(`Error refreshing ${provider} token:`, error); return null; diff --git a/packages/web/src/ee/features/permissionSyncing/types.ts b/packages/web/src/ee/features/permissionSyncing/types.ts index 3bdb87c79..3fdc16e26 100644 --- a/packages/web/src/ee/features/permissionSyncing/types.ts +++ b/packages/web/src/ee/features/permissionSyncing/types.ts @@ -1,4 +1,4 @@ -export type IntegrationIdentityProviderState = { +export type LinkedAccountProviderState = { id: string; required: boolean; isLinked: boolean; diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts index 2e925f185..9a5153ff7 100644 --- a/packages/web/src/ee/features/sso/sso.ts +++ b/packages/web/src/ee/features/sso/sso.ts @@ -19,6 +19,8 @@ import { GCPIAPIdentityProviderConfig, GitHubIdentityProviderConfig, GitLabIdent const logger = createLogger('web-sso'); +const GITHUB_CLOUD_HOSTNAME = "github.com" + export const getEEIdentityProviders = async (): Promise => { const providers: IdentityProvider[] = []; @@ -30,89 +32,93 @@ export const getEEIdentityProviders = async (): Promise => { const providerConfig = identityProvider as GitHubIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); - const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? false}); + const baseUrl = providerConfig.baseUrl; + providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.accountLinkingRequired ?? false}); } if (identityProvider.provider === "gitlab") { const providerConfig = identityProvider as GitLabIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); - const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined; - providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.required ?? false}); + const baseUrl = providerConfig.baseUrl; + providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose, required: providerConfig.accountLinkingRequired ?? false}); } if (identityProvider.provider === "google") { const providerConfig = identityProvider as GoogleIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); - providers.push({ provider: createGoogleProvider(clientId, clientSecret), purpose: "sso"}); + providers.push({ provider: createGoogleProvider(clientId, clientSecret), purpose: providerConfig.purpose}); } if (identityProvider.provider === "okta") { const providerConfig = identityProvider as OktaIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push({ provider: createOktaProvider(clientId, clientSecret, issuer), purpose: "sso"}); + providers.push({ provider: createOktaProvider(clientId, clientSecret, issuer), purpose: providerConfig.purpose}); } if (identityProvider.provider === "keycloak") { const providerConfig = identityProvider as KeycloakIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: "sso" }); + providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: providerConfig.purpose }); } if (identityProvider.provider === "microsoft-entra-id") { const providerConfig = identityProvider as MicrosoftEntraIDIdentityProviderConfig; const clientId = await getTokenFromConfig(providerConfig.clientId); const clientSecret = await getTokenFromConfig(providerConfig.clientSecret); const issuer = await getTokenFromConfig(providerConfig.issuer); - providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: "sso" }); + providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: providerConfig.purpose }); } if (identityProvider.provider === "gcp-iap") { const providerConfig = identityProvider as GCPIAPIdentityProviderConfig; const audience = await getTokenFromConfig(providerConfig.audience); - providers.push({ provider: createGCPIAPProvider(audience), purpose: "sso" }); + providers.push({ provider: createGCPIAPProvider(audience), purpose: providerConfig.purpose }); } } - // @deprecate - if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { - providers.push({ provider: createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL), purpose: "sso" }); - } - - if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) { - providers.push({ provider: createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL), purpose: "sso" }); - } - - if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) { - providers.push({ provider: createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET), purpose: "sso" }); - } - - if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) { - providers.push({ provider: createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER), purpose: "sso" }); - } - - if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) { - providers.push({ provider: createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER), purpose: "sso" }); - } - - if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) { - providers.push({ provider: createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER), purpose: "sso" }); - } - - if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { - providers.push({ provider: createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE), purpose: "sso" }); + // @deprecate in favor of defining identity providers throught the identityProvider object in the config file. This was done to allow for more control over + // which identity providers are defined and their purpose. We've left this logic here to support backwards compat with deployments that expect these env vars, + // but this logic will be removed in the future + // We only go through this path if no identityProviders are defined in the config to prevent accidental duplication of providers + if (identityProviders.length == 0) { + if (env.AUTH_EE_GITHUB_CLIENT_ID && env.AUTH_EE_GITHUB_CLIENT_SECRET) { + providers.push({ provider: createGitHubProvider(env.AUTH_EE_GITHUB_CLIENT_ID, env.AUTH_EE_GITHUB_CLIENT_SECRET, env.AUTH_EE_GITHUB_BASE_URL), purpose: "sso" }); + } + + if (env.AUTH_EE_GITLAB_CLIENT_ID && env.AUTH_EE_GITLAB_CLIENT_SECRET) { + providers.push({ provider: createGitLabProvider(env.AUTH_EE_GITLAB_CLIENT_ID, env.AUTH_EE_GITLAB_CLIENT_SECRET, env.AUTH_EE_GITLAB_BASE_URL), purpose: "sso" }); + } + + if (env.AUTH_EE_GOOGLE_CLIENT_ID && env.AUTH_EE_GOOGLE_CLIENT_SECRET) { + providers.push({ provider: createGoogleProvider(env.AUTH_EE_GOOGLE_CLIENT_ID, env.AUTH_EE_GOOGLE_CLIENT_SECRET), purpose: "sso" }); + } + + if (env.AUTH_EE_OKTA_CLIENT_ID && env.AUTH_EE_OKTA_CLIENT_SECRET && env.AUTH_EE_OKTA_ISSUER) { + providers.push({ provider: createOktaProvider(env.AUTH_EE_OKTA_CLIENT_ID, env.AUTH_EE_OKTA_CLIENT_SECRET, env.AUTH_EE_OKTA_ISSUER), purpose: "sso" }); + } + + if (env.AUTH_EE_KEYCLOAK_CLIENT_ID && env.AUTH_EE_KEYCLOAK_CLIENT_SECRET && env.AUTH_EE_KEYCLOAK_ISSUER) { + providers.push({ provider: createKeycloakProvider(env.AUTH_EE_KEYCLOAK_CLIENT_ID, env.AUTH_EE_KEYCLOAK_CLIENT_SECRET, env.AUTH_EE_KEYCLOAK_ISSUER), purpose: "sso" }); + } + + if (env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID && env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET && env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER) { + providers.push({ provider: createMicrosoftEntraIDProvider(env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_ID, env.AUTH_EE_MICROSOFT_ENTRA_ID_CLIENT_SECRET, env.AUTH_EE_MICROSOFT_ENTRA_ID_ISSUER), purpose: "sso" }); + } + + if (env.AUTH_EE_GCP_IAP_ENABLED && env.AUTH_EE_GCP_IAP_AUDIENCE) { + providers.push({ provider: createGCPIAPProvider(env.AUTH_EE_GCP_IAP_AUDIENCE), purpose: "sso" }); + } } - + return providers; } const createGitHubProvider = (clientId: string, clientSecret: string, baseUrl?: string): Provider => { + const hostname = baseUrl ? new URL(baseUrl).hostname : GITHUB_CLOUD_HOSTNAME return GitHub({ clientId: clientId, clientSecret: clientSecret, - enterprise: { - baseUrl: baseUrl, - }, + ...(hostname === GITHUB_CLOUD_HOSTNAME ? { enterprise: { baseUrl: baseUrl } } : {}), // if this is set the provider expects GHE so we need this check authorization: { params: { scope: [ diff --git a/packages/web/src/features/chat/actions.ts b/packages/web/src/features/chat/actions.ts index 349c8bcc0..19ec9abd5 100644 --- a/packages/web/src/features/chat/actions.ts +++ b/packages/web/src/features/chat/actions.ts @@ -22,6 +22,7 @@ import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; import { createOpenRouter } from '@openrouter/ai-sdk-provider'; import { getTokenFromConfig } from "@sourcebot/crypto"; import { ChatVisibility, OrgRole, Prisma } from "@sourcebot/db"; +import { createLogger } from "@sourcebot/logger"; import { LanguageModel } from "@sourcebot/schemas/v3/languageModel.type"; import { Token } from "@sourcebot/schemas/v3/shared.type"; import { generateText, JSONValue, extractReasoningMiddleware, wrapLanguageModel } from "ai"; @@ -31,6 +32,8 @@ import { StatusCodes } from "http-status-codes"; import path from 'path'; import { LanguageModelInfo, SBChatMessage } from "./types"; +const logger = createLogger('chat-actions'); + export const createChat = async (domain: string) => sew(() => withAuth((userId) => withOrgMembership(userId, domain, async ({ org }) => { @@ -360,11 +363,15 @@ export const getConfiguredLanguageModelsInfo = async (): Promise => { - const config = await loadConfig(env.CONFIG_PATH); - return config.models ?? []; + try { + const config = await loadConfig(env.CONFIG_PATH); + return config.models ?? []; + } catch (error) { + logger.error('Failed to load language model configuration', error); + return []; + } } - export const _getAISDKLanguageModelAndOptions = async (config: LanguageModel): Promise<{ model: AISDKLanguageModelV2, providerOptions?: Record>, diff --git a/packages/web/src/lib/identityProviders.ts b/packages/web/src/lib/identityProviders.ts index d35cd2db7..dff90187d 100644 --- a/packages/web/src/lib/identityProviders.ts +++ b/packages/web/src/lib/identityProviders.ts @@ -3,7 +3,7 @@ import { getProviders } from "@/auth"; export interface IdentityProviderMetadata { id: string; name: string; - purpose: "sso" | "integration"; + purpose: "sso" | "account_linking"; required: boolean; } diff --git a/schemas/v3/identityProvider.json b/schemas/v3/identityProvider.json index 3eeeef969..de2e0d113 100644 --- a/schemas/v3/identityProvider.json +++ b/schemas/v3/identityProvider.json @@ -4,12 +4,13 @@ "definitions": { "GitHubIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "github" }, "purpose": { - "enum": ["sso", "integration"] + "enum": ["sso", "account_linking"] }, "clientId": { "$ref": "./shared.json#/definitions/Token" @@ -18,9 +19,17 @@ "$ref": "./shared.json#/definitions/Token" }, "baseUrl": { - "$ref": "./shared.json#/definitions/Token" - }, - "required": { + "type": "string", + "format": "url", + "default": "https://github.com", + "description": "The URL of the GitHub host. Defaults to https://github.com", + "examples": [ + "https://github.com", + "https://github.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" + }, + "accountLinkingRequired": { "type": "boolean", "default": false } @@ -29,12 +38,13 @@ }, "GitLabIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gitlab" }, "purpose": { - "enum": ["sso", "integration"] + "enum": ["sso", "account_linking"] }, "clientId": { "$ref": "./shared.json#/definitions/Token" @@ -43,21 +53,33 @@ "$ref": "./shared.json#/definitions/Token" }, "baseUrl": { - "$ref": "./shared.json#/definitions/Token" - }, - "required": { + "type": "string", + "format": "url", + "default": "https://gitlab.com", + "description": "The URL of the GitLab host. Defaults to https://gitlab.com", + "examples": [ + "https://gitlab.com", + "https://gitlab.example.com" + ], + "pattern": "^https?:\\/\\/[^\\s/$.?#].[^\\s]*$" + }, + "accountLinkingRequired": { "type": "boolean", - "default": false + "default": false } }, "required": ["provider", "purpose", "clientId", "clientSecret"] }, "GoogleIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "google" }, + "purpose": { + "const": "sso" + }, "clientId": { "$ref": "./shared.json#/definitions/Token" }, @@ -65,14 +87,18 @@ "$ref": "./shared.json#/definitions/Token" } }, - "required": ["provider", "clientId", "clientSecret"] + "required": ["provider", "purpose", "clientId", "clientSecret"] }, "OktaIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "okta" }, + "purpose": { + "const": "sso" + }, "clientId": { "$ref": "./shared.json#/definitions/Token" }, @@ -83,14 +109,18 @@ "$ref": "./shared.json#/definitions/Token" } }, - "required": ["provider", "clientId", "clientSecret", "issuer"] + "required": ["provider", "purpose", "clientId", "clientSecret", "issuer"] }, "KeycloakIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "keycloak" }, + "purpose": { + "const": "sso" + }, "clientId": { "$ref": "./shared.json#/definitions/Token" }, @@ -101,14 +131,18 @@ "$ref": "./shared.json#/definitions/Token" } }, - "required": ["provider", "clientId", "clientSecret", "issuer"] + "required": ["provider", "purpose", "clientId", "clientSecret", "issuer"] }, "MicrosoftEntraIDIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "microsoft-entra-id" }, + "purpose": { + "const": "sso" + }, "clientId": { "$ref": "./shared.json#/definitions/Token" }, @@ -119,19 +153,23 @@ "$ref": "./shared.json#/definitions/Token" } }, - "required": ["provider", "clientId", "clientSecret", "issuer"] + "required": ["provider", "purpose", "clientId", "clientSecret", "issuer"] }, "GCPIAPIdentityProviderConfig": { "type": "object", + "additionalProperties": false, "properties": { "provider": { "const": "gcp-iap" }, + "purpose": { + "const": "sso" + }, "audience": { "$ref": "./shared.json#/definitions/Token" } }, - "required": ["provider", "audience"] + "required": ["provider", "purpose", "audience"] } }, "oneOf": [ From cab5948473ffe175a9b5088819db88da5f9e7c17 Mon Sep 17 00:00:00 2001 From: msukkari Date: Tue, 4 Nov 2025 20:06:47 -0800 Subject: [PATCH 16/16] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24e03b1ad..b195c482c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Added - [Experimental][Sourcebot EE] Added GitLab permission syncing. [#585](https://github.com/sourcebot-dev/sourcebot/pull/585) +- [Sourcebot EE] Added external identity provider config and support for multiple accounts. [#595](https://github.com/sourcebot-dev/sourcebot/pull/595) ### Fixed - [ask sb] Fixed issue where reasoning tokens would appear in `text` content for openai compatible models. [#582](https://github.com/sourcebot-dev/sourcebot/pull/582)