bake: git auth support for remote definitions

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax 2024-03-28 08:38:35 +01:00
parent 38fbd9a85c
commit 4d39259f8e
No known key found for this signature in database
GPG Key ID: ADE44D8C9D44FBE4
3 changed files with 101 additions and 7 deletions

View File

@ -4,6 +4,8 @@ import (
"archive/tar" "archive/tar"
"bytes" "bytes"
"context" "context"
"os"
"strings"
"github.com/docker/buildx/builder" "github.com/docker/buildx/builder"
controllerapi "github.com/docker/buildx/controller/pb" controllerapi "github.com/docker/buildx/controller/pb"
@ -23,13 +25,34 @@ type Input struct {
} }
func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, names []string, pw progress.Writer) ([]File, *Input, error) { func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, names []string, pw progress.Writer) ([]File, *Input, error) {
var session []session.Attachable var sessions []session.Attachable
var filename string var filename string
st, ok := dockerui.DetectGitContext(url, false) st, ok := dockerui.DetectGitContext(url, false)
if ok { if ok {
ssh, err := controllerapi.CreateSSH([]*controllerapi.SSH{{ID: "default"}}) if ssh, err := controllerapi.CreateSSH([]*controllerapi.SSH{{
if err == nil { ID: "default",
session = append(session, ssh) Paths: strings.Split(os.Getenv("BUILDX_BAKE_GIT_SSH"), ","),
}}); err == nil {
sessions = append(sessions, ssh)
}
var gitAuthSecrets []*controllerapi.Secret
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_TOKEN"); ok {
gitAuthSecrets = append(gitAuthSecrets, &controllerapi.Secret{
ID: llb.GitAuthTokenKey,
Env: "BUILDX_BAKE_GIT_AUTH_TOKEN",
})
}
if _, ok := os.LookupEnv("BUILDX_BAKE_GIT_AUTH_HEADER"); ok {
gitAuthSecrets = append(gitAuthSecrets, &controllerapi.Secret{
ID: llb.GitAuthHeaderKey,
Env: "BUILDX_BAKE_GIT_AUTH_HEADER",
})
}
if len(gitAuthSecrets) > 0 {
if secrets, err := controllerapi.CreateSecrets(gitAuthSecrets); err == nil {
sessions = append(sessions, secrets)
}
} }
} else { } else {
st, filename, ok = dockerui.DetectHTTPContext(url) st, filename, ok = dockerui.DetectHTTPContext(url)
@ -59,7 +82,7 @@ func ReadRemoteFiles(ctx context.Context, nodes []builder.Node, url string, name
ch, done := progress.NewChannel(pw) ch, done := progress.NewChannel(pw)
defer func() { <-done }() defer func() { <-done }()
_, err = c.Build(ctx, client.SolveOpt{Session: session, Internal: true}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) { _, err = c.Build(ctx, client.SolveOpt{Session: sessions, Internal: true}, "buildx", func(ctx context.Context, c gwclient.Client) (*gwclient.Result, error) {
def, err := st.Marshal(ctx) def, err := st.Marshal(ctx)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -29,6 +29,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){
testBakeLocal, testBakeLocal,
testBakeLocalMulti, testBakeLocalMulti,
testBakeRemote, testBakeRemote,
testBakeRemoteAuth,
testBakeRemoteCmdContext, testBakeRemoteCmdContext,
testBakeRemoteLocalOverride, testBakeRemoteLocalOverride,
testBakeLocalCwdOverride, testBakeLocalCwdOverride,
@ -144,6 +145,41 @@ EOT
require.FileExists(t, filepath.Join(dirDest, "foo")) require.FileExists(t, filepath.Join(dirDest, "foo"))
} }
func testBakeRemoteAuth(t *testing.T, sb integration.Sandbox) {
bakefile := []byte(`
target "default" {
dockerfile-inline = <<EOT
FROM scratch
COPY foo /foo
EOT
}
`)
dir := tmpdir(
t,
fstest.CreateFile("docker-bake.hcl", bakefile, 0600),
fstest.CreateFile("foo", []byte("foo"), 0600),
)
dirDest := t.TempDir()
git, err := gitutil.New(gitutil.WithWorkingDir(dir))
require.NoError(t, err)
gitutil.GitInit(git, t)
gitutil.GitAdd(git, t, "docker-bake.hcl", "foo")
gitutil.GitCommit(git, t, "initial commit")
token := identity.NewID()
addr := gitutil.GitServeHTTP(git, t, gitutil.WithAccessToken(token))
out, err := bakeCmd(sb, withDir(dir),
withEnv("BUILDX_BAKE_GIT_AUTH_TOKEN="+token),
withArgs(addr, "--set", "*.output=type=local,dest="+dirDest),
)
require.NoError(t, err, out)
require.FileExists(t, filepath.Join(dirDest, "foo"))
}
func testBakeRemoteLocalOverride(t *testing.T, sb integration.Sandbox) { func testBakeRemoteLocalOverride(t *testing.T, sb integration.Sandbox) {
remoteBakefile := []byte(` remoteBakefile := []byte(`
target "default" { target "default" {

View File

@ -10,11 +10,28 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func GitServeHTTP(c *Git, t testing.TB) (url string) { type gitServe struct {
token string
}
type GitServeOpt func(*gitServe)
func WithAccessToken(token string) GitServeOpt {
return func(s *gitServe) {
s.token = token
}
}
func GitServeHTTP(c *Git, t testing.TB, opts ...GitServeOpt) (url string) {
t.Helper() t.Helper()
gitUpdateServerInfo(c, t) gitUpdateServerInfo(c, t)
ctx, cancel := context.WithCancel(context.TODO()) ctx, cancel := context.WithCancel(context.TODO())
gs := &gitServe{}
for _, opt := range opts {
opt(gs)
}
ready := make(chan struct{}) ready := make(chan struct{})
done := make(chan struct{}) done := make(chan struct{})
@ -28,7 +45,25 @@ func GitServeHTTP(c *Git, t testing.TB) (url string) {
go func() { go func() {
mux := http.NewServeMux() mux := http.NewServeMux()
prefix := fmt.Sprintf("/%s/", name) prefix := fmt.Sprintf("/%s/", name)
mux.Handle(prefix, http.StripPrefix(prefix, http.FileServer(http.Dir(dir))))
handler := func(next http.Handler) http.Handler {
var tokenChecked bool
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if gs.token != "" && !tokenChecked {
t.Logf("git access token to check: %q", gs.token)
user, pass, _ := r.BasicAuth()
t.Logf("basic auth: user=%q pass=%q", user, pass)
if pass != gs.token {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
tokenChecked = true
}
next.ServeHTTP(w, r)
})
}
mux.Handle(prefix, handler(http.StripPrefix(prefix, http.FileServer(http.Dir(dir)))))
l, err := net.Listen("tcp", "localhost:0") l, err := net.Listen("tcp", "localhost:0")
if err != nil { if err != nil {
panic(err) panic(err)