-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add gomod git auth #509
base: main
Are you sure you want to change the base?
feat: Add gomod git auth #509
Conversation
|
91abd07
to
d66c8cd
Compare
generator_gomod.go
Outdated
@@ -1,14 +1,20 @@ | |||
package dalec | |||
|
|||
import ( | |||
"bytes" | |||
_ "embed" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is unused?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
generator_gomod.go
Outdated
gomodCacheDir = "/go/pkg/mod" | ||
gomodCacheDir = "/go/pkg/mod" | ||
gitConfigMountpoint = "/dev/shm/git" | ||
scriptRelativePath = "/go_mod_download.sh" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give this variable a better name?
Truly, I think you can define the const inside the function you are using it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
generator_gomod.go
Outdated
const ( | ||
fourKB = 4096 | ||
workDir = "/work/src" | ||
scriptMountPoint = "/tmp/mnt" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's give this a better path to make sure it's not overwriting anything in the builder image (just in case).
In other places I've done something like /tmp/dalec/internal/...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
generator_gomod.go
Outdated
@@ -54,6 +72,101 @@ func withGomod(g *SourceGenerator, srcSt, worker llb.State, opts ...llb.Constrai | |||
} | |||
} | |||
|
|||
func (g *SourceGenerator) gitconfigGeneratorScript() llb.State { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered utilizing GIT_ASKPASS
or just more generally git credential helpers?
I think it would probably be worthwhile to handle secrets with a helper of some sort that can just read secrets directly from /run/secrets
(where buildkit puts them) instead of trying to deal with the configuration file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK GIT_ASKPASS
won't work with github sources since username/password authentication is not allowed by github. I'll look into the credential helpers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL about GIT_ASKPASS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
abed044
to
a088848
Compare
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks good for my change requests; just have to get Brian G's approval too
2588022
to
3149a03
Compare
@cpuguy83 This should be ready for another round of review. I'll probably have to modify the tests, but I'd like to get your thoughts on the overall approach. |
source.go
Outdated
gm.Auth[host] = gomodAuth | ||
} | ||
|
||
// func (gm *GeneratorGomod) fillDefaults |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leftover?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
2c71e12
to
2c1b3a9
Compare
cmd/frontend/git_credential_gomod.go
Outdated
var errs []error | ||
fill := func(k, v string) { | ||
if v != "" { | ||
if _, err := fmt.Fprintln(&buf, k+"="+v); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that bytes.Buffer
will never return an error on write and this can all be simplified to not bother with error handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
frontend/build.go
Outdated
return llb.Scratch().File(llb.Copy(f, srcPath, dalec.GitCredentialHelperGomod)), nil | ||
} | ||
|
||
func GomodGitCredentialHelperGetter(client gwclient.Client) func() (llb.State, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this just be a closer in gateway.go
rather than giving it an exported function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
cmd/frontend/main.go
Outdated
) | ||
|
||
func main() { | ||
cmd := filepath.Base(os.Args[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was it not possible to tell git to use a subcommand?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this. There are now 2 subcommands, frontend
and credential-helper
. If the subcommand is blank, it behaves as though the subcommand were frontend
.
generator_gomod.go
Outdated
return func(in llb.State) llb.State { | ||
workDir := "/work/src" | ||
const ( | ||
fourKB = 4096 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like this is used anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this and other unused const
s.
generator_gomod.go
Outdated
} | ||
|
||
var b bytes.Buffer | ||
enc := gob.NewEncoder(&b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why gob?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to avoid yaml messiness -- we've already got a go struct, why not keep it that way rather than translating it into another form and back?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly because its a weird encoding and is actually less efficient than the stdlib json encoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By using the filepath to convey the necessary information.
generator_gomod.go
Outdated
continue | ||
} | ||
|
||
fmt.Fprintf(&script, `git config --global credential."https://%s".helper "gomod %s"`, host, configPath) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's give this a name that's more dalec specific?
dalec-git-credentials
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can give it an absolute path also, so I'm just giving it the path to the frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
generator_gomod.go
Outdated
} | ||
|
||
for secret := range secrets { | ||
llb.AddSecret("/run/secrets/"+secret, llb.SecretID(secret)).SetRunOption(ei) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What it help simplify things to mount the secret such that we can find it by host name instead of having to encode configs?
e.g. something like /run/secrets/dalec-git-auth/<host>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking the same thing earlier today. I'll set the destination path on the secrets instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to encode the auth type also (token or header).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
source.go
Outdated
@@ -18,6 +19,11 @@ import ( | |||
"github.com/pkg/errors" | |||
) | |||
|
|||
const ( | |||
GitCredentialHelperGomod = "git-credential-gomod" | |||
GitCredentialHelperGomodSrcDir = "/usr/bin" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem like this is used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed this and others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem like this got removed?
source.go
Outdated
Resolver llb.ImageMetaResolver | ||
Forward ForwarderFunc | ||
GetContext func(string, ...llb.LocalOption) (*llb.State, error) | ||
GitCredentialHelpers map[string]GitCredHelperGetter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't there only ever be one helper here and it doesn't seem like it should be tied to any particular need (e.g. gomod).
This is how we make our buildkit secrets available to git, shouldn't need much more than that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to a func() (llb.RunOption, error)
. The error is thrown if the frontend state can't be acquired. The runopt mounts the frontend at /usr/local/bin/frontend
and can be used anywhere the credential helper is needed.
7157dec
to
0b2fb91
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's think about how we can test these changes in the integration suite.
I think if we can run a service on the host that is accessible to buildkit it shouldn't be a problem (other than just setting up multiple different git services).
cmd/frontend/main.go
Outdated
args := flag.Args()[2:] | ||
// skip os.Args[0] and "credential-helper" | ||
gomodMain(args) | ||
case "", frontendBasename: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit, I think we can remove the frontend
subcommand and just assume if no subcommand is provided then it should be the frontend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
test/testenv/buildx.go
Outdated
@@ -292,6 +307,16 @@ func (b *BuildxEnv) RunTest(ctx context.Context, t *testing.T, f TestFunc, opts | |||
withProjectRoot(t, &so) | |||
withResolveLocal(&so) | |||
|
|||
withSecrets(&so, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like secrets should be a TestRunnerOpt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also doesn't seem like we're actually using this in any tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It got added to the main RunTest
. I'll move it to the test proper as a TestRunnerOpt
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nevermind. This was from before I got rid of the integration tests. I changed it to use TestRunnerOpt
s and I'll use it when I add the integration tests.
I don't know how we do this without monkeying around with network namespaces. If that's the case, the tests would only run on linux. Setting the namespaces such that the frontend can communicate with a service running on the host requires root privileges. |
98c11a6
to
bf5b5cc
Compare
Dockerfile
Outdated
@@ -1,4 +1,4 @@ | |||
FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/oss/go/microsoft/golang:1.22@sha256:9e5243001d0f43d6e1c556a0ce8eedc1bc80eb37b5210036b289d2c601bc08b6 AS go | |||
FROM --platform=${BUILDPLATFORM} mcr.microsoft.com/oss/go/microsoft/golang:1.24@sha256:7c2024496593127e761a4610d628e7f653168342e7b60b21d6745adc236b0bd9 AS go |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should stick with 1.23 here (which, IIRC dependabot updated this week)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test can't run locally for me due to this error (beyond needing to add the platform to the image refs used).
go: host.docker.internal/user/private.git@v0.0.0: no secure protocol found for repository
.gitmodules
Outdated
@@ -0,0 +1,3 @@ | |||
[submodule "test/fixtures/git/user/private"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something we need to commit to the repo?
I feel like we should be able to create a repo on the fly without submodules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed, now creating repo on the fly
frontend/debug/handle_sources.go
Outdated
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
res, err := client.Solve(ctx, gwclient.SolveRequest{ | ||
Definition: def.ToPB(), | ||
FrontendOpt: map[string]string{ | ||
"add-hosts": "host.docker.internal=10.0.2.2", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should probably be copied in from the client opts rather than hard-coding it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mistake that I left this in, thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
frontend/gateway.go
Outdated
@@ -74,6 +74,9 @@ func ForwarderFromClient(ctx context.Context, client gwclient.Client) dalec.Forw | |||
req, err := newSolveRequest( | |||
toDockerfile(ctx, st, dockerfileDt, spec, dalec.ProgressGroup("prepare dockerfile to forward to frontend")), | |||
copyForForward(ctx, client), | |||
func(sr *gwclient.SolveRequest) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Started doing something here, then took another approach. Left it in by mistake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
generator_gomod.go
Outdated
@@ -41,19 +50,108 @@ func withGomod(g *SourceGenerator, srcSt, worker llb.State, opts ...llb.Constrai | |||
paths = []string{"."} | |||
} | |||
|
|||
sort.Strings(paths) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paths
is already ordered by the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
source.go
Outdated
@@ -18,6 +19,11 @@ import ( | |||
"github.com/pkg/errors" | |||
) | |||
|
|||
const ( | |||
GitCredentialHelperGomod = "git-credential-gomod" | |||
GitCredentialHelperGomodSrcDir = "/usr/bin" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't seem like this got removed?
test/source_test.go
Outdated
return pid | ||
} | ||
|
||
func runGitServer(addr string, port int) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you pass through a *testing.T
shutdown the listener in a t.Cleanup
function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
}, | ||
} | ||
|
||
outsideAddr, insideAddr := getGitServerAddrs(ctx, t, c) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we are using these values anywhere other than runGitServer
, maybe it makes sense to have runGitServer
handle all the things here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
insideAddr
gets added as an extra host a few lines down.
})) | ||
} | ||
|
||
func initGomodWorker(c gwclient.Client, host string, port int) llb.State { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain why we need to configure git this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because you can't have a port number in a go module name. We tell git to use host:port
so that when go invokes git to fetch the module, git knows to use host:port
instead of just host
. This is all because the git server is not running on 443/80, because we're starting our own git server on localhost and can't use those ports without privileges.
922a79c
to
7a679a8
Compare
Can you please try this again with the latest changes? I was experiencing the same error this morning but I believe it's fixed now. |
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
The LLB has changed substantially since we adoped git credential helpers. We now check: - SSH sockets will be mounted - Secrets will be mounted as files (not provided in the environment) - The gomod credential helper will be mounted - The auth config and `go mod download` wrapper script will be mounted Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Instead, use the `gob` package to encode/decode the bytes. This is to avoid errors that might arise from the marshaling/unmarshaling to YAML. Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
- Use the filepath of the secret mount to communicate with the credential helper - Clean up the credential helper - Handle cli flags properly - Modified the unit tests to reflect changes to llb operations - Various other small fixes as requested Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Some of the unit tests do not use valid hosts. Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
8aaf10c
to
a86107f
Compare
Also improve variable naming in credential helper. Signed-off-by: Peter Engelbert <pmengelbert@gmail.com>
See Commit Descriptions