mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 00:04:10 +00:00
fix: define the credential facade for private builds without enterprise
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1xHmkxuxYb1GYvth1BS75
This commit is contained in:
co-authored by
Claude Opus 5
parent
6551d23642
commit
87b81bef37
@@ -1 +1 @@
|
||||
5d9cd2b60b286840d1647103f89cf7953b8b2065
|
||||
12224d76e0e75d0f7455ef0202e4b287567143a3
|
||||
@@ -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<Postgres>,
|
||||
_w_id: &str,
|
||||
|
||||
@@ -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<String>,
|
||||
/// 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,
|
||||
|
||||
@@ -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}
|
||||
<Alert type="error" title="Could not list projects" size="xs">{listError}</Alert>
|
||||
{/if}
|
||||
{#if projects.length > 0}
|
||||
{#if staleListing}
|
||||
<div class="text-xs font-normal text-secondary">
|
||||
The token changed. List the projects again to choose one it can reach.
|
||||
</div>
|
||||
{/if}
|
||||
{#if projects.length > 0 && !staleListing}
|
||||
<div class="flex flex-col gap-y-1">
|
||||
<div class="text-xs font-semibold text-emphasis">Project</div>
|
||||
<Select
|
||||
|
||||
@@ -641,6 +641,9 @@
|
||||
{:else if repo.credential.rotatable}
|
||||
Repository token expires on {repo.credential.expires_at}. Renewing it automatically
|
||||
requires an enterprise license.
|
||||
{:else if (repo.credential.scopes ?? []).some((s) => s === 'api' || s === 'self_rotate')}
|
||||
Repository token expires on {repo.credential.expires_at}. Windmill only renews a token it
|
||||
holds, and this repository authenticates with one it does not.
|
||||
{:else}
|
||||
Repository token expires on {repo.credential.expires_at}. Give it the api or self_rotate
|
||||
scope to let Windmill renew it automatically.
|
||||
|
||||
Reference in New Issue
Block a user