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-03-05 17:16:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kargo-cli (Old) and /work/SRC/openSUSE:Factory/.kargo-cli.new.561 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kargo-cli" Thu Mar 5 17:16:11 2026 rev:47 rq:1336636 version:1.9.5 Changes: -------- --- /work/SRC/openSUSE:Factory/kargo-cli/kargo-cli.changes 2026-03-02 17:39:39.761692932 +0100 +++ /work/SRC/openSUSE:Factory/.kargo-cli.new.561/kargo-cli.changes 2026-03-05 17:24:22.169602850 +0100 @@ -1,0 +2,6 @@ +Tue Mar 03 05:44:22 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 1.9.5: + no CLI-related changes or dependency updates + +------------------------------------------------------------------- Old: ---- kargo-cli-1.9.4.obscpio New: ---- kargo-cli-1.9.5.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kargo-cli.spec ++++++ --- /var/tmp/diff_new_pack.6ro9G4/_old 2026-03-05 17:24:23.437654161 +0100 +++ /var/tmp/diff_new_pack.6ro9G4/_new 2026-03-05 17:24:23.441654323 +0100 @@ -19,7 +19,7 @@ %define executable_name kargo Name: kargo-cli -Version: 1.9.4 +Version: 1.9.5 Release: 0 Summary: CLI for the Kubernetes Application lifecycle orchestration License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.6ro9G4/_old 2026-03-05 17:24:23.485656104 +0100 +++ /var/tmp/diff_new_pack.6ro9G4/_new 2026-03-05 17:24:23.493656427 +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.9.4</param> + <param name="revision">v1.9.5</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.6ro9G4/_old 2026-03-05 17:24:23.517657398 +0100 +++ /var/tmp/diff_new_pack.6ro9G4/_new 2026-03-05 17:24:23.521657560 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/akuity/kargo</param> - <param name="changesrevision">fefda31245c559f016baac40d3fcd20674315e44</param></service></servicedata> + <param name="changesrevision">fd25620c2473ed19bec4be4d0f181287ef0f0391</param></service></servicedata> (No newline at EOF) ++++++ kargo-cli-1.9.4.obscpio -> kargo-cli-1.9.5.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kargo-cli-1.9.4/pkg/net/safe_dialer.go new/kargo-cli-1.9.5/pkg/net/safe_dialer.go --- old/kargo-cli-1.9.4/pkg/net/safe_dialer.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kargo-cli-1.9.5/pkg/net/safe_dialer.go 2026-03-02 21:00:56.000000000 +0100 @@ -0,0 +1,82 @@ +package net + +import ( + "context" + "fmt" + "net" + "net/http" + "time" +) + +var ( + linkLocalV4 = net.IPNet{ + IP: net.IP{169, 254, 0, 0}, + Mask: net.CIDRMask(16, 32), + } + linkLocalV6 = net.IPNet{ + IP: net.ParseIP("fe80::"), + Mask: net.CIDRMask(10, 128), + } +) + +// isLinkLocal returns true if the given IP is in the IPv4 link-local range +// (169.254.0.0/16) or the IPv6 link-local range (fe80::/10). +func isLinkLocal(ip net.IP) bool { + return linkLocalV4.Contains(ip) || linkLocalV6.Contains(ip) +} + +// SafeDialContext returns a DialContext function that blocks connections to +// link-local IP addresses (169.254.0.0/16 and fe80::/10). This prevents SSRF +// attacks targeting cloud instance metadata endpoints (e.g. 169.254.169.254). +// +// The returned function resolves the hostname before connecting and rejects the +// connection if all resolved addresses are link-local. +func SafeDialContext(dialer *net.Dialer) func( + ctx context.Context, + network string, + addr string, +) (net.Conn, error) { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + host, port, err := net.SplitHostPort(addr) + if err != nil { + return nil, fmt.Errorf("failed to parse address %q: %w", addr, err) + } + + // Resolve the hostname to IP addresses. + ips, err := net.DefaultResolver.LookupIPAddr(ctx, host) + if err != nil { + return nil, fmt.Errorf("failed to resolve host %q: %w", host, err) + } + + // Filter out link-local addresses. + var safe []net.IPAddr + for _, ip := range ips { + if !isLinkLocal(ip.IP) { + safe = append(safe, ip) + } + } + + if len(safe) == 0 { + return nil, fmt.Errorf( + "connections to link-local addresses are not permitted "+ + "(host %q resolved to link-local IPs only)", + host, + ) + } + + // Dial using the first safe address. + safeAddr := net.JoinHostPort(safe[0].IP.String(), port) + return dialer.DialContext(ctx, network, safeAddr) + } +} + +// SafeTransport wraps the given transport's DialContext to block connections to +// link-local IP addresses. +func SafeTransport(t *http.Transport) *http.Transport { + dialer := &net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + } + t.DialContext = SafeDialContext(dialer) + return t +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kargo-cli-1.9.4/pkg/net/safe_dialer_test.go new/kargo-cli-1.9.5/pkg/net/safe_dialer_test.go --- old/kargo-cli-1.9.4/pkg/net/safe_dialer_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/kargo-cli-1.9.5/pkg/net/safe_dialer_test.go 2026-03-02 21:00:56.000000000 +0100 @@ -0,0 +1,88 @@ +package net + +import ( + "net" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_isLinkLocal(t *testing.T) { + tests := []struct { + name string + ip string + expected bool + }{ + { + name: "IPv4 link-local lower bound", + ip: "169.254.0.0", + expected: true, + }, + { + name: "IPv4 link-local metadata endpoint", + ip: "169.254.169.254", + expected: true, + }, + { + name: "IPv4 link-local upper bound", + ip: "169.254.255.255", + expected: true, + }, + { + name: "IPv4 just below link-local range", + ip: "169.253.255.255", + expected: false, + }, + { + name: "IPv4 just above link-local range", + ip: "169.255.0.0", + expected: false, + }, + { + name: "IPv4 private 10.x", + ip: "10.0.0.1", + expected: false, + }, + { + name: "IPv4 public", + ip: "8.8.8.8", + expected: false, + }, + { + name: "IPv4 loopback", + ip: "127.0.0.1", + expected: false, + }, + { + name: "IPv6 link-local", + ip: "fe80::1", + expected: true, + }, + { + name: "IPv6 link-local upper bound", + ip: "febf::ffff", + expected: true, + }, + { + name: "IPv6 just outside link-local", + ip: "fec0::1", + expected: false, + }, + { + name: "IPv6 loopback", + ip: "::1", + expected: false, + }, + { + name: "IPv6 public", + ip: "2001:db8::1", + expected: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ip := net.ParseIP(tt.ip) + assert.Equal(t, tt.expected, isLinkLocal(ip)) + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kargo-cli-1.9.4/pkg/promotion/runner/builtin/http_downloader.go new/kargo-cli-1.9.5/pkg/promotion/runner/builtin/http_downloader.go --- old/kargo-cli-1.9.4/pkg/promotion/runner/builtin/http_downloader.go 2026-02-27 17:07:48.000000000 +0100 +++ new/kargo-cli-1.9.5/pkg/promotion/runner/builtin/http_downloader.go 2026-03-02 21:00:56.000000000 +0100 @@ -18,6 +18,7 @@ kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/pkg/io/fs" "github.com/akuity/kargo/pkg/logging" + kargonet "github.com/akuity/kargo/pkg/net" "github.com/akuity/kargo/pkg/promotion" "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" ) @@ -156,6 +157,8 @@ return nil, fmt.Errorf("error creating HTTP client: %w", err) } + // #nosec G704 -- The client is using a custom dialer that mitigates the worst + // practical risks of SSRF by refusing to dial link-local addresses. resp, err := client.Do(req) if err != nil { return nil, fmt.Errorf("error sending HTTP request: %w", err) @@ -190,7 +193,7 @@ // buildHTTPClient creates an HTTP client with the specified configuration. func (d *httpDownloader) buildHTTPClient(cfg builtin.HTTPDownloadConfig) (*http.Client, error) { - httpTransport := cleanhttp.DefaultTransport() + httpTransport := kargonet.SafeTransport(cleanhttp.DefaultTransport()) if cfg.InsecureSkipTLSVerify { httpTransport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: true, // nolint: gosec diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kargo-cli-1.9.4/pkg/promotion/runner/builtin/http_requester.go new/kargo-cli-1.9.5/pkg/promotion/runner/builtin/http_requester.go --- old/kargo-cli-1.9.4/pkg/promotion/runner/builtin/http_requester.go 2026-02-27 17:07:48.000000000 +0100 +++ new/kargo-cli-1.9.5/pkg/promotion/runner/builtin/http_requester.go 2026-03-02 21:00:56.000000000 +0100 @@ -19,6 +19,7 @@ kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/pkg/io" "github.com/akuity/kargo/pkg/logging" + kargonet "github.com/akuity/kargo/pkg/net" "github.com/akuity/kargo/pkg/promotion" "github.com/akuity/kargo/pkg/x/promotion/runner/builtin" ) @@ -95,6 +96,8 @@ return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, &promotion.TerminalError{Err: fmt.Errorf("error creating HTTP client: %w", err)} } + // #nosec G704 -- The client is using a custom dialer that mitigates the worst + // practical risks of SSRF by refusing to dial link-local addresses. resp, err := client.Do(req) if err != nil { return promotion.StepResult{Status: kargoapi.PromotionStepStatusErrored}, @@ -247,7 +250,7 @@ } func (h *httpRequester) getClient(cfg builtin.HTTPConfig) (*http.Client, error) { - httpTransport := cleanhttp.DefaultTransport() + httpTransport := kargonet.SafeTransport(cleanhttp.DefaultTransport()) if cfg.InsecureSkipTLSVerify { httpTransport.TLSClientConfig = &tls.Config{ InsecureSkipVerify: true, // nolint: gosec ++++++ kargo-cli.obsinfo ++++++ --- /var/tmp/diff_new_pack.6ro9G4/_old 2026-03-05 17:24:27.609822985 +0100 +++ /var/tmp/diff_new_pack.6ro9G4/_new 2026-03-05 17:24:27.621823471 +0100 @@ -1,5 +1,5 @@ name: kargo-cli -version: 1.9.4 -mtime: 1772208468 -commit: fefda31245c559f016baac40d3fcd20674315e44 +version: 1.9.5 +mtime: 1772481656 +commit: fd25620c2473ed19bec4be4d0f181287ef0f0391 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/kargo-cli/vendor.tar.gz /work/SRC/openSUSE:Factory/.kargo-cli.new.561/vendor.tar.gz differ: char 13, line 1
