Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package kargo-cli for openSUSE:Factory 
checked in at 2026-01-19 18:37:15
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/kargo-cli (Old)
 and      /work/SRC/openSUSE:Factory/.kargo-cli.new.1928 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "kargo-cli"

Mon Jan 19 18:37:15 2026 rev:39 rq:1327992 version:1.8.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/kargo-cli/kargo-cli.changes      2025-11-26 
17:18:27.681845611 +0100
+++ /work/SRC/openSUSE:Factory/.kargo-cli.new.1928/kargo-cli.changes    
2026-01-19 18:41:25.530301648 +0100
@@ -1,0 +2,15 @@
+Mon Jan 19 06:50:39 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.8.6:
+  This release contains no code changes compared to v1.8.5. It has
+  been retagged to address CI pipeline issues in the release
+  process.
+- Update to version 1.8.5:
+  * chore(backport release-1.8): chore(deps): bump
+    github.com/expr-lang/expr from 1.17.6 to 1.17.7 (#5515)
+  * chore(backport release-1.8): chore: port conflict for
+    development clusters (#5493)
+  * chore(backport release-1.8): docs: update CLI auth callback URL
+    to use HTTP (#5441)
+
+-------------------------------------------------------------------

Old:
----
  kargo-cli-1.8.4.obscpio

New:
----
  kargo-cli-1.8.6.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ kargo-cli.spec ++++++
--- /var/tmp/diff_new_pack.GxK0yN/_old  2026-01-19 18:41:26.554344019 +0100
+++ /var/tmp/diff_new_pack.GxK0yN/_new  2026-01-19 18:41:26.554344019 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package kargo-cli
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %define executable_name kargo
 
 Name:           kargo-cli
-Version:        1.8.4
+Version:        1.8.6
 Release:        0
 Summary:        CLI for the Kubernetes Application lifecycle orchestration
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.GxK0yN/_old  2026-01-19 18:41:26.614346501 +0100
+++ /var/tmp/diff_new_pack.GxK0yN/_new  2026-01-19 18:41:26.618346667 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/akuity/kargo</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v1.8.4</param>
+    <param name="revision">v1.8.6</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.GxK0yN/_old  2026-01-19 18:41:26.646347826 +0100
+++ /var/tmp/diff_new_pack.GxK0yN/_new  2026-01-19 18:41:26.646347826 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param name="url">https://github.com/akuity/kargo</param>
-              <param 
name="changesrevision">dc38d05ff871ace7ae40fc23ef333ca717c96909</param></service></servicedata>
+              <param 
name="changesrevision">d9a709fa1adfc2e74e4b5811ebd072f5d60d5bbf</param></service></servicedata>
 (No newline at EOF)
 

++++++ kargo-cli-1.8.4.obscpio -> kargo-cli-1.8.6.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/Makefile new/kargo-cli-1.8.6/Makefile
--- old/kargo-cli-1.8.4/Makefile        2025-11-25 22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/Makefile        2026-01-17 01:21:59.000000000 +0100
@@ -333,7 +333,7 @@
 .PHONY: hack-build
 hack-build: build-base-image
        { \
-               $(CONTAINER_RUNTIME) run -d -p $(LOCAL_REG_PORT):5000 --name 
tmp-registry registry:2; \
+               $(CONTAINER_RUNTIME) run -d -p $(LOCAL_REG_PORT):5000 --name 
tmp-registry registry:3.0.0; \
                trap '$(CONTAINER_RUNTIME) rm -f tmp-registry' EXIT; \
                $(CONTAINER_RUNTIME) push $(BASE_IMAGE):latest-amd64; \
                $(CONTAINER_RUNTIME) push $(BASE_IMAGE):latest-arm64; \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/docs/docs/20-quickstart/index.md 
new/kargo-cli-1.8.6/docs/docs/20-quickstart/index.md
--- old/kargo-cli-1.8.4/docs/docs/20-quickstart/index.md        2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/docs/docs/20-quickstart/index.md        2026-01-17 
01:21:59.000000000 +0100
@@ -735,8 +735,8 @@
 :::info
 The `uat` and `prod` instances of our site should be accessible at:
 
-* `uat`: [localhost:30082](http://localhost:30082)
-* `prod`: [localhost:30083](http://localhost:30083)
+* `uat`: [localhost:32081](http://localhost:32081)
+* `prod`: [localhost:32082](http://localhost:32082)
 :::
 
 :::info
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/docs/docs/40-operator-guide/40-security/20-openid-connect/30-aws-cognito/index.md
 
new/kargo-cli-1.8.6/docs/docs/40-operator-guide/40-security/20-openid-connect/30-aws-cognito/index.md
--- 
old/kargo-cli-1.8.4/docs/docs/40-operator-guide/40-security/20-openid-connect/30-aws-cognito/index.md
       2025-11-25 22:45:38.000000000 +0100
+++ 
new/kargo-cli-1.8.6/docs/docs/40-operator-guide/40-security/20-openid-connect/30-aws-cognito/index.md
       2026-01-17 01:21:59.000000000 +0100
@@ -146,7 +146,7 @@
           This is where users of the Kargo UI will be redirected to after
           logging in.
 
-        * `https://localhost/auth/callback`
+        * `http://localhost/auth/callback`
 
            This is where users of the `kargo` CLI will be redirected to
            redirected to after logging in. (The CLI launches a server to serve
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/docs/docs/40-operator-guide/40-security/20-openid-connect/index.md
 
new/kargo-cli-1.8.6/docs/docs/40-operator-guide/40-security/20-openid-connect/index.md
--- 
old/kargo-cli-1.8.4/docs/docs/40-operator-guide/40-security/20-openid-connect/index.md
      2025-11-25 22:45:38.000000000 +0100
+++ 
new/kargo-cli-1.8.6/docs/docs/40-operator-guide/40-security/20-openid-connect/index.md
      2026-01-17 01:21:59.000000000 +0100
@@ -64,7 +64,7 @@
 **With a compatible identity provider:**
 
   - `https://<hostname for api server>/login` (for the UI)
-  - `https://localhost/auth/callback` (for the CLI)
+  - `http://localhost/auth/callback` (for the CLI)
 
     <br/>
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/50-security/20-access-controls/index.md
 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/50-security/20-access-controls/index.md
--- 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/50-security/20-access-controls/index.md
 2025-11-25 22:45:38.000000000 +0100
+++ 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/50-security/20-access-controls/index.md
 2026-01-17 01:21:59.000000000 +0100
@@ -124,7 +124,7 @@
 user-to-`ServiceAccount` mappings and the permissions associated with those
 `ServiceAccount` resources.
 
-Three such "Kargo roles" are pre-defined in a project's namespace when a new
+There are several "Kargo roles" pre-defined in a project's namespace when a new
 `Project` resource is created:
 
 1. `default`: This Kargo role exists by virtue of the existence of the 
`default`
@@ -141,6 +141,15 @@
    annotated as being Kargo-managed, and as such, the "Kargo role" that
    abstracts them can be modified or deleted via the UI or CLI.
 
+1. `kargo-promoter`: This Kargo role is a trio of `ServiceAccount`, `Role`, and
+   `RoleBinding` resources created by the Kargo management controller. Its
+   permissions are pre-defined as those necessary to promote `Stage`s and 
create
+   `Promotion`s, but not to create, update, or delete core pipeline resources
+   such as `Stage`s and `Warehouse`s. It is not
+   initially mapped to any users. All three resources are annotated as being
+   Kargo-managed, and as such, the "Kargo role" that abstracts them can be
+   modified or deleted via the UI or CLI.
+
 1. `kargo-viewer`: This Kargo role is a trio of `ServiceAccount`, `Role`, and
    `RoleBinding` resources created by the Kargo management controller. Its
    permissions are pre-defined as those necessary to view, but not modify or
@@ -179,10 +188,11 @@
   ```
 
   ```shell
-  NAME           KARGO MANAGED   AGE
-  default        false           18h
-  kargo-admin    true            18h
-  kargo-viewer   true            18h
+  NAME             KARGO MANAGED   AGE
+  default          false           18h
+  kargo-admin      true            18h
+  kargo-promoter   true            18h
+  kargo-viewer     true            18h
   ```
 
 * The details of a specific role can be examined by naming the role and
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
--- 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
    2025-11-25 22:45:38.000000000 +0100
+++ 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/60-reference-docs/30-promotion-steps/git-merge-pr.md
    2026-01-17 01:21:59.000000000 +0100
@@ -10,6 +10,23 @@
 `git-merge-pr` merges an open pull request. This step commonly follows a
 [`git-open-pr`](git-open-pr.md) step.
 
+:::important
+This step only executes synchronous merges. It can neither initiate an
+asynchronous merge by placing a PR on a merge queue (or similar), nor can it
+recognize when an open PR is already _in_ a merge queue (having been placed
+there by someone or something else), and thus cannot wait for an aynchronous
+merge in-progress to complete.
+:::
+
+:::caution
+__GitHub__ repositories can be configured with branch protection rules that
+require PRs to be merged via a merge queue. When such a rule is in place, the
+results of the `git-merge-pr` step attempting a synchronous merge will depend
+upon permissions. With sufficient permissions to bypass branch protection 
rules,
+the merge queue will be bypassed. Without such permissions, the step's attempt
+to merge will fail.
+:::
+
 ## Configuration
 
 | Name                    | Type      | Required | Description                 
                                                                                
                                                                                
                   |
@@ -49,8 +66,8 @@
 ### Merge with Wait
 
 This example demonstrates merging a pull request with waiting enabled. If the 
pull
-request is not immediately ready to merge, the step will return a running 
status and
-Kargo will retry it later.
+request is not yet mergeable for any reason, the step will return a running
+status and Kargo will retry it on the next reconciliation.
 
 ```yaml
 steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/60-reference-docs/40-expressions.md 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/60-reference-docs/40-expressions.md
--- 
old/kargo-cli-1.8.4/docs/docs/50-user-guide/60-reference-docs/40-expressions.md 
    2025-11-25 22:45:38.000000000 +0100
+++ 
new/kargo-cli-1.8.6/docs/docs/50-user-guide/60-reference-docs/40-expressions.md 
    2026-01-17 01:21:59.000000000 +0100
@@ -633,7 +633,7 @@
       repoURL: oci://example.com/my-other-chart
   freightCreationCriteria:
     expression: |
-      chartFrom('oci://example.com/my-chart').Version == 
chartFrom('oci://example.com/my-other-chart').Tag
+      chartFrom('oci://example.com/my-chart').Version == 
chartFrom('oci://example.com/my-other-chart').Version
 ```
 
 :::info
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/go.mod new/kargo-cli-1.8.6/go.mod
--- old/kargo-cli-1.8.4/go.mod  2025-11-25 22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/go.mod  2026-01-17 01:21:59.000000000 +0100
@@ -23,7 +23,7 @@
        github.com/coreos/go-oidc/v3 v3.16.0
        github.com/cyphar/filepath-securejoin v0.6.0
        github.com/evanphx/json-patch/v5 v5.9.11
-       github.com/expr-lang/expr v1.17.6
+       github.com/expr-lang/expr v1.17.7
        github.com/fatih/structtag v1.2.0
        github.com/fluxcd/pkg/kustomize v1.23.0
        github.com/go-git/go-git/v5 v5.16.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/go.sum new/kargo-cli-1.8.6/go.sum
--- old/kargo-cli-1.8.4/go.sum  2025-11-25 22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/go.sum  2026-01-17 01:21:59.000000000 +0100
@@ -142,8 +142,8 @@
 github.com/evanphx/json-patch/v5 v5.9.11/go.mod 
h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
 github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f 
h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
 github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod 
h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
-github.com/expr-lang/expr v1.17.6 
h1:1h6i8ONk9cexhDmowO/A64VPxHScu7qfSl2k8OlINec=
-github.com/expr-lang/expr v1.17.6/go.mod 
h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
+github.com/expr-lang/expr v1.17.7 
h1:Q0xY/e/2aCIp8g9s/LGvMDCC5PxYlvHgDZRQ4y16JX8=
+github.com/expr-lang/expr v1.17.7/go.mod 
h1:8/vRC7+7HBzESEqt5kKpYXxrxkr31SaO8r40VO/1IT4=
 github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
 github.com/fatih/color v1.16.0/go.mod 
h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
 github.com/fatih/structtag v1.2.0 
h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/hack/quickstart/k3d.sh 
new/kargo-cli-1.8.6/hack/quickstart/k3d.sh
--- old/kargo-cli-1.8.4/hack/quickstart/k3d.sh  2025-11-25 22:45:38.000000000 
+0100
+++ new/kargo-cli-1.8.6/hack/quickstart/k3d.sh  2026-01-17 01:21:59.000000000 
+0100
@@ -10,7 +10,7 @@
   --no-lb \
   --k3s-arg '--disable=traefik@server:0' \
   -p '31443-31445:31443-31445@servers:0:direct' \
-  -p '30081-30083:30081-30083@servers:0:direct' \
+  -p '32080-32082:32080-32082@servers:0:direct' \
   --wait
 
 helm install cert-manager cert-manager \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/hack/quickstart/kind.sh 
new/kargo-cli-1.8.6/hack/quickstart/kind.sh
--- old/kargo-cli-1.8.4/hack/quickstart/kind.sh 2025-11-25 22:45:38.000000000 
+0100
+++ new/kargo-cli-1.8.6/hack/quickstart/kind.sh 2026-01-17 01:21:59.000000000 
+0100
@@ -20,12 +20,12 @@
     hostPort: 31444
   - containerPort: 31445 # External webhooks server
     hostPort: 31445
-  - containerPort: 30081 # test application instance
-    hostPort: 30081
-  - containerPort: 30082 # UAT application instance
-    hostPort: 30082
-  - containerPort: 30083 # prod application instance
-    hostPort: 30083
+  - containerPort: 32080 # test application instance
+    hostPort: 32080
+  - containerPort: 32081 # UAT application instance
+    hostPort: 32081
+  - containerPort: 32082 # prod application instance
+    hostPort: 32082
   
 EOF
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/controller/git/base_repo.go 
new/kargo-cli-1.8.6/pkg/controller/git/base_repo.go
--- old/kargo-cli-1.8.4/pkg/controller/git/base_repo.go 2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/controller/git/base_repo.go 2026-01-17 
01:21:59.000000000 +0100
@@ -359,7 +359,7 @@
                "--heads",
                "--exit-code", // Return 2 if not found
                b.accessURL,
-               branch,
+               "refs/heads/"+branch,
        ))
        var exitErr *libExec.ExitError
        if errors.As(err, &exitErr) && exitErr.ExitCode == 2 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/controller/git/repo.go 
new/kargo-cli-1.8.6/pkg/controller/git/repo.go
--- old/kargo-cli-1.8.4/pkg/controller/git/repo.go      2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/controller/git/repo.go      2026-01-17 
01:21:59.000000000 +0100
@@ -128,6 +128,9 @@
        if opts.Depth > 0 {
                args = append(args, "--depth", fmt.Sprint(opts.Depth))
        }
+       if opts.Filter != "" {
+               args = append(args, "--filter", opts.Filter)
+       }
        args = append(args, r.accessURL, r.dir)
        cmd := r.buildGitCommand(args...)
        cmd.Dir = r.homeDir // Override the cmd.Dir that's set by 
r.buildGitCommand()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/pkg/controller/management/projects/event_handlers.go 
new/kargo-cli-1.8.6/pkg/controller/management/projects/event_handlers.go
--- old/kargo-cli-1.8.4/pkg/controller/management/projects/event_handlers.go    
2025-11-25 22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/controller/management/projects/event_handlers.go    
2026-01-17 01:21:59.000000000 +0100
@@ -148,7 +148,7 @@
        case oldCond == nil || newCond == nil:
                fallthrough
        case oldCond.Status != newCond.Status:
-               logger.Info("Warehouse health changed, enqueueing Project")
+               logger.Info("Stage health changed, enqueueing Project")
                wq.Add(reconcile.Request{
                        NamespacedName: types.NamespacedName{Name: 
oldStage.Namespace},
                })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/pkg/controller/promotions/promotions.go 
new/kargo-cli-1.8.6/pkg/controller/promotions/promotions.go
--- old/kargo-cli-1.8.4/pkg/controller/promotions/promotions.go 2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/controller/promotions/promotions.go 2026-01-17 
01:21:59.000000000 +0100
@@ -329,6 +329,7 @@
        newStatus := promo.Status.DeepCopy()
 
        var suggestedRequeueInterval *time.Duration
+       var promoteErr error
 
        // Wrap the promoteFn() call in an anonymous function to recover() any 
panics, so
        // we can update the promo's phase with Error if it does. This breaks 
an infinite
@@ -346,7 +347,6 @@
                        }
                }()
                var otherStatus *kargoapi.PromotionStatus
-               var promoteErr error
                otherStatus, suggestedRequeueInterval, promoteErr = r.promoteFn(
                        promoCtx,
                        *promo,
@@ -357,7 +357,10 @@
                        newStatus = otherStatus
                }
                if promoteErr != nil {
-                       newStatus.Phase = kargoapi.PromotionPhaseErrored
+                       // Preserve Running status for progressive backoff on 
retryable errors.
+                       if newStatus.Phase != kargoapi.PromotionPhaseRunning || 
otherStatus == nil {
+                               newStatus.Phase = kargoapi.PromotionPhaseErrored
+                       }
                        newStatus.Message = promoteErr.Error()
                        logger.Error(promoteErr, "error executing Promotion")
                }
@@ -458,9 +461,13 @@
                return ctrl.Result{}, err
        }
 
-       // If the promotion is still running, we'll need to periodically check 
on
-       // it.
+       // If the promotion is still running, we'll need to periodically check 
on it.
        if newStatus.Phase == kargoapi.PromotionPhaseRunning {
+               if promoteErr != nil {
+                       // Retryable error: use progressive backoff.
+                       return ctrl.Result{}, promoteErr
+               }
+               // Waiting for external condition: use calculated interval.
                return ctrl.Result{
                        RequeueAfter: calculateRequeueInterval(promo, 
suggestedRequeueInterval),
                }, nil
@@ -584,7 +591,6 @@
                )
        }
        if err != nil {
-               workingPromo.Status.Phase = kargoapi.PromotionPhaseErrored
                return &workingPromo.Status, nil, err
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/kargo-cli-1.8.4/pkg/gitprovider/bitbucket/bitbucket.go 
new/kargo-cli-1.8.6/pkg/gitprovider/bitbucket/bitbucket.go
--- old/kargo-cli-1.8.4/pkg/gitprovider/bitbucket/bitbucket.go  2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/gitprovider/bitbucket/bitbucket.go  2026-01-17 
01:21:59.000000000 +0100
@@ -333,7 +333,7 @@
 
        // Check if PR is draft - cannot merge draft PRs
        if bbPR.Draft {
-               return nil, false, fmt.Errorf("cannot merge pull request %d: 
pull request is in draft state", id)
+               return nil, false, nil
        }
 
        // TODO: The Bitbucket API lacks comprehensive merge eligibility 
checks. We
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/gitprovider/gitea/gitea.go 
new/kargo-cli-1.8.6/pkg/gitprovider/gitea/gitea.go
--- old/kargo-cli-1.8.4/pkg/gitprovider/gitea/gitea.go  2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/gitprovider/gitea/gitea.go  2026-01-17 
01:21:59.000000000 +0100
@@ -297,16 +297,10 @@
        case giteaPR.State != gitea.StateOpen:
                return nil, false, fmt.Errorf("pull request %d is closed but 
not merged", id)
 
-       case !giteaPR.Mergeable:
+       case giteaPR.Draft || !giteaPR.Mergeable:
                return nil, false, nil
        }
 
-       // TODO(fykaa): We should also check if the PR is in draft status before
-       // merging. The Gitea API includes a draft field, but the go-sdk doesn't
-       // expose it yet.
-       //
-       // See: https://gitea.com/gitea/go-sdk/pulls/731
-
        // Merge the PR
        if _, err = p.client.MergePullRequest(
                ctx, p.owner, p.repo, int(id), &gitea.MergePullRequestOption{},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/gitprovider/github/github.go 
new/kargo-cli-1.8.6/pkg/gitprovider/github/github.go
--- old/kargo-cli-1.8.4/pkg/gitprovider/github/github.go        2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/gitprovider/github/github.go        2026-01-17 
01:21:59.000000000 +0100
@@ -316,7 +316,7 @@
        case ptr.Deref(ghPR.State, prStateClosed) != prStateOpen:
                return nil, false, fmt.Errorf("pull request %d is closed but 
not merged", id)
 
-       case ghPR.Mergeable == nil || !*ghPR.Mergeable || (ghPR.Draft != nil && 
*ghPR.Draft):
+       case ptr.Deref(ghPR.Draft, false) || !ptr.Deref(ghPR.Mergeable, false):
                return nil, false, nil
        }
 
@@ -345,6 +345,7 @@
        }
 
        pr := convertGithubPR(*updatedPR)
+
        return &pr, true, nil
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/gitprovider/gitlab/gitlab.go 
new/kargo-cli-1.8.6/pkg/gitprovider/gitlab/gitlab.go
--- old/kargo-cli-1.8.4/pkg/gitprovider/gitlab/gitlab.go        2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/gitprovider/gitlab/gitlab.go        2026-01-17 
01:21:59.000000000 +0100
@@ -226,7 +226,7 @@
        case glMR.State != "opened":
                return nil, false, fmt.Errorf("pull request %d is closed but 
not merged", id)
 
-       case glMR.DetailedMergeStatus != "mergeable":
+       case glMR.Draft || glMR.DetailedMergeStatus != "mergeable":
                return nil, false, nil
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/promotion/simple_engine.go 
new/kargo-cli-1.8.6/pkg/promotion/simple_engine.go
--- old/kargo-cli-1.8.4/pkg/promotion/simple_engine.go  2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/promotion/simple_engine.go  2026-01-17 
01:21:59.000000000 +0100
@@ -2,7 +2,6 @@
 
 import (
        "context"
-       "errors"
        "fmt"
        "os"
        "regexp"
@@ -83,12 +82,7 @@
                defer os.RemoveAll(workDir)
        }
 
-       result := e.executeSteps(ctx, promoCtx, steps, workDir)
-       if result.Status == kargoapi.PromotionPhaseErrored {
-               err = errors.New(result.Message)
-       }
-
-       return result, err
+       return e.executeSteps(ctx, promoCtx, steps, workDir)
 }
 
 // executeSteps executes a list of Steps in sequence.
@@ -97,7 +91,7 @@
        pCtx Context,
        steps []Step,
        workDir string,
-) Result {
+) (Result, error) {
        // NB: Make a deep copy of the Context so that we don't modify the 
original.
        promoCtx := pCtx.DeepCopy()
        if promoCtx.State == nil {
@@ -128,8 +122,15 @@
                        exprDataCache = e.cacheFunc()
                }
 
-               if e.shouldSkipStep(ctx, exprDataCache, promoCtx, step, 
stepExecMeta) {
-                       continue
+               // Only evaluate the "if" conditio when the step has not yet 
started.
+               // If the step has already started (on a previous 
reconciliation), we
+               // should not re-evaluate whether to skip it. Re-evaluating 
could cause
+               // a step's own Failed status from a previous attempt to 
incorrectly
+               // trigger the skip condition.
+               if stepExecMeta.StartedAt == nil {
+                       if e.shouldSkipStep(ctx, exprDataCache, promoCtx, step, 
stepExecMeta) {
+                               continue
+                       }
                }
 
                // Get a StepRunner for the step.
@@ -182,7 +183,7 @@
 
                // Determine what to do based on the result.
                if !e.determineStepCompletion(step, registration.Metadata, 
stepExecMeta, err) {
-                       // The step is still running, so we need to wait
+                       // Step incomplete; return error (if any) for 
progressive backoff.
                        return Result{
                                Status:                
kargoapi.PromotionPhaseRunning,
                                CurrentStep:           i,
@@ -190,7 +191,7 @@
                                State:                 promoCtx.State,
                                HealthChecks:          healthChecks,
                                RetryAfter:            result.RetryAfter,
-                       }
+                       }, err
                }
 
                // If the step succeeded, we can add any health checks to the 
list.
@@ -211,7 +212,7 @@
                StepExecutionMetadata: promoCtx.StepExecutionMetadata,
                State:                 promoCtx.State,
                HealthChecks:          healthChecks,
-       }
+       }, nil
 }
 
 func (e *simpleEngine) prepareStepMetadata(promoCtx *Context, step Step) 
*kargoapi.StepExecutionMetadata {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/promotion/simple_engine_test.go 
new/kargo-cli-1.8.6/pkg/promotion/simple_engine_test.go
--- old/kargo-cli-1.8.4/pkg/promotion/simple_engine_test.go     2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/promotion/simple_engine_test.go     2026-01-17 
01:21:59.000000000 +0100
@@ -49,7 +49,7 @@
                                {Kind: "error-step"},
                        },
                        assertions: func(t *testing.T, result Result, err 
error) {
-                               assert.ErrorContains(t, err, "error running 
step")
+                               assert.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                        },
                },
@@ -62,13 +62,33 @@
                                {Kind: "context-waiter"},
                        },
                        assertions: func(t *testing.T, result Result, err 
error) {
-                               assert.ErrorContains(t, err, 
context.Canceled.Error())
+                               assert.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
+                               assert.Contains(t, result.Message, 
context.Canceled.Error())
                                assert.Len(t, result.StepExecutionMetadata, 1)
                                assert.Equal(t, 
kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
                                assert.Contains(t, 
result.StepExecutionMetadata[0].Message, context.Canceled.Error())
                        },
                },
+               {
+                       name: "running promotion with recoverable error returns 
error for backoff",
+                       promoCtx: Context{
+                               Project: "test-project",
+                       },
+                       steps: []Step{
+                               {
+                                       Kind:  "recoverable-error-step",
+                                       Alias: "step1",
+                                       Retry: 
&kargoapi.PromotionStepRetry{ErrorThreshold: 3},
+                               },
+                       },
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               assert.Error(t, err)
+                               assert.Equal(t, kargoapi.PromotionPhaseRunning, 
result.Status)
+                               assert.Len(t, result.StepExecutionMetadata, 1)
+                               assert.Equal(t, 
kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
+                       },
+               },
        }
 
        for _, tt := range tests {
@@ -121,6 +141,19 @@
                                        },
                                },
                        )
+                       testRegistry.register(
+                               "recoverable-error-step",
+                               StepRunnerRegistration{
+                                       Factory: func(StepRunnerCapabilities) 
StepRunner {
+                                               return &MockStepRunner{
+                                                       RunResult: StepResult{
+                                                               Status: 
kargoapi.PromotionStepStatusErrored,
+                                                       },
+                                                       RunErr: 
errors.New("recoverable error"),
+                                               }
+                                       },
+                               },
+                       )
 
                        engine := &simpleEngine{registry: testRegistry}
 
@@ -136,12 +169,13 @@
                register   func(stepRunnerRegistry)
                promoCtx   Context
                steps      []Step
-               assertions func(*testing.T, Result)
+               assertions func(*testing.T, Result, error)
        }{
                {
                        name:  "runner not found",
                        steps: []Step{{Kind: "unknown-step"}},
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "no 
promotion step runner found for kind")
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -157,7 +191,8 @@
                {
                        name:  "error determining whether to skip step",
                        steps: []Step{{If: "${{ bogus() }}"}},
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "error 
checking if step")
                                assert.Contains(t, result.Message, "should be 
skipped")
@@ -179,7 +214,8 @@
                                {Kind: "success-step", Alias: "step1"},
                                {Kind: "success-step", Alias: "step2"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -209,7 +245,8 @@
                                {Kind: "skipped-step", Alias: "step1"},
                                {Kind: "skipped-step", Alias: "step2"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -240,7 +277,8 @@
                                {Kind: "error-step", Alias: "step2", If: "${{ 
false }}"},
                                {Kind: "success-step", Alias: "step3", If: "${{ 
true }}"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(2), result.CurrentStep)
@@ -288,7 +326,8 @@
                                // This step should be run
                                {Kind: "success-step", Alias: "step2"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -315,7 +354,8 @@
                                {Kind: "success-step", Alias: "step1"},
                                {Kind: "terminal-error-step", Alias: "step2"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "an 
unrecoverable error occurred")
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -346,7 +386,8 @@
                                {Kind: "success-step", Alias: "step1"},
                                {Kind: "error-step", Alias: "step2"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "met error 
threshold")
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -380,7 +421,8 @@
                                        Retry: 
&kargoapi.PromotionStepRetry{ErrorThreshold: 3},
                                },
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.Error(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseRunning, 
result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -413,7 +455,8 @@
                                        },
                                },
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "timed out 
after")
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -444,7 +487,8 @@
                                        },
                                },
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "timed out 
after")
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -459,7 +503,8 @@
                {
                        name:  "step is still running; timeout not elapsed",
                        steps: []Step{{Kind: "running-step"}},
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseRunning, 
result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -477,7 +522,8 @@
                                {Kind: "context-waiter"}, // Closes context and 
errors
                                {Kind: "success-step"},   // Won't run because 
of canceled context
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, 
context.Canceled.Error())
                                assert.Equal(t, int64(1), result.CurrentStep)
@@ -516,7 +562,8 @@
                                Kind:  "task-level-output-step",
                                Alias: "task-1::custom-output",
                        }},
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -564,7 +611,8 @@
                                Kind:  "task-level-output-step",
                                Alias: "custom-output",
                        }},
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
                                assert.Empty(t, result.Message)
                                assert.Equal(t, int64(0), result.CurrentStep)
@@ -582,6 +630,31 @@
                        },
                },
                {
+                       name: "previously failed step does not skip on retry",
+                       promoCtx: Context{
+                               StepExecutionMetadata: 
kargoapi.StepExecutionMetadataList{{
+                                       Alias:     "step1",
+                                       StartedAt: 
ptr.To(metav1.NewTime(time.Now().Add(-time.Minute))),
+                                       Status:    
kargoapi.PromotionStepStatusFailed,
+                                       Message:   "previous failure",
+                               }},
+                       },
+                       steps: []Step{
+                               {Kind: "success-step", Alias: "step1"},
+                       },
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
+                               assert.Equal(t, 
kargoapi.PromotionPhaseSucceeded, result.Status)
+                               assert.Equal(t, int64(0), result.CurrentStep)
+
+                               require.Len(t, result.StepExecutionMetadata, 1)
+
+                               assert.Equal(t, 
kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
+                               assert.NotNil(t, 
result.StepExecutionMetadata[0].StartedAt)
+                               assert.NotNil(t, 
result.StepExecutionMetadata[0].FinishedAt)
+                       },
+               },
+               {
                        name: "panic during step execution",
                        register: func(registry stepRunnerRegistry) {
                                registry.register(
@@ -614,7 +687,8 @@
                                {Kind: "panic-step", Alias: "step2"},
                                {Kind: "success-step", Alias: "step3"},
                        },
-                       assertions: func(t *testing.T, result Result) {
+                       assertions: func(t *testing.T, result Result, err 
error) {
+                               require.NoError(t, err)
                                assert.Equal(t, kargoapi.PromotionPhaseErrored, 
result.Status)
                                assert.Contains(t, result.Message, "something 
went wrong")
                                assert.Equal(t, int64(2), result.CurrentStep)
@@ -727,7 +801,8 @@
                                kargoClient: fake.NewClientBuilder().Build(),
                        }
 
-                       tt.assertions(t, engine.executeSteps(ctx, tt.promoCtx, 
tt.steps, t.TempDir()))
+                       result, err := engine.executeSteps(ctx, tt.promoCtx, 
tt.steps, t.TempDir())
+                       tt.assertions(t, result, err)
                })
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/webhook/external/artifactory.go 
new/kargo-cli-1.8.6/pkg/webhook/external/artifactory.go
--- old/kargo-cli-1.8.4/pkg/webhook/external/artifactory.go     2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/webhook/external/artifactory.go     2026-01-17 
01:21:59.000000000 +0100
@@ -109,7 +109,7 @@
                }
 
                mac := hmac.New(sha256.New, token)
-               mac.Write(requestBody)
+               _, _ = mac.Write(requestBody)
                computedSig := hex.EncodeToString(mac.Sum(nil))
 
                if !hmac.Equal([]byte(sig), []byte(computedSig)) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/webhook/external/github.go 
new/kargo-cli-1.8.6/pkg/webhook/external/github.go
--- old/kargo-cli-1.8.4/pkg/webhook/external/github.go  2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/webhook/external/github.go  2026-01-17 
01:21:59.000000000 +0100
@@ -210,11 +210,10 @@
                        return
 
                case *gh.PushEvent:
-                       // TODO(krancour): GetHTMLURL() gives us a repo URL 
starting with
-                       // https://. By refreshing Warehouses using a 
normalized representation of
-                       // that URL, we will miss any Warehouses that are 
subscribed to the same
-                       // repository using a different URL format.
-                       repoURLs = 
[]string{urls.NormalizeGit(e.GetRepo().GetCloneURL())}
+                       repoURLs = []string{
+                               urls.NormalizeGit(e.GetRepo().GetCloneURL()),
+                               urls.NormalizeGit(e.GetRepo().GetSSHURL()),
+                       }
                        ref := e.GetRef()
                        qualifiers = []string{ref}
                        logger = logger.WithValues("ref", ref)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/webhook/external/github_test.go 
new/kargo-cli-1.8.6/pkg/webhook/external/github_test.go
--- old/kargo-cli-1.8.4/pkg/webhook/external/github_test.go     2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/webhook/external/github_test.go     2026-01-17 
01:21:59.000000000 +0100
@@ -33,6 +33,12 @@
                        CloneURL: gh.Ptr("https://github.com/example/repo";),
                },
        }
+       validPushEventSshRepoURL := &gh.PushEvent{
+               Ref: gh.Ptr("refs/heads/main"),
+               Repo: &gh.PushEventRepository{
+                       SSHURL: gh.Ptr("[email protected]:user/repo.git"),
+               },
+       }
        validPackageEventImage := &gh.PackageEvent{
                Action: gh.Ptr("published"),
                Package: &gh.Package{
@@ -502,7 +508,7 @@
                        },
                },
                {
-                       name:       "warehouse refreshed (push event, git)",
+                       name:       "warehouse refreshed (push event, git, 
https)",
                        secretData: testSecretData,
                        client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
                                &kargoapi.Warehouse{
@@ -529,6 +535,46 @@
                                require.NoError(t, err)
                                req := httptest.NewRequest(
                                        http.MethodPost,
+                                       testURL,
+                                       bytes.NewBuffer(bodyBytes),
+                               )
+                               req.Header.Set(gh.EventTypeHeader, 
githubEventTypePush)
+                               req.Header.Set(gh.SHA256SignatureHeader, 
sign(bodyBytes))
+                               return req
+                       },
+                       assertions: func(t *testing.T, rr 
*httptest.ResponseRecorder) {
+                               require.Equal(t, http.StatusOK, rr.Code)
+                               require.JSONEq(t, `{"msg":"refreshed 1 
warehouse(s)"}`, rr.Body.String())
+                       },
+               },
+               {
+                       name:       "warehouse refreshed (push event, git, 
ssh)",
+                       secretData: testSecretData,
+                       client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
+                               &kargoapi.Warehouse{
+                                       ObjectMeta: metav1.ObjectMeta{
+                                               Namespace: testProjectName,
+                                               Name:      "fake-warehouse",
+                                       },
+                                       Spec: kargoapi.WarehouseSpec{
+                                               Subscriptions: 
[]kargoapi.RepoSubscription{{
+                                                       Git: 
&kargoapi.GitSubscription{
+                                                               RepoURL: 
"[email protected]:user/repo.git",
+                                                               Branch:  "main",
+                                                       },
+                                               }},
+                                       },
+                               },
+                       ).WithIndex(
+                               &kargoapi.Warehouse{},
+                               indexer.WarehousesBySubscribedURLsField,
+                               indexer.WarehousesBySubscribedURLs,
+                       ).Build(),
+                       req: func() *http.Request {
+                               bodyBytes, err := 
json.Marshal(validPushEventSshRepoURL)
+                               require.NoError(t, err)
+                               req := httptest.NewRequest(
+                                       http.MethodPost,
                                        testURL,
                                        bytes.NewBuffer(bodyBytes),
                                )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/webhook/external/gitlab.go 
new/kargo-cli-1.8.6/pkg/webhook/external/gitlab.go
--- old/kargo-cli-1.8.4/pkg/webhook/external/gitlab.go  2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/webhook/external/gitlab.go  2026-01-17 
01:21:59.000000000 +0100
@@ -120,7 +120,10 @@
                case *gl.PushEvent:
                        var repoURLs []string
                        if e.Repository != nil {
-                               repoURLs = 
[]string{urls.NormalizeGit(e.Repository.GitHTTPURL)}
+                               repoURLs = []string{
+                                       
urls.NormalizeGit(e.Repository.GitHTTPURL),
+                                       
urls.NormalizeGit(e.Repository.GitSSHURL),
+                               }
                        }
                        logger = logger.WithValues(
                                "repoURLs", repoURLs,
@@ -131,7 +134,10 @@
                case *gl.TagEvent:
                        var repoURLs []string
                        if e.Repository != nil {
-                               repoURLs = 
[]string{urls.NormalizeGit(e.Repository.GitHTTPURL)}
+                               repoURLs = []string{
+                                       
urls.NormalizeGit(e.Repository.GitHTTPURL),
+                                       
urls.NormalizeGit(e.Repository.GitSSHURL),
+                               }
                        }
                        logger = logger.WithValues(
                                "repoURLs", repoURLs,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/webhook/external/gitlab_test.go 
new/kargo-cli-1.8.6/pkg/webhook/external/gitlab_test.go
--- old/kargo-cli-1.8.4/pkg/webhook/external/gitlab_test.go     2025-11-25 
22:45:38.000000000 +0100
+++ new/kargo-cli-1.8.6/pkg/webhook/external/gitlab_test.go     2026-01-17 
01:21:59.000000000 +0100
@@ -22,7 +22,8 @@
 {
        "ref": "refs/heads/main",
        "repository":{
-               "git_http_url": "https://gitlab.com/example/repo";
+               "git_http_url": "https://gitlab.com/example/repo.git";,
+               "git_ssh_url": "[email protected]:example/repo.git"
        }
 }`
 
@@ -30,7 +31,8 @@
 {
        "ref": "refs/tags/v1.0.0",
        "repository":{
-               "git_http_url": "https://gitlab.com/example/repo";
+               "git_http_url": "https://gitlab.com/example/repo.git";,
+               "git_ssh_url": "[email protected]:example/repo.git"
        }
 }`
 
@@ -152,7 +154,7 @@
                        },
                },
                {
-                       name:       "warehouse refreshed (push event)",
+                       name:       "warehouse refreshed (push event, https)",
                        secretData: testSecretData,
                        client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
                                &kargoapi.Warehouse{
@@ -193,6 +195,47 @@
                        },
                },
                {
+                       name:       "warehouse refreshed (push event, ssh)",
+                       secretData: testSecretData,
+                       client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
+                               &kargoapi.Warehouse{
+                                       ObjectMeta: metav1.ObjectMeta{
+                                               Namespace: testProjectName,
+                                               Name:      "fake-warehouse",
+                                       },
+                                       Spec: kargoapi.WarehouseSpec{
+                                               Subscriptions: 
[]kargoapi.RepoSubscription{{
+                                                       Git: 
&kargoapi.GitSubscription{
+                                                               RepoURL: 
"[email protected]:example/repo",
+                                                               Branch:  "main",
+                                                       },
+                                               }},
+                                       },
+                               },
+                       ).WithIndex(
+                               &kargoapi.Warehouse{},
+                               indexer.WarehousesBySubscribedURLsField,
+                               indexer.WarehousesBySubscribedURLs,
+                       ).Build(),
+                       req: func() *http.Request {
+                               bodyBuf := 
bytes.NewBuffer([]byte(gitlabPushEventRequestBody))
+                               req := httptest.NewRequest(
+                                       http.MethodPost,
+                                       testURL,
+                                       bodyBuf,
+                               )
+                               req.Header.Set(gitlabTokenHeader, testToken)
+                               req.Header.Set(gitlabEventHeader, 
string(gl.EventTypePush))
+                               return req
+                       },
+                       assertions: func(t *testing.T, rr 
*httptest.ResponseRecorder) {
+                               require.Equal(t, http.StatusOK, rr.Code)
+                               require.JSONEq(
+                                       t, `{"msg":"refreshed 1 
warehouse(s)"}`, rr.Body.String(),
+                               )
+                       },
+               },
+               {
                        name: "no ref match (tag event)",
                        // This event would prompt the Warehouse to refresh if 
not for the ref in
                        // the event being for a tag falling outside the 
subscription's semver
@@ -238,7 +281,7 @@
                        },
                },
                {
-                       name:       "warehouse refreshed (tag event)",
+                       name:       "warehouse refreshed (tag event, https)",
                        secretData: testSecretData,
                        client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
                                &kargoapi.Warehouse{
@@ -253,6 +296,48 @@
                                                                
CommitSelectionStrategy: kargoapi.CommitSelectionStrategySemVer,
                                                                
SemverConstraint:        "^1.0.0",
                                                        },
+                                               }},
+                                       },
+                               },
+                       ).WithIndex(
+                               &kargoapi.Warehouse{},
+                               indexer.WarehousesBySubscribedURLsField,
+                               indexer.WarehousesBySubscribedURLs,
+                       ).Build(),
+                       req: func() *http.Request {
+                               bodyBuf := 
bytes.NewBuffer([]byte(gitlabTagPushEventRequestBody))
+                               req := httptest.NewRequest(
+                                       http.MethodPost,
+                                       testURL,
+                                       bodyBuf,
+                               )
+                               req.Header.Set(gitlabTokenHeader, testToken)
+                               req.Header.Set(gitlabEventHeader, 
string(gl.EventTypeTagPush))
+                               return req
+                       },
+                       assertions: func(t *testing.T, rr 
*httptest.ResponseRecorder) {
+                               require.Equal(t, http.StatusOK, rr.Code)
+                               require.JSONEq(
+                                       t, `{"msg":"refreshed 1 
warehouse(s)"}`, rr.Body.String(),
+                               )
+                       },
+               },
+               {
+                       name:       "warehouse refreshed (tag event, ssh)",
+                       secretData: testSecretData,
+                       client: 
fake.NewClientBuilder().WithScheme(testScheme).WithObjects(
+                               &kargoapi.Warehouse{
+                                       ObjectMeta: metav1.ObjectMeta{
+                                               Namespace: testProjectName,
+                                               Name:      "fake-warehouse",
+                                       },
+                                       Spec: kargoapi.WarehouseSpec{
+                                               Subscriptions: 
[]kargoapi.RepoSubscription{{
+                                                       Git: 
&kargoapi.GitSubscription{
+                                                               RepoURL:        
         "[email protected]:example/repo",
+                                                               
CommitSelectionStrategy: kargoapi.CommitSelectionStrategySemVer,
+                                                               
SemverConstraint:        "^1.0.0",
+                                                       },
                                                }},
                                        },
                                },
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/yaml/yaml.go 
new/kargo-cli-1.8.6/pkg/yaml/yaml.go
--- old/kargo-cli-1.8.4/pkg/yaml/yaml.go        2025-11-25 22:45:38.000000000 
+0100
+++ new/kargo-cli-1.8.6/pkg/yaml/yaml.go        2026-01-17 01:21:59.000000000 
+0100
@@ -11,6 +11,14 @@
        "go.yaml.in/yaml/v3"
 )
 
+// The maximum size of the input buffer for processing YAML files. Given that 
the max size of a
+// Kubernetes manifest (the most common thing we're dealing with) is 1 MB, 
this number is chosen to
+// assume that the max value of any given key would be just shy of that number 
(imagine a config map
+// with a single large value which is a config file for something in the 
container). Please note
+// that we do not allocate a buffer of this size up front; this is just the 
maximum size that we
+// will allow when processing input.
+const maxBufferSize = 1024 * 1024 // 1 MB
+
 // Update represents a discrete update to be made to a YAML document.
 type Update struct {
        // Key is the dot-separated path to the field to update.
@@ -86,6 +94,11 @@
 
        scanner := bufio.NewScanner(bytes.NewBuffer(inBytes))
        scanner.Split(bufio.ScanLines)
+       // Create an initial buffer of 100B which should be plenty for most 
lines. This means we will
+       // likely avoid an allocation on the first scan. If we encounter a line 
that exceeds this size,
+       // the buffer will grow up to maxBufferSize.
+       var buf = make([]byte, 0, 100)
+       scanner.Buffer(buf, maxBufferSize)
        var line int
        for scanner.Scan() {
                const errMsg = "error writing to byte buffer"
@@ -117,6 +130,9 @@
                }
                line++
        }
+       if scanner.Err() != nil {
+               return nil, fmt.Errorf("error scanning input bytes: %w", 
scanner.Err())
+       }
 
        return outBuf.Bytes(), nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/kargo-cli-1.8.4/pkg/yaml/yaml_test.go 
new/kargo-cli-1.8.6/pkg/yaml/yaml_test.go
--- old/kargo-cli-1.8.4/pkg/yaml/yaml_test.go   2025-11-25 22:45:38.000000000 
+0100
+++ new/kargo-cli-1.8.6/pkg/yaml/yaml_test.go   2026-01-17 01:21:59.000000000 
+0100
@@ -106,6 +106,36 @@
                                )
                        },
                },
