From 09754bebc60e5bbb9f02c015af7778c30e0e2ad8 Mon Sep 17 00:00:00 2001 From: zeshan Date: Thu, 17 Apr 2025 15:01:58 +0800 Subject: [PATCH 1/2] Fix #36897: Resolve NO_PROXY recognition issue in oss remote backend --- internal/backend/remote-state/oss/backend.go | 27 ++--- .../backend/remote-state/oss/backend_test.go | 100 ++++++++++++++++++ 2 files changed, 111 insertions(+), 16 deletions(-) diff --git a/internal/backend/remote-state/oss/backend.go b/internal/backend/remote-state/oss/backend.go index 2750b98c6731..10128d92e674 100644 --- a/internal/backend/remote-state/oss/backend.go +++ b/internal/backend/remote-state/oss/backend.go @@ -12,7 +12,6 @@ import ( "net/http" "net/url" "os" - "regexp" "runtime" "strconv" "strings" @@ -35,6 +34,7 @@ import ( "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/legacy/helper/schema" "github.com/hashicorp/terraform/version" + "golang.org/x/net/http/httpproxy" ) // Deprecated in favor of flattening assume_role_* options @@ -414,7 +414,10 @@ func (b *Backend) configure(ctx context.Context) error { } options = append(options, oss.UserAgent(fmt.Sprintf("%s/%s", TerraformUA, TerraformVersion))) - proxyUrl := getHttpProxyUrl() + proxyUrl, err := getHttpProxyUrl(endpoint) + if err != nil { + return err + } if proxyUrl != nil { options = append(options, oss.Proxy(proxyUrl.String())) } @@ -706,19 +709,11 @@ func getAuthCredentialByEcsRoleName(ecsRoleName string) (accessKey, secretKey, t return accessKeyId.(string), accessKeySecret.(string), securityToken.(string), nil } -func getHttpProxyUrl() *url.URL { - for _, v := range []string{"HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"} { - value := strings.Trim(os.Getenv(v), " ") - if value != "" { - if !regexp.MustCompile(`^http(s)?://`).MatchString(value) { - value = fmt.Sprintf("https://%s", value) - } - proxyUrl, err := url.Parse(value) - if err == nil { - return proxyUrl - } - break - } +func getHttpProxyUrl(rawUrl string) (*url.URL, error) { + pc := httpproxy.FromEnvironment() + u, err := url.Parse(rawUrl) + if err != nil { + return nil, err } - return nil + return pc.ProxyFunc()(u) } diff --git a/internal/backend/remote-state/oss/backend_test.go b/internal/backend/remote-state/oss/backend_test.go index 31d78ffd88c5..50c34dfc27ca 100644 --- a/internal/backend/remote-state/oss/backend_test.go +++ b/internal/backend/remote-state/oss/backend_test.go @@ -251,3 +251,103 @@ func deleteTablestoreTable(t *testing.T, otsClient *tablestore.TableStoreClient, t.Logf("WARNING: Failed to delete the test TableStore table %q. It has been left in your Alibaba Cloud account and may incur charges. (error was %s)", tableName, err) } } + +func TestGetHttpProxyUrl(t *testing.T) { + tests := []struct { + name string + rawUrl string + httpProxy string + httpsProxy string + noProxy string + expectedProxyURL string + }{ + { + name: "should set proxy using http_proxy environment variable", + rawUrl: "http://example.com", + httpProxy: "http://foo.bar:3128", + httpsProxy: "https://secure.example.com", + noProxy: "", + expectedProxyURL: "http://foo.bar:3128", + }, + { + name: "should set proxy using http_proxy environment variable", + rawUrl: "http://example.com", + httpProxy: "http://foo.barr", + httpsProxy: "https://secure.example.com", + noProxy: "", + expectedProxyURL: "http://foo.barr", + }, + { + name: "should set proxy using https_proxy environment variable", + rawUrl: "https://secure.example.com", + httpProxy: "http://foo.bar", + httpsProxy: "https://foo.bar.com:3128", + noProxy: "", + expectedProxyURL: "https://foo.bar.com:3128", + }, + { + name: "should set proxy using https_proxy environment variable", + rawUrl: "https://secure.example.com", + httpProxy: "", + httpsProxy: "http://foo.baz", + noProxy: "", + expectedProxyURL: "http://foo.baz", + }, + { + name: "should not set http proxy if NO_PROXY contains the host", + rawUrl: "http://example.internal", + httpProxy: "http://foo.bar:3128", + httpsProxy: "", + noProxy: "example.internal", + expectedProxyURL: "", + }, + { + name: "should not set HTTP proxy when NO_PROXY matches the domain with suffix", + rawUrl: "http://qqu.example.internal", + httpProxy: "http://foo.bar:3128", + httpsProxy: "", + noProxy: ".example.internal", + expectedProxyURL: "", + }, + { + name: "should not set https proxy if NO_PROXY contains the host", + rawUrl: "https://secure.internal", + httpProxy: "", + httpsProxy: "https://foo.baz:3128", + noProxy: "secure.internal", + expectedProxyURL: "", + }, + { + name: "should not set https proxy if NO_PROXY matches the domain with suffix", + rawUrl: "https://ss.qcsc.secure.internal", + httpProxy: "", + httpsProxy: "https://foo.baz:3128", + noProxy: ".secure.internal", + expectedProxyURL: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set environment variables + t.Setenv("HTTP_PROXY", tt.httpProxy) + t.Setenv("HTTPS_PROXY", tt.httpsProxy) + t.Setenv("NO_PROXY", tt.noProxy) + + proxyUrl, err := getHttpProxyUrl(tt.rawUrl) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + if tt.expectedProxyURL == "" { + if proxyUrl != nil { + t.Fatalf("unexpected proxy URL, want nil, got: %s", proxyUrl) + } + } else { + if tt.expectedProxyURL != proxyUrl.String() { + t.Fatalf("unexpected proxy URL, want: %s, got: %s", tt.expectedProxyURL, proxyUrl.String()) + } + } + }) + } +} From a31d280913decf26cfcd2db2a27630526dd1ae8d Mon Sep 17 00:00:00 2001 From: zeshan Date: Thu, 17 Apr 2025 23:00:15 +0800 Subject: [PATCH 2/2] refactor(internal/backend/remote-state/oss): update and clean up go.mod dependencies --- internal/backend/remote-state/oss/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backend/remote-state/oss/go.mod b/internal/backend/remote-state/oss/go.mod index 83ac004ae92f..6e5e8027e119 100644 --- a/internal/backend/remote-state/oss/go.mod +++ b/internal/backend/remote-state/oss/go.mod @@ -12,6 +12,7 @@ require ( github.com/hashicorp/terraform/internal/legacy v0.0.0-00010101000000-000000000000 github.com/jmespath/go-jmespath v0.4.0 github.com/mitchellh/go-homedir v1.1.0 + golang.org/x/net v0.38.0 ) require ( @@ -41,7 +42,6 @@ require ( github.com/stretchr/testify v1.8.4 // indirect github.com/zclconf/go-cty v1.16.2 // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.38.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/sys v0.31.0 // indirect golang.org/x/text v0.23.0 // indirect