mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-11 20:05:25 +00:00
feedback
This commit is contained in:
parent
8e7bcc6459
commit
822c57af3f
28 changed files with 991 additions and 3785 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 `<sourcebot_deployment_url>/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
|
||||
---
|
||||
|
||||
<Note>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)</Note>
|
||||
|
||||
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`
|
||||
|
||||
---
|
||||
Sourcebot supports authentication using several different [external identity providers](/docs/configuration/idp) as well. These identity providers require an
|
||||
[enterprise license](/docs/license-key)
|
||||
|
|
@ -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.
|
|||
<Steps>
|
||||
<Step title="Register an Oauth Client">
|
||||
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)
|
||||
</Tab>
|
||||
<Tab title="GitHub OAuth App">
|
||||
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.
|
||||
|
||||
<Accordion title="instructions">
|
||||
<Steps>
|
||||
<Step title="Register an OAuth Application">
|
||||
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 `<sourcebot_url>/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.
|
||||
</Step>
|
||||
<Step title="Define environment variables">
|
||||
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`)
|
||||
</Step>
|
||||
<Step title="Define the identity provider config">
|
||||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
### Google
|
||||
|
||||
[Auth.js Google Provider Docs](https://authjs.dev/getting-started/providers/google)
|
||||
|
||||
A Google connection can be used for [authentication](/docs/configuration/auth).
|
||||
|
||||
<Accordion title="instructions">
|
||||
<Steps>
|
||||
<Step title="Register an OAuth Client">
|
||||
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 `<sourcebot_url>/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.
|
||||
</Step>
|
||||
<Step title="Define environment variables">
|
||||
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`)
|
||||
</Step>
|
||||
<Step title="Define the identity provider config">
|
||||
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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
### Okta
|
||||
|
||||
[Auth.js Okta Provider Docs](https://authjs.dev/getting-started/providers/okta)
|
||||
|
||||
An Okta connection can be used for [authentication](/docs/configuration/auth).
|
||||
|
||||
<Accordion title="instructions">
|
||||
<Steps>
|
||||
<Step title="Register an OAuth Application">
|
||||
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 `<sourcebot_url>/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.
|
||||
</Step>
|
||||
<Step title="Define environment variables">
|
||||
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`)
|
||||
</Step>
|
||||
<Step title="Define the identity provider config">
|
||||
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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
### Keycloak
|
||||
|
||||
[Auth.js Keycloak Provider Docs](https://authjs.dev/getting-started/providers/keycloak)
|
||||
|
||||
A Keycloak connection can be used for [authentication](/docs/configuration/auth).
|
||||
|
||||
<Accordion title="instructions">
|
||||
<Steps>
|
||||
<Step title="Register an OAuth Client">
|
||||
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 `<sourcebot_url>/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://<keycloak-domain>/realms/<realm-name>`) which you'll provide to Sourcebot.
|
||||
</Step>
|
||||
<Step title="Define environment variables">
|
||||
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`)
|
||||
</Step>
|
||||
<Step title="Define the identity provider config">
|
||||
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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
### 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).
|
||||
|
||||
<Accordion title="instructions">
|
||||
<Steps>
|
||||
<Step title="Register an OAuth Application">
|
||||
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 `<sourcebot_url>/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.
|
||||
</Step>
|
||||
<Step title="Define environment variables">
|
||||
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/<TENANT_ID>/v2.0`
|
||||
</Step>
|
||||
<Step title="Define the identity provider config">
|
||||
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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
</Accordion>
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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/<project-id>/secrets/<secret-name>/versions/<version-id>`. 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="min-h-screen flex flex-col items-center justify-center p-6">
|
||||
<LogoutEscapeHatch className="absolute top-0 right-0 p-6" />
|
||||
<div className="bg-red-50 border border-red-200 rounded-md p-6 max-w-md w-full text-center">
|
||||
<h2 className="text-lg font-semibold text-red-800 mb-2">An error occurred</h2>
|
||||
<p className="text-red-700 mb-1">
|
||||
{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."}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -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 (
|
||||
<div className="min-h-screen flex items-center justify-center p-6">
|
||||
<LogoutEscapeHatch className="absolute top-0 right-0 p-6" />
|
||||
<LinkAccounts integrationProviderStates={integrationProviderStates} callbackUrl={`/${domain}`}/>
|
||||
<LinkAccounts linkedAccountProviderStates={linkedAccountProviderStates} callbackUrl={`/${domain}`}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <LinkedAccountsSettings />;
|
||||
|
|
|
|||
|
|
@ -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<string, LinkedAccountToken>;
|
||||
|
||||
declare module 'next-auth' {
|
||||
interface Session {
|
||||
user: {
|
||||
id: string;
|
||||
} & DefaultSession['user'];
|
||||
integrationProviderErrors?: Record<string, string>;
|
||||
linkedAccountProviderErrors?: Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'next-auth/jwt' {
|
||||
interface JWT {
|
||||
userId: string;
|
||||
integrationTokens?: Record<string, {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
expiresAt: number;
|
||||
error?: string;
|
||||
}>;
|
||||
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<string, string> = {};
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
|
@ -42,12 +42,12 @@ export const LinkAccounts = ({ integrationProviderStates, callbackUrl }: LinkAcc
|
|||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
{integrationProviderStates
|
||||
{linkedAccountProviderStates
|
||||
.sort((a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0))
|
||||
.map(state => (
|
||||
<IntegrationProviderCard
|
||||
<LinkedAccountProviderCard
|
||||
key={state.id}
|
||||
integrationProviderState={state}
|
||||
linkedAccountProviderState={state}
|
||||
callbackUrl={callbackUrl}
|
||||
/>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -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({
|
|||
<div className="flex flex-col gap-1.5 min-w-0 flex-1">
|
||||
<CardTitle className="text-base">
|
||||
<ProviderInfo
|
||||
providerId={integrationProviderState.id}
|
||||
required={integrationProviderState.required}
|
||||
providerId={linkedAccountProviderState.id}
|
||||
required={linkedAccountProviderState.required}
|
||||
showBadge={true}
|
||||
/>
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
<div className="flex flex-col gap-1.5">
|
||||
{integrationProviderState.isLinked? (
|
||||
{linkedAccountProviderState.isLinked? (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex items-center gap-1.5">
|
||||
<Check className="h-3.5 w-3.5 text-green-600 dark:text-green-500" />
|
||||
|
|
@ -50,11 +50,11 @@ export function IntegrationProviderCard({
|
|||
Connected
|
||||
</span>
|
||||
</div>
|
||||
{integrationProviderState.linkedAccountId && (
|
||||
{linkedAccountProviderState.linkedAccountId && (
|
||||
<>
|
||||
<span className="text-muted-foreground">•</span>
|
||||
<span className="text-muted-foreground font-mono truncate">
|
||||
{integrationProviderState.linkedAccountId}
|
||||
{linkedAccountProviderState.linkedAccountId}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -67,7 +67,7 @@ export function IntegrationProviderCard({
|
|||
</span>
|
||||
</div>
|
||||
)}
|
||||
{integrationProviderState.error && (
|
||||
{linkedAccountProviderState.error && (
|
||||
<div className="flex items-center gap-1.5">
|
||||
<AlertCircle className="h-3.5 w-3.5 text-destructive" />
|
||||
<span className="text-destructive font-medium">
|
||||
|
|
@ -80,14 +80,14 @@ export function IntegrationProviderCard({
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex-shrink-0 ml-4">
|
||||
{integrationProviderState.isLinked? (
|
||||
{linkedAccountProviderState.isLinked? (
|
||||
<UnlinkButton
|
||||
provider={integrationProviderState.id}
|
||||
provider={linkedAccountProviderState.id}
|
||||
providerName={providerInfo.displayName}
|
||||
/>
|
||||
) : (
|
||||
<LinkButton
|
||||
provider={integrationProviderState.id}
|
||||
provider={linkedAccountProviderState.id}
|
||||
callbackUrl={callbackUrl ?? defaultCallbackUrl}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -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 <div className="min-h-screen flex flex-col items-center justify-center p-6">
|
||||
<LogoutEscapeHatch className="absolute top-0 right-0 p-6" />
|
||||
<div className="bg-red-50 border border-red-200 rounded-md p-6 max-w-md w-full text-center">
|
||||
<h2 className="text-lg font-semibold text-red-800 mb-2">An error occurred</h2>
|
||||
<p className="text-red-700 mb-1">
|
||||
{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."}
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -30,7 +30,7 @@ export async function LinkedAccountsSettings() {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
{integrationProviderStates.length === 0 ? (
|
||||
{linkedAccountProviderStates.length === 0 ? (
|
||||
<Card>
|
||||
<CardContent className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<div className="rounded-full bg-muted p-3 mb-4">
|
||||
|
|
@ -44,13 +44,13 @@ export async function LinkedAccountsSettings() {
|
|||
</Card>
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{integrationProviderStates
|
||||
{linkedAccountProviderStates
|
||||
.sort((a, b) => (b.required ? 1 : 0) - (a.required ? 1 : 0))
|
||||
.map((state) => {
|
||||
return (
|
||||
<IntegrationProviderCard
|
||||
<LinkedAccountProviderCard
|
||||
key={state.id}
|
||||
integrationProviderState={state}
|
||||
linkedAccountProviderState={state}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -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
|
|||
<Image
|
||||
src={icon.src}
|
||||
alt={displayName}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
className={`${sizes.icon} ${icon.className || ''}`}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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<string, IntegrationToken>;
|
||||
|
||||
export async function refreshIntegrationTokens(
|
||||
currentTokens: IntegrationTokensMap | undefined,
|
||||
userId: string
|
||||
): Promise<IntegrationTokensMap> {
|
||||
export async function refreshLinkedAccountTokens(
|
||||
currentTokens: LinkedAccountTokensMap | undefined
|
||||
): Promise<LinkedAccountTokensMap> {
|
||||
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;
|
||||
// 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}`);
|
||||
return null;
|
||||
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.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 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;
|
||||
logger.error(`All provider configs failed for: ${provider}`);
|
||||
return null;
|
||||
} catch (error) {
|
||||
logger.error(`Error refreshing ${provider} token:`, error);
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export type IntegrationIdentityProviderState = {
|
||||
export type LinkedAccountProviderState = {
|
||||
id: string;
|
||||
required: boolean;
|
||||
isLinked: boolean;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import { GCPIAPIdentityProviderConfig, GitHubIdentityProviderConfig, GitLabIdent
|
|||
|
||||
const logger = createLogger('web-sso');
|
||||
|
||||
const GITHUB_CLOUD_HOSTNAME = "github.com"
|
||||
|
||||
export const getEEIdentityProviders = async (): Promise<IdentityProvider[]> => {
|
||||
const providers: IdentityProvider[] = [];
|
||||
|
||||
|
|
@ -30,89 +32,93 @@ export const getEEIdentityProviders = async (): Promise<IdentityProvider[]> => {
|
|||
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" });
|
||||
}
|
||||
// @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_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_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_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_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_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" });
|
||||
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: [
|
||||
|
|
|
|||
|
|
@ -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<LanguageModelIn
|
|||
* or pass the result of calling this function to the client.
|
||||
*/
|
||||
export const _getConfiguredLanguageModelsFull = async (): Promise<LanguageModel[]> => {
|
||||
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<string, Record<string, JSONValue>>,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { getProviders } from "@/auth";
|
|||
export interface IdentityProviderMetadata {
|
||||
id: string;
|
||||
name: string;
|
||||
purpose: "sso" | "integration";
|
||||
purpose: "sso" | "account_linking";
|
||||
required: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
"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
|
||||
}
|
||||
|
|
@ -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,9 +53,17 @@
|
|||
"$ref": "./shared.json#/definitions/Token"
|
||||
},
|
||||
"baseUrl": {
|
||||
"$ref": "./shared.json#/definitions/Token"
|
||||
"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
|
||||
}
|
||||
|
|
@ -54,10 +72,14 @@
|
|||
},
|
||||
"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": [
|
||||
|
|
|
|||
Loading…
Reference in a new issue