diff --git a/plan/task/gitPull.go b/plan/task/gitPull.go index 789412ec..6922f1f9 100644 --- a/plan/task/gitPull.go +++ b/plan/task/gitPull.go @@ -3,8 +3,10 @@ package task import ( "context" "net/url" + "strings" "github.com/moby/buildkit/client/llb" + "github.com/rs/zerolog/log" "go.dagger.io/dagger/compiler" "go.dagger.io/dagger/plancontext" "go.dagger.io/dagger/solver" @@ -18,53 +20,65 @@ type gitPullTask struct { } func (c gitPullTask) Run(ctx context.Context, pctx *plancontext.Context, s solver.Solver, v *compiler.Value) (*compiler.Value, error) { - remote, err := v.Lookup("remote").String() - if err != nil { - return nil, err - } - ref, err := v.Lookup("ref").String() - if err != nil { - return nil, err + var gitPull struct { + Remote string + Ref string + KeepGitDir bool + Username string } - remoteRedacted := remote - if u, err := url.Parse(remote); err == nil { - remoteRedacted = u.Redacted() + if err := v.Decode(&gitPull); err != nil { + return nil, err } gitOpts := []llb.GitOption{} - var opts struct { - KeepGitDir bool - } - if err := v.Decode(&opts); err != nil { - return nil, err - } + lg := log.Ctx(ctx) - if opts.KeepGitDir { + if gitPull.KeepGitDir { + lg.Debug().Str("keepGitDir", "true").Msg("adding git option") gitOpts = append(gitOpts, llb.KeepGitDir()) } - // Secret - if authToken := v.Lookup("authToken"); authToken.Exists() { + if gitPull.Username != "" { + pwd := v.Lookup("password") + + pwdSecret, err := pctx.Secrets.FromValue(pwd) + if err != nil { + return nil, err + } + + remote, err := url.Parse(gitPull.Remote) + if err != nil { + return nil, err + } + + remote.User = url.UserPassword(gitPull.Username, strings.TrimSpace(pwdSecret.PlainText())) + gitPull.Remote = remote.String() + } else if authToken := v.Lookup("authToken"); plancontext.IsSecretValue(authToken) { authTokenSecret, err := pctx.Secrets.FromValue(authToken) if err != nil { return nil, err } + lg.Debug().Str("authToken", "***").Msg("adding git option") gitOpts = append(gitOpts, llb.AuthTokenSecret(authTokenSecret.ID())) - } - - if authHeader := v.Lookup("authHeader"); authHeader.Exists() { + } else if authHeader := v.Lookup("authHeader"); plancontext.IsSecretValue(authHeader) { authHeaderSecret, err := pctx.Secrets.FromValue(authHeader) if err != nil { return nil, err } + lg.Debug().Str("authHeader", "***").Msg("adding git option") gitOpts = append(gitOpts, llb.AuthHeaderSecret(authHeaderSecret.ID())) } - gitOpts = append(gitOpts, withCustomName(v, "FetchGit %s@%s", remoteRedacted, ref)) + remoteRedacted := gitPull.Remote + if u, err := url.Parse(gitPull.Remote); err == nil { + remoteRedacted = u.Redacted() + } - st := llb.Git(remote, ref, gitOpts...) + gitOpts = append(gitOpts, withCustomName(v, "GitPull %s@%s", remoteRedacted, gitPull.Ref)) + + st := llb.Git(gitPull.Remote, gitPull.Ref, gitOpts...) result, err := s.Solve(ctx, st, pctx.Platform.Get()) if err != nil { diff --git a/stdlib/europa/dagger/engine/git.cue b/stdlib/europa/dagger/engine/git.cue index c21a0b68..83e3fa8c 100644 --- a/stdlib/europa/dagger/engine/git.cue +++ b/stdlib/europa/dagger/engine/git.cue @@ -11,12 +11,21 @@ package engine } // Pull a directory from a git remote +// Note: do not add credentials to the remote url: e.g: https://username:password@github.com +// as this will expose those in logs. By using username and password (as #Secret) Dagger will +// url encode them for you #GitPull: { $dagger: task: _name: "GitPull" - remote: string - ref: string - authToken?: #Secret - authHeader?: #Secret - keepGitDir: true | *false - output: #FS + remote: string + ref: string + keepGitDir: true | *false + { + username: string + password: #Secret // can be password or personal access token + } | { + authToken: #Secret + } | { + authHeader: #Secret + } + output: #FS } diff --git a/tests/tasks/gitPull/privateRepo.cue b/tests/tasks/gitPull/privateRepo.cue index bafdda4d..2aa2be53 100644 --- a/tests/tasks/gitPull/privateRepo.cue +++ b/tests/tasks/gitPull/privateRepo.cue @@ -3,27 +3,29 @@ package main import "alpha.dagger.io/europa/dagger/engine" engine.#Plan & { - inputs: secrets: TestPAT: command: { + inputs: secrets: token: command: { name: "sops" args: ["exec-env", "./privateRepo.enc.yaml", "echo $data"] } + actions: { alpine: engine.#Pull & { - source: "alpine:3.15.0@sha256:e7d88de73db3d3fd9b2d63aa7f447a10fd0220b7cbf39803c803f2af9ba256b3" + source: "alpine:3.15.0" } testRepo: engine.#GitPull & { - remote: "https://github.com/dagger/dagger.git" - ref: "main" - authToken: inputs.secrets.TestPAT.contents + remote: "https://github.com/dagger/dagger.git" + ref: "main" + username: "dagger-test" + password: inputs.secrets.token.contents } testContent: engine.#Exec & { input: alpine.output always: true - args: ["ls", "-l", "/input/repo | grep 'universe -> stdlib'"] + args: ["ls", "-l", "/repo"] mounts: inputRepo: { - dest: "/input/repo" + dest: "/repo" contents: testRepo.output } }