From 544ef33d6d0d0f3d88cec607a31f45172ea82345 Mon Sep 17 00:00:00 2001 From: Ralf Lang Date: Tue, 3 Mar 2026 19:23:11 +0100 Subject: [PATCH 1/4] fix(ci): respect COMPONENTS_PHAR_URL environment variable in bootstrap script The bootstrap template was hardcoding the PHAR URL instead of respecting the environment variable passed from the workflow. Changed line 14 from: COMPONENTS_PHAR_URL="{{COMPONENTS_PHAR_URL}}" To: COMPONENTS_PHAR_URL="${COMPONENTS_PHAR_URL:-{{COMPONENTS_PHAR_URL}}}" This allows the workflow to pass the organization variable value while maintaining a fallback default. Without this fix, the org variable COMPONENTS_PHAR_URL is ignored and the hardcoded default is always used. --- data/ci/bootstrap-github.sh.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/ci/bootstrap-github.sh.template b/data/ci/bootstrap-github.sh.template index 249a981e..0dda80a5 100644 --- a/data/ci/bootstrap-github.sh.template +++ b/data/ci/bootstrap-github.sh.template @@ -11,7 +11,7 @@ set -o pipefail # Configuration BOOTSTRAP_PHP_VERSION="{{PHP_VERSION}}" -COMPONENTS_PHAR_URL="{{COMPONENTS_PHAR_URL}}" +COMPONENTS_PHAR_URL="${COMPONENTS_PHAR_URL:-{{COMPONENTS_PHAR_URL}}}" COMPONENT_NAME="{{COMPONENT_NAME}}" WORK_DIR="{{WORK_DIR}}" From 989ccc683ab08570bf355022870df689c2a4102b Mon Sep 17 00:00:00 2001 From: Ralf Lang Date: Tue, 3 Mar 2026 19:24:51 +0100 Subject: [PATCH 2/4] fix(ci): use 'help' command instead of '--version' for PHAR validation The horde-components PHAR does not support --version flag (it requires --version-part argument). This caused the bootstrap script to always fail when validating the downloaded PHAR. Changed validation from: php "$COMPONENTS_PHAR" --version &> /dev/null To: php "$COMPONENTS_PHAR" help &> /dev/null The help command works without arguments and validates that the PHAR is executable and functional. Also removed the redundant --version call after download that would also fail. --- data/ci/bootstrap-github.sh.template | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/ci/bootstrap-github.sh.template b/data/ci/bootstrap-github.sh.template index 0dda80a5..50f547d3 100644 --- a/data/ci/bootstrap-github.sh.template +++ b/data/ci/bootstrap-github.sh.template @@ -98,13 +98,12 @@ if ! curl -sS -L -o "$COMPONENTS_PHAR" "$COMPONENTS_PHAR_URL"; then fi # Validate it's a valid phar -if ! php "$COMPONENTS_PHAR" --version &> /dev/null; then +if ! php "$COMPONENTS_PHAR" help &> /dev/null; then log_error "Downloaded phar is not valid or not executable" exit 1 fi log_info "horde-components.phar downloaded successfully" -php "$COMPONENTS_PHAR" --version # Stage 4: Handoff to PHP (horde-components ci setup) log_info "Bootstrap complete. Handing off to horde-components ci setup" From 51fbf117b0ea0748fb38ea80bd10e5b7dd661746 Mon Sep 17 00:00:00 2001 From: Ralf Lang Date: Tue, 3 Mar 2026 19:25:57 +0100 Subject: [PATCH 3/4] fix(ci): use --ci-mode instead of --mode in bootstrap script --- data/ci/bootstrap-github.sh.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/ci/bootstrap-github.sh.template b/data/ci/bootstrap-github.sh.template index 50f547d3..61869fbb 100644 --- a/data/ci/bootstrap-github.sh.template +++ b/data/ci/bootstrap-github.sh.template @@ -109,7 +109,7 @@ log_info "horde-components.phar downloaded successfully" log_info "Bootstrap complete. Handing off to horde-components ci setup" php "$COMPONENTS_PHAR" ci setup \ - --mode=github \ + --ci-mode=github \ --work-dir="$WORK_DIR" \ --component="$COMPONENT_NAME" From e22316ff4f621c2180f92dab3269d2c9075741f8 Mon Sep 17 00:00:00 2001 From: Ralf Lang Date: Tue, 3 Mar 2026 19:30:31 +0100 Subject: [PATCH 4/4] fix(ci): skip sudo prefix when running as root user Add isRoot() method to detect if running as root (euid 0) and cache the result. When running as root, skip the 'sudo' prefix in all privileged commands. This fixes CI execution in GitHub Actions where the runner process runs as root and doesn't need sudo to execute privileged operations. Changes: - Add isRoot() static method with cached result - Update canRunPasswordless() to return true if root - Update addPpa() to skip sudo if root - Update installPhp() to skip sudo if root - Update installExtension() to skip sudo if root - Update isPhpInstalled() to skip sudo if root Without this fix, all sudo commands fail in GitHub Actions because the helper script is called with sudo when already running as root. --- src/Ci/Setup/SudoHelper.php | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/Ci/Setup/SudoHelper.php b/src/Ci/Setup/SudoHelper.php index b8591065..cb3ca813 100644 --- a/src/Ci/Setup/SudoHelper.php +++ b/src/Ci/Setup/SudoHelper.php @@ -35,6 +35,24 @@ class SudoHelper */ private const HELPER_SCRIPT = '/usr/local/bin/horde-ci-sudo-helper'; + /** + * Cached result of isRoot() check. + */ + private static ?bool $isRoot = null; + + /** + * Check if running as root user. + * + * @return bool + */ + public static function isRoot(): bool + { + if (self::$isRoot === null) { + self::$isRoot = posix_geteuid() === 0; + } + return self::$isRoot; + } + /** * Check if sudo helper is available. * @@ -52,6 +70,11 @@ public static function isAvailable(): bool */ public static function canRunPasswordless(): bool { + // Root doesn't need sudo + if (self::isRoot()) { + return true; + } + if (!self::isAvailable()) { return false; } @@ -72,7 +95,8 @@ public static function addPpa(): bool throw new Exception('Sudo helper not found: ' . self::HELPER_SCRIPT); } - $command = 'sudo ' . escapeshellarg(self::HELPER_SCRIPT) . ' add-ppa 2>&1'; + $sudo = self::isRoot() ? '' : 'sudo '; + $command = $sudo . escapeshellarg(self::HELPER_SCRIPT) . ' add-ppa 2>&1'; $output = []; $exitCode = 0; exec($command, $output, $exitCode); @@ -93,8 +117,10 @@ public static function installPhp(string $version): bool throw new Exception('Sudo helper not found: ' . self::HELPER_SCRIPT); } + $sudo = self::isRoot() ? '' : 'sudo '; $command = sprintf( - 'sudo %s install-php %s 2>&1', + '%s%s install-php %s 2>&1', + $sudo, escapeshellarg(self::HELPER_SCRIPT), escapeshellarg($version) ); @@ -120,8 +146,10 @@ public static function installExtension(string $phpVersion, string $extension): throw new Exception('Sudo helper not found: ' . self::HELPER_SCRIPT); } + $sudo = self::isRoot() ? '' : 'sudo '; $command = sprintf( - 'sudo %s install-extension %s %s 2>&1', + '%s%s install-extension %s %s 2>&1', + $sudo, escapeshellarg(self::HELPER_SCRIPT), escapeshellarg($phpVersion), escapeshellarg($extension) @@ -147,8 +175,10 @@ public static function isPhpInstalled(string $version): bool return file_exists("/usr/bin/php{$version}"); } + $sudo = self::isRoot() ? '' : 'sudo '; $command = sprintf( - 'sudo %s check-php %s 2>&1', + '%s%s check-php %s 2>&1', + $sudo, escapeshellarg(self::HELPER_SCRIPT), escapeshellarg($version) );