Merge pull request #3648 from crazy-max/bake-auth-token-domain
bake: derive git auth host from remote URL
This commit is contained in:
+2
-23
@@ -1330,16 +1330,6 @@ func updateContext(t *build.Inputs, inp *Input) {
|
|||||||
t.ContextPath = inp.URL
|
t.ContextPath = inp.URL
|
||||||
}
|
}
|
||||||
|
|
||||||
func isRemoteContext(t build.Inputs, inp *Input) bool {
|
|
||||||
if urlutil.IsRemoteURL(t.ContextPath) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if inp != nil && urlutil.IsRemoteURL(inp.URL) && !strings.HasPrefix(t.ContextPath, "cwd://") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectLocalPaths(t build.Inputs) []string {
|
func collectLocalPaths(t build.Inputs) []string {
|
||||||
var out []string
|
var out []string
|
||||||
if t.ContextState == nil {
|
if t.ContextState == nil {
|
||||||
@@ -1509,19 +1499,8 @@ func toBuildOpt(t *Target, inp *Input) (*build.Options, error) {
|
|||||||
bo.Platforms = platforms
|
bo.Platforms = platforms
|
||||||
|
|
||||||
secrets := t.Secrets
|
secrets := t.Secrets
|
||||||
if isRemoteContext(bi, inp) {
|
if inp != nil && shouldAttachGitAuthSecrets(inp.URL, bi.ContextPath) {
|
||||||
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
|
secrets = append(secrets, gitAuthSecretsFromEnv(inp.URL)...)
|
||||||
secrets = append(secrets, &buildflags.Secret{
|
|
||||||
ID: llb.GitAuthTokenKey,
|
|
||||||
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
|
|
||||||
secrets = append(secrets, &buildflags.Secret{
|
|
||||||
ID: llb.GitAuthHeaderKey,
|
|
||||||
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bo.SecretSpecs = secrets.Normalize()
|
bo.SecretSpecs = secrets.Normalize()
|
||||||
secretAttachment, err := build.CreateSecrets(bo.SecretSpecs)
|
secretAttachment, err := build.CreateSecrets(bo.SecretSpecs)
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package bake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/buildx/util/buildflags"
|
||||||
|
"github.com/docker/buildx/util/urlutil"
|
||||||
|
"github.com/moby/buildkit/client/llb"
|
||||||
|
"github.com/moby/buildkit/util/gitutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
bakeGitAuthTokenEnv = "BUILDX_BAKE_GIT_AUTH_TOKEN" // #nosec G101 -- environment variable key, not a credential
|
||||||
|
bakeGitAuthHeaderEnv = "BUILDX_BAKE_GIT_AUTH_HEADER"
|
||||||
|
)
|
||||||
|
|
||||||
|
func gitAuthSecretsFromEnv(remoteURL string) buildflags.Secrets {
|
||||||
|
return gitAuthSecretsFromEnviron(os.Environ(), remoteURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitAuthSecretsFromEnviron(environ []string, remoteURL string) buildflags.Secrets {
|
||||||
|
host, ok := gitAuthHostFromURL(remoteURL)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
secrets := make(buildflags.Secrets, 0, 2)
|
||||||
|
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthTokenKey, bakeGitAuthTokenEnv, environ, host)...)
|
||||||
|
secrets = append(secrets, gitAuthSecretsForEnv(llb.GitAuthHeaderKey, bakeGitAuthHeaderEnv, environ, host)...)
|
||||||
|
return secrets
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitAuthSecretsForEnv(secretIDPrefix, envPrefix string, environ []string, host string) buildflags.Secrets {
|
||||||
|
envKey, ok := findGitAuthEnvKey(envPrefix, environ)
|
||||||
|
if !ok || host == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return buildflags.Secrets{&buildflags.Secret{
|
||||||
|
ID: secretIDPrefix + "." + host,
|
||||||
|
Env: envKey,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func shouldAttachGitAuthSecrets(inputURL, contextPath string) bool {
|
||||||
|
if !urlutil.IsRemoteURL(inputURL) || !urlutil.IsRemoteURL(contextPath) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
inputHost, ok := gitAuthHostFromURL(inputURL)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
contextHost, ok := gitAuthHostFromURL(contextPath)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.EqualFold(inputHost, contextHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitAuthHostFromURL(remoteURL string) (string, bool) {
|
||||||
|
gitURL, err := gitutil.ParseURL(remoteURL)
|
||||||
|
if err != nil || gitURL.Host == "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
return gitURL.Host, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func findGitAuthEnvKey(envKey string, environ []string) (string, bool) {
|
||||||
|
for _, env := range environ {
|
||||||
|
key, _, ok := strings.Cut(env, "=")
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.EqualFold(key, envKey) {
|
||||||
|
return key, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package bake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/buildx/util/buildflags"
|
||||||
|
"github.com/moby/buildkit/client/llb"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGitAuthSecretsFromEnviron(t *testing.T) {
|
||||||
|
t.Run("empty without remote url", func(t *testing.T) {
|
||||||
|
secrets := gitAuthSecretsFromEnviron([]string{
|
||||||
|
bakeGitAuthTokenEnv + "=token",
|
||||||
|
bakeGitAuthHeaderEnv + "=basic",
|
||||||
|
}, "")
|
||||||
|
require.Empty(t, secrets)
|
||||||
|
})
|
||||||
|
t.Run("derives host from remote url", func(t *testing.T) {
|
||||||
|
secrets := gitAuthSecretsFromEnviron([]string{
|
||||||
|
bakeGitAuthTokenEnv + "=token",
|
||||||
|
bakeGitAuthHeaderEnv + "=basic",
|
||||||
|
}, "https://example.com/org/repo.git")
|
||||||
|
require.Equal(t, []string{
|
||||||
|
llb.GitAuthTokenKey + ".example.com|" + bakeGitAuthTokenEnv,
|
||||||
|
llb.GitAuthHeaderKey + ".example.com|" + bakeGitAuthHeaderEnv,
|
||||||
|
}, secretPairs(secrets))
|
||||||
|
})
|
||||||
|
t.Run("ignores host suffixed keys", func(t *testing.T) {
|
||||||
|
secrets := gitAuthSecretsFromEnviron([]string{
|
||||||
|
bakeGitAuthTokenEnv + ".example.com=token",
|
||||||
|
bakeGitAuthHeaderEnv + ".example.com=basic",
|
||||||
|
}, "https://example.com/org/repo.git")
|
||||||
|
require.Empty(t, secrets)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldAttachGitAuthSecrets(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
inputURL string
|
||||||
|
contextPath string
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "same host http urls",
|
||||||
|
inputURL: "https://example.com/org/repo.git",
|
||||||
|
contextPath: "https://example.com/another/repo.git",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "same host mixed git url styles",
|
||||||
|
inputURL: "https://example.com/org/repo.git",
|
||||||
|
contextPath: "git@example.com:another/repo.git",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "different hosts",
|
||||||
|
inputURL: "https://example.com/org/repo.git",
|
||||||
|
contextPath: "https://other.example.com/org/repo.git",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non remote context",
|
||||||
|
inputURL: "https://example.com/org/repo.git",
|
||||||
|
contextPath: "cwd://src",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
require.Equal(t, tt.want, shouldAttachGitAuthSecrets(tt.inputURL, tt.contextPath))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func secretPairs(secrets buildflags.Secrets) []string {
|
||||||
|
out := make([]string, 0, len(secrets))
|
||||||
|
for _, s := range secrets {
|
||||||
|
out = append(out, s.ID+"|"+s.Env)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
+1
-14
@@ -44,20 +44,7 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
|
|||||||
}}); err == nil {
|
}}); err == nil {
|
||||||
sessions = append(sessions, ssh)
|
sessions = append(sessions, ssh)
|
||||||
}
|
}
|
||||||
var gitAuthSecrets []*buildflags.Secret
|
if gitAuthSecrets := gitAuthSecretsFromEnv(url); len(gitAuthSecrets) > 0 {
|
||||||
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
|
|
||||||
gitAuthSecrets = append(gitAuthSecrets, &buildflags.Secret{
|
|
||||||
ID: llb.GitAuthTokenKey,
|
|
||||||
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
|
|
||||||
gitAuthSecrets = append(gitAuthSecrets, &buildflags.Secret{
|
|
||||||
ID: llb.GitAuthHeaderKey,
|
|
||||||
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if len(gitAuthSecrets) > 0 {
|
|
||||||
if secrets, err := build.CreateSecrets(gitAuthSecrets); err == nil {
|
if secrets, err := build.CreateSecrets(gitAuthSecrets); err == nil {
|
||||||
sessions = append(sessions, secrets)
|
sessions = append(sessions, secrets)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user