Skip to content

Commit 0f78e11

Browse files
committed
Go: Detect and apply proxy settings (WIP)
1 parent ded27bc commit 0f78e11

File tree

4 files changed

+168
-1
lines changed

4 files changed

+168
-1
lines changed

go/extractor/toolchain/toolchain.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ func SupportsWorkspaces() bool {
139139

140140
// Constructs a `*exec.Cmd` for `go` with the specified arguments.
141141
func GoCommand(arg ...string) *exec.Cmd {
142-
return exec.Command("go", arg...)
142+
cmd := exec.Command("go", arg...)
143+
util.ApplyProxyEnvVars(cmd)
144+
return cmd
143145
}
144146

145147
// Run `go mod tidy -e` in the directory given by `path`.

go/extractor/util/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/extractor/util/registryproxy.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package util
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log/slog"
7+
"os"
8+
"os/exec"
9+
"strings"
10+
)
11+
12+
const PROXY_HOST = "CODEQL_PROXY_HOST"
13+
const PROXY_PORT = "CODEQL_PROXY_PORT"
14+
const PROXY_CA_CERTIFICATE = "CODEQL_PROXY_CA_CERTIFICATE"
15+
const PROXY_URLS = "CODEQL_PROXY_URLS"
16+
const GOPROXY_SERVER = "goproxy_server"
17+
18+
type RegistryConfig struct {
19+
Type string `json:"type"`
20+
URL string `json:"url"`
21+
}
22+
23+
var proxy_address string
24+
var proxy_cert_file string
25+
var proxy_configs []RegistryConfig
26+
27+
// Tries to parse the given string value into an array of RegistryConfig values.
28+
func parseRegistryConfigs(str string) ([]RegistryConfig, error) {
29+
var configs []RegistryConfig
30+
if err := json.Unmarshal([]byte(str), &configs); err != nil {
31+
return nil, err
32+
}
33+
34+
return configs, nil
35+
}
36+
37+
func checkEnvVars() {
38+
if proxy_host, proxy_host_set := os.LookupEnv(PROXY_HOST); proxy_host_set {
39+
if proxy_port, proxy_port_set := os.LookupEnv(PROXY_PORT); proxy_port_set {
40+
proxy_address = fmt.Sprintf("http://%s:%s", proxy_host, proxy_port)
41+
slog.Info("Found private registry proxy", slog.String("proxy_address", proxy_address))
42+
}
43+
}
44+
45+
if proxy_cert, proxy_cert_set := os.LookupEnv(PROXY_CA_CERTIFICATE); proxy_cert_set {
46+
// Write the certificate to a temporary file
47+
slog.Info("Found certificate")
48+
49+
f, err := os.CreateTemp("", "codeql-proxy.crt")
50+
if err != nil {
51+
slog.Error("Unable to create temporary file for the proxy certificate", slog.String("error", err.Error()))
52+
}
53+
54+
_, err = f.WriteString(proxy_cert)
55+
if err != nil {
56+
slog.Error("Failed to write to the temporary certificate file", slog.String("error", err.Error()))
57+
}
58+
59+
err = f.Close()
60+
if err != nil {
61+
slog.Error("Failed to close the temporary certificate file", slog.String("error", err.Error()))
62+
} else {
63+
proxy_cert_file = f.Name()
64+
}
65+
}
66+
67+
if proxy_urls, proxy_urls_set := os.LookupEnv(PROXY_URLS); proxy_urls_set {
68+
val, err := parseRegistryConfigs(proxy_urls)
69+
if err != nil {
70+
slog.Error("Unable to parse proxy configurations", slog.String("error", err.Error()))
71+
} else {
72+
// We only care about private registry configurations that are relevant to Go and
73+
// filter others out at this point.
74+
proxy_configs = make([]RegistryConfig, 0)
75+
for _, cfg := range val {
76+
if cfg.Type == GOPROXY_SERVER {
77+
proxy_configs = append(proxy_configs, cfg)
78+
slog.Info("Found GOPROXY server", slog.String("url", cfg.URL))
79+
}
80+
}
81+
}
82+
}
83+
}
84+
85+
// Applies private package proxy related environment variables to `cmd`.
86+
func ApplyProxyEnvVars(cmd *exec.Cmd) {
87+
slog.Info(
88+
"Applying private registry proxy environment variables",
89+
slog.String("cmd_args", strings.Join(cmd.Args, " ")),
90+
)
91+
92+
checkEnvVars()
93+
94+
if proxy_address != "" {
95+
cmd.Env = append(cmd.Env, fmt.Sprintf("HTTP_PROXY=%s", proxy_address))
96+
cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", proxy_address))
97+
}
98+
if proxy_cert_file != "" {
99+
slog.Info("Setting SSL_CERT_FILE", slog.String("proxy_cert_file", proxy_cert_file))
100+
cmd.Env = append(cmd.Env, fmt.Sprintf("SSL_CERT_FILE=%s", proxy_cert_file))
101+
}
102+
103+
if len(proxy_configs) > 0 {
104+
goproxy_val := "https://proxy.golang.org,direct"
105+
106+
for _, cfg := range proxy_configs {
107+
goproxy_val = cfg.URL + "," + goproxy_val
108+
}
109+
110+
cmd.Env = append(cmd.Env, fmt.Sprintf("GOPROXY=%s", goproxy_val))
111+
cmd.Env = append(cmd.Env, "GOPRIVATE=")
112+
cmd.Env = append(cmd.Env, "GONOPROXY=")
113+
}
114+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package util
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func parseRegistryConfigsFail(t *testing.T, str string) {
8+
_, err := parseRegistryConfigs(str)
9+
10+
if err == nil {
11+
t.Fatal("Expected `parseRegistryConfigs` to fail, but it succeeded.")
12+
}
13+
}
14+
15+
func parseRegistryConfigsSuccess(t *testing.T, str string) []RegistryConfig {
16+
val, err := parseRegistryConfigs(str)
17+
18+
if err != nil {
19+
t.Fatalf("Expected `parseRegistryConfigs` to succeed, but it failed: %s", err.Error())
20+
}
21+
22+
return val
23+
}
24+
25+
func TestParseRegistryConfigs(t *testing.T) {
26+
// parseRegistryConfigsFail(t, "")
27+
28+
empty := parseRegistryConfigsSuccess(t, "[]")
29+
30+
if len(empty) != 0 {
31+
t.Fatal("Expected `parseRegistryConfigs(\"[]\")` to return no configurations, but got some.")
32+
}
33+
34+
single := parseRegistryConfigsSuccess(t, "[{ \"type\": \"goproxy_server\", \"url\": \"https://proxy.example.com/mod\" }]")
35+
36+
if len(single) != 1 {
37+
t.Fatalf("Expected `parseRegistryConfigs` to return one configuration, but got %d.", len(single))
38+
}
39+
40+
first := single[0]
41+
42+
if first.Type != "goproxy_server" {
43+
t.Fatalf("Expected `Type` to be `goproxy_server`, but got `%s`", first.Type)
44+
}
45+
46+
if first.URL != "https://proxy.example.com/mod" {
47+
t.Fatalf("Expected `URL` to be `https://proxy.example.com/mod`, but got `%s`", first.URL)
48+
}
49+
}

0 commit comments

Comments
 (0)