diff --git a/backend/windmill-api-workspaces/src/workspaces.rs b/backend/windmill-api-workspaces/src/workspaces.rs index 42c1fb40af..faf19ffe26 100644 --- a/backend/windmill-api-workspaces/src/workspaces.rs +++ b/backend/windmill-api-workspaces/src/workspaces.rs @@ -2753,6 +2753,23 @@ fn cleanup_legacy_git_sync_settings_in_memory( #[cfg(not(feature = "enterprise"))] const CE_GIT_SYNC_MAX_USERS: i64 = 2; +/// Auto-pull is licensed per plan, not just per build: the poller only serves +/// Enterprise plans at runtime, so the save path must reject the setting too — +/// otherwise an EE binary without the plan could still register a webhook and +/// receive webhook-driven pulls. +#[cfg(feature = "enterprise")] +async fn check_auto_pull_license() -> Result<()> { + if !matches!( + windmill_common::ee_oss::get_license_plan().await, + windmill_common::ee_oss::LicensePlan::Enterprise + ) { + return Err(Error::BadRequest( + "Automatic pull from git requires an Enterprise license".to_string(), + )); + } + Ok(()) +} + #[cfg(feature = "enterprise")] async fn check_git_sync_access(_db: &DB, _w_id: &str) -> Result<()> { Ok(()) @@ -2886,6 +2903,14 @@ async fn edit_git_sync_config( "Automatic pull from git is an Enterprise Edition feature".to_string(), )); } + #[cfg(feature = "enterprise")] + if git_sync_settings + .repositories + .iter() + .any(|r| r.auto_pull.as_ref().is_some_and(|a| a.enabled)) + { + check_auto_pull_license().await?; + } // Preserve server-owned auto-pull state (webhook id/secret, synced sha, last // status) that the redacted GET response omits — otherwise a whole-config // save from the UI would drop the webhook secret (breaking delivery) or @@ -3083,6 +3108,15 @@ async fn edit_git_sync_repository( "Automatic pull from git is an Enterprise Edition feature".to_string(), )); } + #[cfg(feature = "enterprise")] + if new_config + .repository + .auto_pull + .as_ref() + .is_some_and(|a| a.enabled) + { + check_auto_pull_license().await?; + } // Promotion mode: EE only #[cfg(not(feature = "enterprise"))] diff --git a/backend/windmill-worker/src/result_processor.rs b/backend/windmill-worker/src/result_processor.rs index c009137f84..45b89bb338 100644 --- a/backend/windmill-worker/src/result_processor.rs +++ b/backend/windmill-worker/src/result_processor.rs @@ -920,6 +920,11 @@ fn git_sync_deploy_pr_head_branch( if !use_individual_branch { return None; } + // Mirrors the CLI's computeGitSyncDeployBranch: user/group objects are + // pushed to the base branch and never get their own wm_deploy branch. + if path_type == "user" || path_type == "group" { + return None; + } let git_ref = if !item_path.is_empty() { item_path } else { @@ -1866,6 +1871,26 @@ pub fn extract_error_value( mod git_sync_pr_tests { use super::{git_sync_deploy_pr_head_branch, git_sync_push_result_pushed}; + #[test] + fn user_and_group_items_get_no_promotion_branch() { + for path_type in ["user", "group"] { + assert_eq!( + git_sync_deploy_pr_head_branch( + "ws", + None, + None, + "main", + true, + false, + "u/someone", + "", + path_type + ), + None + ); + } + } + #[test] fn push_result_pushed_flag() { assert_eq!(