diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 608773d2df..777436b1d2 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -5d9cd2b60b286840d1647103f89cf7953b8b2065 \ No newline at end of file +12224d76e0e75d0f7455ef0202e4b287567143a3 \ No newline at end of file diff --git a/backend/windmill-common/src/git_sync_oss.rs b/backend/windmill-common/src/git_sync_oss.rs index 8b9062ec5a..79f282d927 100644 --- a/backend/windmill-common/src/git_sync_oss.rs +++ b/backend/windmill-common/src/git_sync_oss.rs @@ -1,7 +1,7 @@ #[cfg(feature = "private")] #[allow(unused)] pub use crate::git_sync_ee::*; -#[cfg(not(feature = "private"))] +#[cfg(not(all(feature = "private", feature = "enterprise")))] use sqlx::{Pool, Postgres}; use url::Url; @@ -17,7 +17,11 @@ pub async fn get_github_app_token_internal( /// Server-held git credentials are an enterprise feature, so on this build a /// repository URL authenticates with whatever it already carries. -#[cfg(not(feature = "private"))] +/// +/// Gated on the pair rather than on `private` alone: `private` does not imply +/// `enterprise`, and the callers are plain (no `#[cfg]`), so a build with one +/// and not the other would find neither this nor the enterprise definition. +#[cfg(not(all(feature = "private", feature = "enterprise")))] pub async fn with_stored_credential( _db: &Pool, _w_id: &str, diff --git a/backend/windmill-common/src/workspaces.rs b/backend/windmill-common/src/workspaces.rs index 085ac7f695..cbd656fb2a 100644 --- a/backend/windmill-common/src/workspaces.rs +++ b/backend/windmill-common/src/workspaces.rs @@ -441,8 +441,11 @@ pub struct GitCredentialStatus { /// different credential here", which look identical at the API otherwise. #[serde(default, skip_serializing_if = "Option::is_none")] pub token_fingerprint: Option, - /// Rotation needs both a scope that permits it (`api` or `self_rotate`) and a - /// URL Windmill can write back to. `scopes` says which of the two is missing. + /// Whether Windmill renews this credential itself. That needs a scope which + /// permits it (`api` or `self_rotate`) and a credential this workspace holds: + /// a token carried in the repository URL is the operator's to manage, and one + /// resolved from an ancestor is the ancestor's, so neither is renewed here. + /// `scopes` therefore only tells the scope half apart. pub rotatable: bool, /// Unix timestamp (seconds) of the last check. pub checked_at: i64, diff --git a/frontend/src/lib/components/GitLabIntegration.svelte b/frontend/src/lib/components/GitLabIntegration.svelte index 7ad9b4fcef..4ee286c899 100644 --- a/frontend/src/lib/components/GitLabIntegration.svelte +++ b/frontend/src/lib/components/GitLabIntegration.svelte @@ -41,6 +41,10 @@ let listError: string | undefined = $state(undefined) let applying = $state(false) let applyError: string | undefined = $state(undefined) + /** The token the current listing was made with. Editing the token afterwards + * leaves projects on screen that were never checked against it, and applying + * would store the new token for a project chosen under the old one. */ + let listedToken = $state('') // Shown alongside the GitHub App button and on the same terms, so the two // read as one choice rather than one option and one absence. @@ -56,6 +60,7 @@ let enabled = $derived(!!$enterpriseLicense) let project = $derived(projects.find((p) => p.path_with_namespace === selectedProject)) + let staleListing = $derived(projects.length > 0 && token !== listedToken) async function listProjects() { if (!ws) return @@ -66,6 +71,7 @@ workspace: ws, requestBody: { base_url: baseUrl, token, search: search || undefined } }) + listedToken = token selectedProject = projects[0]?.path_with_namespace if (projects.length === 0) { listError = 'The token can see no project with at least the Developer role' @@ -80,7 +86,7 @@ } async function apply(close: (_: any) => void) { - if (!project || !token || applying) return + if (!project || !token || applying || staleListing) return const chosen = project const url = chosen.http_url_to_repo applying = true @@ -178,7 +184,12 @@ {#if listError} {listError} {/if} - {#if projects.length > 0} + {#if staleListing} +
+ The token changed. List the projects again to choose one it can reach. +
+ {/if} + {#if projects.length > 0 && !staleListing}
Project