Skip to content

Commit 8573243

Browse files
committed
bake: support host-suffixed git auth env vars
Signed-off-by: CrazyMax <[email protected]>
1 parent 06f438a commit 8573243

File tree

5 files changed

+161
-25
lines changed

5 files changed

+161
-25
lines changed

bake/bake.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,18 +1508,7 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
15081508

15091509
secrets := t.Secrets
15101510
if isRemoteContext(bi, inp) {
1511-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
1512-
secrets = append(secrets, &buildflags.Secret{
1513-
ID: llb.GitAuthTokenKey,
1514-
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
1515-
})
1516-
}
1517-
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
1518-
secrets = append(secrets, &buildflags.Secret{
1519-
ID: llb.GitAuthHeaderKey,
1520-
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
1521-
})
1522-
}
1511+
secrets = append(secrets, gitAuthSecretsFromEnv()...)
15231512
}
15241513
bo.SecretSpecs = secrets.Normalize()
15251514
secretAttachment, err := build.CreateSecrets(bo.SecretSpecs)

bake/gitauth.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
)
11+
12+
const (
13+
bakeGitAuthTokenEnv = "BUILDX_BAKE_GIT_AUTH_TOKEN" // #nosec G101 -- environment variable key, not a credential
14+
bakeGitAuthHeaderEnv = "BUILDX_BAKE_GIT_AUTH_HEADER"
15+
)
16+
17+
func gitAuthSecretsFromEnv() buildflags.Secrets {
18+
return gitAuthSecretsFromEnviron(os.Environ())
19+
}
20+
21+
func gitAuthSecretsFromEnviron(environ []string) buildflags.Secrets {
22+
secrets := make(buildflags.Secrets, 0, 2)
23+
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthTokenKey, bakeGitAuthTokenEnv, environ)...)
24+
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthHeaderKey, bakeGitAuthHeaderEnv, environ)...)
25+
return secrets
26+
}
27+
28+
func gitAuthSecretsForEnv(secretIDPrefix, envPrefix string, environ []string) buildflags.Secrets {
29+
envKeys := findGitAuthEnvKeys(envPrefix, environ)
30+
secrets := make(buildflags.Secrets, 0, len(envKeys))
31+
for _, envKey := range envKeys {
32+
suffix := envKey[len(envPrefix):]
33+
secrets = append(secrets, &buildflags.Secret{
34+
ID: secretIDPrefix + suffix,
35+
Env: envKey,
36+
})
37+
}
38+
return secrets
39+
}
40+
41+
func findGitAuthEnvKeys(envPrefix string, environ []string) []string {
42+
prefixUpper := strings.ToUpper(envPrefix)
43+
var keys []string
44+
for _, env := range environ {
45+
key, _, ok := strings.Cut(env, "=")
46+
if !ok {
47+
continue
48+
}
49+
if !strings.HasPrefix(strings.ToUpper(key), prefixUpper) {
50+
continue
51+
}
52+
if len(key) == len(envPrefix) {
53+
keys = append(keys, key)
54+
continue
55+
}
56+
if len(key) <= len(envPrefix)+1 {
57+
continue
58+
}
59+
if key[len(envPrefix)] == '.' {
60+
keys = append(keys, key)
61+
}
62+
}
63+
sort.Strings(keys)
64+
return keys
65+
}

bake/gitauth_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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("domain suffix keys", func(t *testing.T) {
23+
secrets := gitAuthSecretsFromEnviron([]string{
24+
bakeGitAuthTokenEnv + ".github.com=token",
25+
bakeGitAuthHeaderEnv + ".github.com=bearer",
26+
bakeGitAuthTokenEnv + ".example.com=token2",
27+
bakeGitAuthTokenEnv + "=fallback",
28+
})
29+
require.Equal(t, []string{
30+
llb.GitAuthTokenKey + "|" + bakeGitAuthTokenEnv,
31+
llb.GitAuthTokenKey + ".example.com|" + bakeGitAuthTokenEnv + ".example.com",
32+
llb.GitAuthTokenKey + ".github.com|" + bakeGitAuthTokenEnv + ".github.com",
33+
llb.GitAuthHeaderKey + ".github.com|" + bakeGitAuthHeaderEnv + ".github.com",
34+
}, secretPairs(secrets))
35+
})
36+
t.Run("ignores non-domain suffix", func(t *testing.T) {
37+
secrets := gitAuthSecretsFromEnviron([]string{
38+
bakeGitAuthTokenEnv + "_EXTRA=token",
39+
bakeGitAuthHeaderEnv + "-extra=basic",
40+
bakeGitAuthTokenEnv + ".=bad",
41+
bakeGitAuthHeaderEnv + ".=bad",
42+
})
43+
require.Empty(t, secrets)
44+
})
45+
}
46+
47+
func secretPairs(secrets buildflags.Secrets) []string {
48+
out := make([]string, 0, len(secrets))
49+
for _, s := range secrets {
50+
out = append(out, s.ID+"|"+s.Env)
51+
}
52+
return out
53+
}

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()
6048
if len(gitAuthSecrets) > 0 {
6149
if secrets, err := build.CreateSecrets(gitAuthSecrets); err == nil {
6250
sessions = append(sessions, secrets)

tests/bake.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"encoding/json"
99
"encoding/pem"
1010
"fmt"
11+
"net/url"
1112
"os"
1213
"path/filepath"
1314
"strconv"
@@ -45,6 +46,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
4546
testBakeLocalMulti,
4647
testBakeRemote,
4748
testBakeRemoteAuth,
49+
testBakeRemoteAuthHostSuffix,
4850
testBakeRemoteCmdContext,
4951
testBakeRemoteLocalOverride,
5052
testBakeLocalCwdOverride,
@@ -662,6 +664,45 @@ EOT
662664
require.FileExists(t, filepath.Join(dirDest, "foo"))
663665
}
664666

667+
func testBakeRemoteAuthHostSuffix(t *testing.T, sb integration.Sandbox) {
668+
bakefile := []byte(`
669+
target "default" {
670+
dockerfile-inline = <<EOT
671+
FROM scratch
672+
COPY foo /foo
673+
EOT
674+
}
675+
`)
676+
dir := tmpdir(
677+
t,
678+
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
679+
fstest.CreateFile("foo", []byte("foo"), 0600),
680+
)
681+
dirDest := t.TempDir()
682+
683+
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
684+
require.NoError(t, err)
685+
686+
gittestutil.GitInit(git, t)
687+
gittestutil.GitAdd(git, t, "docker-bake.hcl", "foo")
688+
gittestutil.GitCommit(git, t, "initial commit")
689+
690+
token := identity.NewID()
691+
addr := gittestutil.GitServeHTTP(git, t, gittestutil.WithAccessToken(token))
692+
parsed, err := url.Parse(addr)
693+
require.NoError(t, err)
694+
host := parsed.Hostname()
695+
require.NotEmpty(t, host)
696+
697+
out, err := bakeCmd(sb, withDir(dir),
698+
withEnv("BUILDX_BAKE_GIT_AUTH_TOKEN."+host+"="+token),
699+
withArgs(addr, "--set", "*.output=type=local,dest="+dirDest),
700+
)
701+
require.NoError(t, err, out)
702+
703+
require.FileExists(t, filepath.Join(dirDest, "foo"))
704+
}
705+
665706
func testBakeRemoteLocalOverride(t *testing.T, sb integration.Sandbox) {
666707
remoteBakefile := []byte(`
667708
target "default" {

0 commit comments

Comments
 (0)