Skip to content

Commit eebe1e5

Browse files
committed
bake: derive git auth host from remote URL
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent 53882ae commit eebe1e5

File tree

4 files changed

+154
-25
lines changed

4 files changed

+154
-25
lines changed

bake/bake.go

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,6 +1340,29 @@ func isRemoteContext(t build.Inputs, inp *Input) bool {
13401340
return false
13411341
}
13421342

1343+
func remoteContextURLs(t build.Inputs, inp *Input) []string {
1344+
urls := make([]string, 0, len(t.NamedContexts)+2)
1345+
seen := make(map[string]struct{}, len(t.NamedContexts)+2)
1346+
add := func(rawURL string) {
1347+
if !urlutil.IsRemoteURL(rawURL) {
1348+
return
1349+
}
1350+
if _, ok := seen[rawURL]; ok {
1351+
return
1352+
}
1353+
seen[rawURL] = struct{}{}
1354+
urls = append(urls, rawURL)
1355+
}
1356+
add(t.ContextPath)
1357+
for _, v := range t.NamedContexts {
1358+
add(v.Path)
1359+
}
1360+
if inp != nil {
1361+
add(inp.URL)
1362+
}
1363+
return urls
1364+
}
1365+
13431366
func collectLocalPaths(t build.Inputs) []string {
13441367
var out []string
13451368
if t.ContextState == nil {
@@ -1510,18 +1533,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
15101533

15111534
secrets := t.Secrets
15121535
if isRemoteContext(bi, inp) {
1513-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
1514-
secrets = append(secrets, &buildflags.Secret{
1515-
ID: llb.GitAuthTokenKey,
1516-
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
1517-
})
1518-
}
1519-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
1520-
secrets = append(secrets, &buildflags.Secret{
1521-
ID: llb.GitAuthHeaderKey,
1522-
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
1523-
})
1524-
}
1536+
secrets = append(secrets, gitAuthSecretsFromEnv(remoteContextURLs(bi, inp)...)...)
15251537
}
15261538
bo.SecretSpecs = secrets.Normalize()
15271539
secretAttachment, err := build.CreateSecrets(bo.SecretSpecs)

bake/gitauth.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package bake
2+
3+
import (
4+
"os"
5+
"sort"
6+
"strings"
7+
8+
"github.com/docker/buildx/util/buildflags"
9+
"github.com/moby/buildkit/client/llb"
10+
"github.com/moby/buildkit/util/gitutil"
11+
)
12+
13+
const (
14+
bakeGitAuthTokenEnv = "BUILDX_BAKE_GIT_AUTH_TOKEN" // #nosec G101 -- environment variable key, not a credential
15+
bakeGitAuthHeaderEnv = "BUILDX_BAKE_GIT_AUTH_HEADER"
16+
)
17+
18+
func gitAuthSecretsFromEnv(remoteURLs ...string) buildflags.Secrets {
19+
return gitAuthSecretsFromEnviron(os.Environ(), remoteURLs...)
20+
}
21+
22+
func gitAuthSecretsFromEnviron(environ []string, remoteURLs ...string) buildflags.Secrets {
23+
hosts := gitAuthHostsFromURLs(remoteURLs)
24+
secrets := make(buildflags.Secrets, 0, 2)
25+
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthTokenKey, bakeGitAuthTokenEnv, environ, hosts)...)
26+
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthHeaderKey, bakeGitAuthHeaderEnv, environ, hosts)...)
27+
return secrets
28+
}
29+
30+
func gitAuthSecretsForEnv(secretIDPrefix, envPrefix string, environ []string, hosts []string) buildflags.Secrets {
31+
envKey, ok := findGitAuthEnvKey(envPrefix, environ)
32+
if !ok {
33+
return nil
34+
}
35+
secrets := make(buildflags.Secrets, 0, len(hosts)+1)
36+
secrets = append(secrets, &buildflags.Secret{
37+
ID: secretIDPrefix,
38+
Env: envKey,
39+
})
40+
for _, host := range hosts {
41+
secrets = append(secrets, &buildflags.Secret{
42+
ID: secretIDPrefix + "." + host,
43+
Env: envKey,
44+
})
45+
}
46+
return secrets
47+
}
48+
49+
func gitAuthHostsFromURLs(remoteURLs []string) []string {
50+
if len(remoteURLs) == 0 {
51+
return nil
52+
}
53+
hosts := make(map[string]struct{}, len(remoteURLs))
54+
for _, remoteURL := range remoteURLs {
55+
gitURL, err := gitutil.ParseURL(remoteURL)
56+
if err != nil || gitURL.Host == "" {
57+
continue
58+
}
59+
hosts[gitURL.Host] = struct{}{}
60+
}
61+
out := make([]string, 0, len(hosts))
62+
for host := range hosts {
63+
out = append(out, host)
64+
}
65+
sort.Strings(out)
66+
return out
67+
}
68+
69+
func findGitAuthEnvKey(envKey string, environ []string) (string, bool) {
70+
for _, env := range environ {
71+
key, _, ok := strings.Cut(env, "=")
72+
if !ok {
73+
continue
74+
}
75+
if strings.EqualFold(key, envKey) {
76+
return key, true
77+
}
78+
}
79+
return "", false
80+
}

