From a317cf302dc509a8eafa96915fbd6807b206cede Mon Sep 17 00:00:00 2001 From: hugocasa Date: Tue, 30 Jun 2026 18:23:08 +0200 Subject: [PATCH] fix(git-sync): poll app-backed repos in auto/polling mode The auto-pull poller skipped app-backed repos (the ls-remote head check can't authenticate a tokenless URL), so auto- and polling-mode app repos never synced when their webhook wasn't live. Wire the poller to fetch the head via the GitHub API for app repos and reconcile. Bump the EE ref. Co-Authored-By: Claude Opus 4.8 --- backend/ee-repo-ref.txt | 2 +- backend/src/monitor.rs | 32 +++++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index a1fd44058e..b324a3859e 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -9b63de906b4d64b79ae29a3e78a99f508f9ec285 +520325a09bd41a20ae61ccd54c155aff66484ccd diff --git a/backend/src/monitor.rs b/backend/src/monitor.rs index aed9a30be3..dbb71b5808 100644 --- a/backend/src/monitor.rs +++ b/backend/src/monitor.rs @@ -3127,13 +3127,40 @@ async fn poll_git_auto_pull_inner(db: &Pool) -> error::Result<()> { continue; } - match windmill_store::resources::get_git_repo_head_for_autopull( + let head = match windmill_store::resources::get_git_repo_head_for_autopull( db, &row.workspace_id, &repo.git_repo_resource_path, ) .await { + Ok(Some(h)) => Ok(Some(h)), + // App-backed repos store a tokenless URL, so the ls-remote head + // check can't authenticate and returns None. Poll the head over + // the GitHub API with a minted installation token instead. This + // is the polling fallback/safety-net for auto- and polling-mode + // app repos whose webhook isn't live (unreachable instance, + // missing permission, or a dropped delivery). `webhook`-mode + // repos are skipped above and stay webhook-only. + Ok(None) => { + #[cfg(feature = "enterprise")] + { + windmill_common::git_sync_ee::get_app_repo_head_for_autopull( + db, + &row.workspace_id, + &repo.git_repo_resource_path, + ) + .await + } + #[cfg(not(feature = "enterprise"))] + { + Ok(None) + } + } + Err(e) => Err(e), + }; + + match head { Ok(Some((git_ref, sha))) => { // Shared reconcile (also used by the webhook receiver): // checks should_pull, enqueues, and records status/failure. @@ -3153,7 +3180,6 @@ async fn poll_git_auto_pull_inner(db: &Pool) -> error::Result<()> { ); } } - // GitHub-App repo: synced via webhook (phase 2), nothing to poll. Ok(None) => {} Err(e) => { windmill_git_sync::record_auto_pull_failure( @@ -3161,7 +3187,7 @@ async fn poll_git_auto_pull_inner(db: &Pool) -> error::Result<()> { &row.workspace_id, &repo.git_repo_resource_path, &auto_pull.last_synced_sha, - format!("ls-remote failed: {e}"), + format!("head check failed: {e}"), ) .await; }