Allow Athens to Propagate Authentication to Mod Download (#1650)

* Allow Athens to Propagate Authentication to Mod Download

* update readme

* add pattern matching to auth propagation

* Propagate authentication to pre declared static host

* quote redis test

* fix flaky redis error message

* fix config tests

* fix config tests

* Update config.dev.toml

Co-authored-by: Ted Wexler <ted@stuckinacan.com>

* gofmt

Co-authored-by: Ted Wexler <ted@stuckinacan.com>
This commit is contained in:
Marwan Sulaiman
2020-07-30 17:06:53 -04:00
committed by GitHub
parent 81906b918f
commit dfb7887080
19 changed files with 546 additions and 135 deletions
+37 -15
View File
@@ -10,6 +10,7 @@ import (
"path/filepath"
"strings"
"github.com/gomods/athens/pkg/auth"
"github.com/gomods/athens/pkg/errors"
"github.com/gomods/athens/pkg/observ"
"github.com/gomods/athens/pkg/storage"
@@ -17,10 +18,11 @@ import (
)
type goGetFetcher struct {
fs afero.Fs
goBinaryName string
envVars []string
gogetDir string
fs afero.Fs
goBinaryName string
envVars []string
gogetDir string
propagateAuthHost string
}
type goModule struct {
@@ -36,16 +38,17 @@ type goModule struct {
}
// NewGoGetFetcher creates fetcher which uses go get tool to fetch modules
func NewGoGetFetcher(goBinaryName, gogetDir string, envVars []string, fs afero.Fs) (Fetcher, error) {
func NewGoGetFetcher(goBinaryName, gogetDir string, envVars []string, fs afero.Fs, propagateAuthHost string) (Fetcher, error) {
const op errors.Op = "module.NewGoGetFetcher"
if err := validGoBinary(goBinaryName); err != nil {
return nil, errors.E(op, err)
}
return &goGetFetcher{
fs: fs,
goBinaryName: goBinaryName,
envVars: envVars,
gogetDir: gogetDir,
fs: fs,
goBinaryName: goBinaryName,
envVars: envVars,
gogetDir: gogetDir,
propagateAuthHost: propagateAuthHost,
}, nil
}
@@ -68,7 +71,7 @@ func (g *goGetFetcher) Fetch(ctx context.Context, mod, ver string) (*storage.Ver
return nil, errors.E(op, err)
}
m, err := downloadModule(g.goBinaryName, g.envVars, g.fs, goPathRoot, modPath, mod, ver)
m, err := g.downloadModule(ctx, goPathRoot, modPath, mod, ver)
if err != nil {
clearFiles(g.fs, goPathRoot)
return nil, errors.E(op, err)
@@ -103,19 +106,34 @@ func (g *goGetFetcher) Fetch(ctx context.Context, mod, ver string) (*storage.Ver
// given a filesystem, gopath, repository root, module and version, runs 'go mod download -json'
// on module@version from the repoRoot with GOPATH=gopath, and returns a non-nil error if anything went wrong.
func downloadModule(goBinaryName string, envVars []string, fs afero.Fs, gopath, repoRoot, module, version string) (goModule, error) {
func (g *goGetFetcher) downloadModule(ctx context.Context, gopath, repoRoot, module, version string) (goModule, error) {
const op errors.Op = "module.downloadModule"
var (
netrcDir string
err error
)
creds, ok := auth.FromContext(ctx)
if ok && g.shouldPropAuth() {
if ok {
netrcDir, err = auth.WriteTemporaryNETRC(g.propagateAuthHost, creds.User, creds.Password)
if err != nil {
return goModule{}, errors.E(op, err)
}
defer os.RemoveAll(netrcDir)
}
}
uri := strings.TrimSuffix(module, "/")
fullURI := fmt.Sprintf("%s@%s", uri, version)
cmd := exec.Command(goBinaryName, "mod", "download", "-json", fullURI)
cmd.Env = prepareEnv(gopath, envVars)
fullURI := fmt.Sprintf("%s@%s", uri, version)
cmd := exec.CommandContext(ctx, g.goBinaryName, "mod", "download", "-json", fullURI)
cmd.Env = prepareEnv(gopath, netrcDir, g.envVars)
cmd.Dir = repoRoot
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd.Stdout = stdout
cmd.Stderr = stderr
err := cmd.Run()
err = cmd.Run()
if err != nil {
err = fmt.Errorf("%v: %s", err, stderr)
var m goModule
@@ -140,6 +158,10 @@ func downloadModule(goBinaryName string, envVars []string, fs afero.Fs, gopath,
return m, nil
}
func (g *goGetFetcher) shouldPropAuth() bool {
return len(g.propagateAuthHost) > 0
}
func isLimitHit(o string) bool {
return strings.Contains(o, "403 response from api.github.com")
}