bake/gitauth_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package bake
2+
3+
import (
4+
"testing"
5+
6+
"github.com/docker/buildx/util/buildflags"
7+
"github.com/moby/buildkit/client/llb"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
func TestGitAuthSecretsFromEnviron(t *testing.T) {
12+
t.Run("base keys", func(t *testing.T) {
13+
secrets := gitAuthSecretsFromEnviron([]string{
14+
bakeGitAuthTokenEnv + "=token",
15+
bakeGitAuthHeaderEnv + "=basic",
16+
})
17+
require.Equal(t, []string{
18+
llb.GitAuthTokenKey + "|" + bakeGitAuthTokenEnv,
19+
llb.GitAuthHeaderKey + "|" + bakeGitAuthHeaderEnv,
20+
}, secretPairs(secrets))
21+
})
22+
t.Run("derives host from remote url", func(t *testing.T) {
23+
secrets := gitAuthSecretsFromEnviron([]string{
24+
bakeGitAuthTokenEnv + "=token",
25+
bakeGitAuthHeaderEnv + "=basic",
26+
}, "https://example.com/org/repo.git")
27+
require.Equal(t, []string{
28+
llb.GitAuthTokenKey + "|" + bakeGitAuthTokenEnv,
29+
llb.GitAuthTokenKey + ".example.com|" + bakeGitAuthTokenEnv,
30+
llb.GitAuthHeaderKey + "|" + bakeGitAuthHeaderEnv,
31+
llb.GitAuthHeaderKey + ".example.com|" + bakeGitAuthHeaderEnv,
32+
}, secretPairs(secrets))
33+
})
34+
t.Run("ignores host suffixed keys", func(t *testing.T) {
35+
secrets := gitAuthSecretsFromEnviron([]string{
36+
bakeGitAuthTokenEnv + ".example.com=token",
37+
bakeGitAuthHeaderEnv + ".example.com=basic",
38+
})
39+
require.Empty(t, secrets)
40+
})
41+
}
42+
43+
func secretPairs(secrets buildflags.Secrets) []string {
44+
out := make([]string, 0, len(secrets))
45+
for _, s := range secrets {
46+
out = append(out, s.ID+"|"+s.Env)
47+
}
48+
return out
49+
}

bake/remote.go

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,7 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
4444
}}); err == nil {
4545
sessions = append(sessions, ssh)
4646
}
47-
var gitAuthSecrets []*buildflags.Secret
48-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
49-
gitAuthSecrets = append(gitAuthSecrets, &buildflags.Secret{
50-
ID: llb.GitAuthTokenKey,
51-
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
52-
})
53-
}
54-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
55-
gitAuthSecrets = append(gitAuthSecrets, &buildflags.Secret{
56-
ID: llb.GitAuthHeaderKey,
57-
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
58-
})
59-
}
47+
gitAuthSecrets := gitAuthSecretsFromEnv(url)
6048
if len(gitAuthSecrets) > 0 {
6149
if secrets, err := build.CreateSecrets(gitAuthSecrets); err == nil {
6250
sessions = append(sessions, secrets)

0 commit comments

Comments
 (0)