diff --git a/backend/.sqlx/query-14bc9dd1d02a3d121297509beacc27f3c29d1b3877c1f2e7c206f0e36ef18701.json b/backend/.sqlx/query-14bc9dd1d02a3d121297509beacc27f3c29d1b3877c1f2e7c206f0e36ef18701.json new file mode 100644 index 0000000000..6310017f18 --- /dev/null +++ b/backend/.sqlx/query-14bc9dd1d02a3d121297509beacc27f3c29d1b3877c1f2e7c206f0e36ef18701.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n (elem->>'installation_id')::bigint as installation_id,\n elem->>'account_id' as account_id,\n elem->>'github_base_url' as github_base_url,\n COALESCE((elem->>'provisioned_by_admin')::bool, false) as \"provisioned_by_admin!\"\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE workspace_id = $1\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "installation_id", + "type_info": "Int8" + }, + { + "ordinal": 1, + "name": "account_id", + "type_info": "Text" + }, + { + "ordinal": 2, + "name": "github_base_url", + "type_info": "Text" + }, + { + "ordinal": 3, + "name": "provisioned_by_admin!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null, + null, + null, + null + ] + }, + "hash": "14bc9dd1d02a3d121297509beacc27f3c29d1b3877c1f2e7c206f0e36ef18701" +} diff --git a/backend/.sqlx/query-2f166b5575a614b028c3130fc5089353bef40f1cccf31b7775d0e9a800425f4d.json b/backend/.sqlx/query-2f166b5575a614b028c3130fc5089353bef40f1cccf31b7775d0e9a800425f4d.json new file mode 100644 index 0000000000..5964de4111 --- /dev/null +++ b/backend/.sqlx/query-2f166b5575a614b028c3130fc5089353bef40f1cccf31b7775d0e9a800425f4d.json @@ -0,0 +1,23 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT COALESCE((elem->>'provisioned_by_admin')::bool, false) as \"is_admin!\"\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE workspace_id = $1\n AND (elem->>'installation_id')::bigint = $2\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "is_admin!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [ + null + ] + }, + "hash": "2f166b5575a614b028c3130fc5089353bef40f1cccf31b7775d0e9a800425f4d" +} diff --git a/backend/.sqlx/query-3c42a56d0ffe39ad217f2ee603431637bcb22c6e713a21bdb83204de9cf383d7.json b/backend/.sqlx/query-3c42a56d0ffe39ad217f2ee603431637bcb22c6e713a21bdb83204de9cf383d7.json new file mode 100644 index 0000000000..83a2c7bfc6 --- /dev/null +++ b/backend/.sqlx/query-3c42a56d0ffe39ad217f2ee603431637bcb22c6e713a21bdb83204de9cf383d7.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "SELECT EXISTS(SELECT 1 FROM workspace_settings WHERE workspace_id = $1)", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "exists", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Text" + ] + }, + "nullable": [ + null + ] + }, + "hash": "3c42a56d0ffe39ad217f2ee603431637bcb22c6e713a21bdb83204de9cf383d7" +} diff --git a/backend/.sqlx/query-f5e98ff83301b89f33e4454ae944da1977030cf2db9dadd372188902bb23062f.json b/backend/.sqlx/query-f5e98ff83301b89f33e4454ae944da1977030cf2db9dadd372188902bb23062f.json new file mode 100644 index 0000000000..ac592bafbe --- /dev/null +++ b/backend/.sqlx/query-f5e98ff83301b89f33e4454ae944da1977030cf2db9dadd372188902bb23062f.json @@ -0,0 +1,34 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n workspace_id,\n (elem->>'installation_id')::bigint as \"installation_id!\",\n COALESCE((elem->>'provisioned_by_admin')::bool, false) as \"provisioned_by_admin!\"\n FROM workspace_settings,\n LATERAL jsonb_array_elements(git_app_installations) AS elem\n WHERE (elem->>'installation_id')::bigint = ANY($1)\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "workspace_id", + "type_info": "Varchar" + }, + { + "ordinal": 1, + "name": "installation_id!", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "provisioned_by_admin!", + "type_info": "Bool" + } + ], + "parameters": { + "Left": [ + "Int8Array" + ] + }, + "nullable": [ + false, + null, + null + ] + }, + "hash": "f5e98ff83301b89f33e4454ae944da1977030cf2db9dadd372188902bb23062f" +} diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 1a1930d96e..1e357752b5 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -14315067c083d3361512de621b12e41dbe3b017d +da5189cf69a453de3855057f41be0d84e5910707 diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index e8b1459e20..e2c8cfad4d 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -2574,6 +2574,104 @@ paths: - app_slug - client_id + /github_app/ghes/discover: + get: + summary: Discover GHES App installations + description: | + Lists every installation the configured self-managed GitHub App can see, + annotated with the workspaces in this Windmill instance the + installation is currently assigned to. Super-admin only. + operationId: discoverGhesInstallations + tags: + - Git Sync + responses: + "200": + description: Discovered installations + content: + application/json: + schema: + type: array + items: + type: object + required: + - installation_id + - account_id + - assigned_workspaces + properties: + installation_id: + type: integer + format: int64 + account_id: + type: string + description: GitHub login of the installation's account (org or user) + assigned_workspaces: + type: array + items: + type: object + required: + - workspace_id + - provisioned_by_admin + properties: + workspace_id: + type: string + provisioned_by_admin: + type: boolean + + /github_app/ghes/assign: + post: + summary: Assign GHES installation to a workspace + description: | + Assigns a discovered GHES App installation to a workspace. The resulting + installation is marked as admin-provisioned, so workspace admins cannot + remove it. Super-admin only. + operationId: assignGhesInstallation + tags: + - Git Sync + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - workspace_id + - installation_id + properties: + workspace_id: + type: string + installation_id: + type: integer + format: int64 + responses: + "200": + description: Installation assigned + + /github_app/ghes/assign/{workspace_id}/{installation_id}: + delete: + summary: Unassign GHES installation from a workspace + description: | + Removes an installation (admin-provisioned or otherwise) from a + workspace. Super-admin only. Does not affect the installation on the + GitHub side. + operationId: unassignGhesInstallation + tags: + - Git Sync + parameters: + - name: workspace_id + in: path + required: true + schema: + type: string + - name: installation_id + in: path + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: Installation unassigned + /users/accept_invite: post: summary: accept invite to workspace @@ -27823,6 +27921,13 @@ components: error: type: string description: Error message if token retrieval failed + github_base_url: + type: string + nullable: true + description: Set for self-managed (GHES) installs. Cloud installs omit this field. + provisioned_by_admin: + type: boolean + description: True when the installation was assigned by the instance super-admin from instance settings. Workspace admins cannot remove these. required: - installation_id - account_id diff --git a/frontend/src/lib/components/GitHubAppIntegration.svelte b/frontend/src/lib/components/GitHubAppIntegration.svelte index 7b35dbf84c..7aa136b072 100644 --- a/frontend/src/lib/components/GitHubAppIntegration.svelte +++ b/frontend/src/lib/components/GitHubAppIntegration.svelte @@ -295,13 +295,21 @@ {#each githubState.workspaceGithubInstallations as installation (`current-${installation.installation_id}-${installation.workspace_id}`)}
Import installation from other instance:
-+ Assign installations of the configured GitHub App to specific workspaces so workspace users + don't need GitHub permissions to set up sync. Click Refresh to load installations + the App can see (save the config above first if you haven't). +
+ + {#if discoveryError} +{discoveryError}
+ {:else if loadingDiscovery && discovered.length === 0} ++ The configured GitHub App has no installations yet. Install it on a GitHub account, then + click Refresh. +
+ {:else} +
+ GitHub account
+ windmill-labs). A GitHub App installation is always scoped to exactly
+ one account.
+ |
+ Installation ID | +Assigned to | ++ |
|---|---|---|---|
| {install.account_id} | +{install.installation_id} | +
+ {#if install.assigned_workspaces.length === 0}
+ —
+ {:else}
+
+ {#each install.assigned_workspaces as assignment (assignment.workspace_id)}
+
+ {assignment.workspace_id}
+
+
+ {/each}
+
+ {/if}
+ |
+
+
+
+
+
+
+
+ |
+