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 6d5e5a21..ab250218 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 00000000..0ebf9eb1 --- /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 89ed6be2..6570edb5 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 87a7eb27..c03a2015 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 c087a759..f743fa9a 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 00000000..32a0bc46 --- /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 00000000..5cea9cf4 --- /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 e49d998b..c4f4358d 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 eb2b412c..60ad4861 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 2fadfef4..c6923cd2 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 00000000..bb6c390f --- /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 3bb129b1..72c7e58d 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 27800d0c..544976d0 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 7accc065..0d12a5ed 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 bb6c390f..76e6c6ae 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 72c7e58d..392a2eb9 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 cc20c745..7071afb1 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 1cfc0252..a62d94c2 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 1d439c76..0f8505cb 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 98fc5b50..e87a1f6d 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 2680064b..1b71b7ae 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 0a5fdac3..2d4511c3 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 94197e01..26efe248 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 df78084a..f061d3b3 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 6d5e5a21..1e95a482 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 fab796de..e187f276 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 829d0254..85202242 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 48750ae1..10311eba 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 f236e3fe..f663ba47 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 1858eee8..49ea2ce6 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 2d1aea88..00000000 --- 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 1d322f44..4783aee6 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 89ed6be2..38351682 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 accfc95c..ebc1bc92 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 82ca9195..4087a944 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 de587935..aa0fbf55 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 75adc311..c6fa87ff 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 40637ff0..006a3bf2 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 ffe5f529..d8a72dff 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 4353c34e..9a1593d6 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 ab3eee3f..91493b0f 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 550d259d..7d4d617f 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 55bae70c..6063f7bd 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 8e8b1f26..8ecd7912 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 042ba8c7..3b98e0e0 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 4bb18549..3a9bace4 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 be5a064d..b474c0e0 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 00000000..1b2f8dc2 --- /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 93adb717..7f2c7fae 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 a37f2f3c..a4e9c304 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 87a7eb27..a6d1280c 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 c087a759..d0a4e34e 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 3b36fbed..f0d56085 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 b6ef68da..9c6c96f1 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 a7c857ce..a5de1b91 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 260d949d..cbd8d9d8 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 e0bcbc48..64872ab1 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 df31c465..0f62c980 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 1e1283ee..2e15067e 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 ec9e3046..afbedaf3 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 c29e1c08..d32ff6fe 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 4cb73c9b..980f2f9f 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 72d367e1..ee0cfd56 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 f25193b8..98a8d960 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 e49d998b..90e7c0ae 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 eb2b412c..75acc3d8 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 3bdb4c00..e3f72781 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 58b9aac6..48f5b83e 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 5ecacd44..44238cad 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 727de2be..23113f50 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 7c3a472a..895084e0 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 8367a4ba..ccac2e99 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 f92e2712..00000000 --- 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 92ed4df7..00000000 --- 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 02714f59..00000000 --- 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 d7f9368b..8f045305 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 0e9638c4..ad4e9f12 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 9fbcfd47..00000000 --- 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 67334c2a..0c9a79a2 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 6cc27833..573a7335 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 be2fdda9..a980a17c 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 d5c87665..35f38fb1 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 ec4a9f4f..c2002782 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 ab5b4e62..9d3b1ca9 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 baa6dae8..a290edd1 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 d4cc114c..aa387fdc 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 00000000..905730ef --- /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 8e362d74..0a3af5ec 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 d8a72dff..892e637b 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 00000000..4e849a4c --- /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 00000000..6c45243b --- /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 fee632d6..bf694f2c 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 d0f4ef0d..708052ca 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 0d12a5ed..8a6d8856 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 84d1228e..9d6f2734 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 195a8d17..df284589 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 1d1eb5e3..f24bb8f5 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 1535ec58..730ca610 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 b446c15f..d995fa9c 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 dc920596..8c2c76ff 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 544976d0..68a2501e 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 8a6d8856..55092032 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 ca2a6697..efcb54ff 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 905730ef..5105f3f1 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 0a3af5ec..5d043b95 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 4e849a4c..1d351539 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 6c45243b..5cac3a74 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 bf694f2c..3133915e 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 708052ca..e7ab4ee4 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 f7c1b56e..4eb454bd 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 895084e0..4ebfd552 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 b60a50a6..05f91006 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 ccac2e99..b0aa8f5b 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 00000000..49750a3a --- /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 00000000..a3cc04f2 --- /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 9d6f2734..442fb919 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 df284589..539bf781 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 f24bb8f5..b13e19fb 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 730ca610..2ce955c5 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 d995fa9c..33077a9b 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 8c2c76ff..fd00c87d 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 68a2501e..1cb0c6dc 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 00000000..29762de1 --- /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 00000000..522da946 --- /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 00000000..3a23d1d5 --- /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 00000000..14307506 --- /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 00000000..cad1d435 --- /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 00000000..1b3788e4 --- /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 00000000..d5b5ca86 --- /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 00000000..5e61e71a --- /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 55092032..579f7ceb 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 ad4e9f12..40d62cab 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 63eb6a47..b08685b2 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 3cd6e258..21bb97d5 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 efcb54ff..792e3fec 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 76e6c6ae..6216d270 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 5105f3f1..f96ad135 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 9ae3403c..04a8b3b5 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 792e3fec..dace28aa 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 f96ad135..c0cbab9e 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 06f02825..0bc6281b 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 10cd4487..9a3b9373 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 2a180b4f..541f0ca7 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 1d58a4a6..4da1b5e9 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 9c9365cb..aef3e6ac 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 05f91006..bfc530c1 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 49750a3a..00000000 --- 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 a3cc04f2..54f6c663 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 29762de1..ded04271 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 14307506..3d1d8339 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 00000000..43e948b1 --- /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 cad1d435..52859269 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 00000000..dcb94d2a --- /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 01cac3ad..3bdb87c7 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 3a2cb43f..441f4139 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 00000000..f8edb811 --- /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 272eab62..4b13fcaf 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 c0cbab9e..988cffcb 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 0bc6281b..d43562fa 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 9a3b9373..0dd3ddc4 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 4da1b5e9..a6bdd2f6 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 59ac61c4..08779d69 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 579f7ceb..2e925f18 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 dace28aa..d35cd2db 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 2c46f8c2..3eeeef96 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 3397dc81..24e03b1a 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 c3d54363..91328b37 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 f8edb811..af4f8e05 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 ee6a96e7..403f534f 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 0ebf9eb1..00000000 --- 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 988cffcb..30c172be 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 d43562fa..615c058a 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 32a0bc46..00000000 --- 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 5cea9cf4..00000000 --- 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 0dd3ddc4..708c3b4c 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 541f0ca7..31d7a9a8 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 a6bdd2f6..ee045243 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 aef3e6ac..0e88d8ab 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 38935953..a3079d7f 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 948171b1..d9c136c9 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 d9cfeb88..64dab588 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 08779d69..95667027 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 52859269..dd3aa531 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 85522712..766784dd 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 3b7fff88..8b326bdf 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 3a23d1d5..fa439473 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 9a7a65cb..ebd05ab9 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 dcb94d2a..f6ebef06 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 3bdb87c7..3fdc16e2 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 2e925f18..9a5153ff 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 349c8bcc..19ec9abd 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 d35cd2db..dff90187 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 3eeeef96..de2e0d11 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 24e03b1a..b195c482 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)