+               {
+                       name: "really long lines still work",
+                       // nolint:lll
+                       inBytes: []byte(`
+characters:
+- name: Anakin
+  affiliation: Light side
+  temptation: "` + strings.Repeat("Did you ever hear the tragedy of Darth 
Plagueis The Wise? I thought not. It's not a story the Jedi would tell you. 
It's a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and 
so wise he could use the Force to influence the midichlorians to create 
life...He had such a knowledge of the dark side that he could even keep the 
ones he cared about from dying. The dark side of the Force is a pathway to many 
abilities some consider to be unnatural. He became so powerful...the only thing 
he was afraid of was losing his power, which eventually, of course, he did. 
Unfortunately, he taught his apprentice everything he knew, then his apprentice 
killed him in his sleep. Ironic. He could save others from death, but not 
himself.", 1000) + `"
+`),
+                       updates: []Update{
+                               {
+                                       Key:   "characters.0.affiliation",
+                                       Value: "Dark side",
+                               },
+                       },
+                       assertions: func(t *testing.T, bytes []byte, err error) 
{
+                               require.NoError(t, err)
+                               require.Equal(
+                                       t,
+                                       // nolint:lll
+                                       []byte(`
+characters:
+- name: Anakin
+  affiliation: Dark side
+  temptation: "`+strings.Repeat("Did you ever hear the tragedy of Darth 
Plagueis The Wise? I thought not. It's not a story the Jedi would tell you. 
It's a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and 
so wise he could use the Force to influence the midichlorians to create 
life...He had such a knowledge of the dark side that he could even keep the 
ones he cared about from dying. The dark side of the Force is a pathway to many 
abilities some consider to be unnatural. He became so powerful...the only thing 
he was afraid of was losing his power, which eventually, of course, he did. 
Unfortunately, he taught his apprentice everything he knew, then his apprentice 
killed him in his sleep. Ironic. He could save others from death, but not 
himself.", 1000)+`"
+`),
+                                       bytes,
+                               )
+                       },
+               },
        }
        for _, testCase := range testCases {
                t.Run(testCase.name, func(t *testing.T) {

++++++ kargo-cli.obsinfo ++++++
--- /var/tmp/diff_new_pack.GxK0yN/_old  2026-01-19 18:41:29.274456566 +0100
+++ /var/tmp/diff_new_pack.GxK0yN/_new  2026-01-19 18:41:29.286457063 +0100
@@ -1,5 +1,5 @@
 name: kargo-cli
-version: 1.8.4
-mtime: 1764107138
-commit: dc38d05ff871ace7ae40fc23ef333ca717c96909
+version: 1.8.6
+mtime: 1768609319
+commit: d9a709fa1adfc2e74e4b5811ebd072f5d60d5bbf
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/kargo-cli/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.kargo-cli.new.1928/vendor.tar.gz differ: char 134, 
line 2

Reply via email to