go icon indicating copy to clipboard operation
go copied to clipboard

cmd/go: private repos on hard-coded hosting providers require special configuration

Open brunetto opened this issue 6 years ago • 31 comments

What version of Go are you using (go version)?

$ go get -u golang.org/x/vgo
$ vgo version
go version go1.10 darwin/amd64 vgo:2018-02-20.1

Does this issue reproduce with the latest release?

yes (coming from https://github.com/golang/go/issues/25590)

What operating system and processor architecture are you using (go env)?

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/brunetto.ziosi/Library/Caches/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/brunetto.ziosi/Code"
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/m3/145jfhdd5qsf66_41wt9p02mhc4hp5/T/go-build518939426=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I ran

vgo get github.com/MY_ORGANIZATION/MY_REPO

where:

  • I ran the command in a folder with a working golang app and a proper go.mod file -> vgo is working here and I can vgo build the app
  • the repo is a private repo with SSO enabled I can access (git pull/push, ...)

What did you expect to see?

The package code in MY_REPO or the go module downloaded

What did you see instead?

vgo get github.com/MY_ORGANIZATION/MY_REPO: git ls-remote -q https://github.com/MY_ORGANIZATION/MY_REPO in /Users/brunetto.ziosi/Code/src/mod/cache/vcs/2cb00fa3547080bb301974fe87cf912af55d50f7a6d8a9955e11fed7a20ac6d3: exit status 128:
	remote: Repository not found.
	fatal: repository 'https://github.com/MY_ORGANIZATION/MY_REPO/' not found

brunetto avatar Jun 29 '18 14:06 brunetto

What vgo commit did you build from?

What happens if you attempt to go get the same repository with the ordinary go tool?

Are you using the credential helper?

bcmills avatar Jun 29 '18 21:06 bcmills

What vgo commit did you build from?

I don't know, I just updated it before running it... how can I know the commit?

What happens if you attempt to go get the same repository with the ordinary go tool?

The simple go get does some stuff in the background and says nothing, if I run go get -v -u I see the repo itself downloaded and some dependencies downloaded, few others blocked by our firewall (-insecure seems to allow the download for everything).

Are you using the credential helper?

I don't think so, I exchanged the keys with github so my remote is like

$ git remote -v
origin	[email protected]:MY_ORGANIZATION/MY_REPO.git (fetch)
origin	[email protected]:MY_ORGANIZATION/MY_REPO.git (push)

brunetto avatar Jul 02 '18 14:07 brunetto

The error text shows the command being run. It is one of the few git commands that doesn't actually care about having a git repo to run, so you can just try it in any directory you want:

git ls-remote -q https://github.com/MY_ORGANIZATION/MY_REPO

Does it work?

rsc avatar Jul 06 '18 03:07 rsc

Possible duplicate of #26145 but the error message from git is different (no mention of terminal prompts disabled).

rsc avatar Jul 06 '18 03:07 rsc

Ok, so

$ git ls-remote -q https://github.com/MY_ORGANIZATION/MY_REPO
remote: Repository not found.
fatal: repository 'https://github.com/MY_ORGANIZATION/MY_REPO/' not found

but

$ git ls-remote [email protected]:MY_ORGANIZATION/MY_REPO.git
3fe3e3f8b07ff40cdf5de8685360715c4c06df9c	HEAD
1fd67741650c052e30bce6d780cd26c273ba0ab2	refs/heads/dev
1498d237221b9e19d55148dded8fafc7316a47bf	refs/heads/evo
3fe3e3f8b07ff40cdf5de8685360715c4c06df9a	refs/heads/master
3e86bf596a1f63631b91cc9cbbc0866b88cb67c3	refs/pull/1/head
14aef40c003sw32ab1402b2471d164c549624e5c	refs/pull/2/head
...

Maybe I am able to reach the repository only via ssh?

brunetto avatar Jul 06 '18 06:07 brunetto

If you can make the https form work then vgo (and old go get) will be happy. The two possible ways to do that are:

  1. Add to $HOME/.gitconfig:

    [url "ssh://[email protected]/MYORGANIZATION/"] insteadOf = https://github.com/MYORGANIZATION/

  2. Add to $HOME/.netrc:

    machine github.com login YOU password APIKEY

where APIKEY is an API key obtained from the GitHub API page with access to private repos.

rsc avatar Jul 10 '18 16:07 rsc

Retitling this to "cmd/go: github private repos require special configuration". Maybe for Go 1.12 we should think about some way to get this right by default. I'm not sure exactly how.

rsc avatar Jul 10 '18 16:07 rsc

The first option, adding

[url "ssh://[email protected]/MYORGANIZATION/"]
    insteadOf = https://github.com/MYORGANIZATION/

to $HOME/.gitconfig work like a charm!!
Thanks!

brunetto avatar Jul 10 '18 20:07 brunetto

Hi Guys,

I don't know if this is the correct issue to comment on so please forgive me if it's not correct, I ended up here because of an Issue I am having with Gitlab. We have a project structure where we use subgroups for project organisation by client/project/repo. So our package import paths are 3 levels deep rather than the standard 2 you see on Github. This is fine except for an issue with go get. Gitlab has a strict security policy where requests for the go-import meta data is incorrect for private sub groups by design for unauthenticated requests. So for example if I wanted to go get my.gitlab.com/foo/bar/fizz the meta data request would be https://my.gitlab.com/foo/bar/fizz?go-get=1 and the meta data returned would be:

<html><head><meta name="go-import" content="my.gitlab.com/foo/bar git https://my.gitlab.com/foo/bar.git" /></head></html>

Gitlab recently did implement support for a HTTP header to override this behaviour over here: https://gitlab.com/gitlab-org/gitlab-ce/issues/42817 so we can send a Private-Token header to get the correct meta. However I cannot find a way where I can get go get to send that header to resolve the source path.

We could update our import paths to include a .git suffix but that feels a little broken?

I guess what we need is a way for go get to find crednetial information for these sorts of projects, perhaps another file that lives alongside go.mod and go.sub like go.creds or something, which could contain credential information (you wouldn't want to check that into a repo tho). Or perhaps a way to override go-import meta data locally? :man_shrugging:

krak3n avatar Jul 24 '18 09:07 krak3n

To add to the list of options in this space (https://github.com/golang/go/issues/26134#issuecomment-403885803), we should also add use of a keychain/keyring as a third option (which is independent of remote VCS). Instructions vary quite widely between platforms, unsurprisingly:

  • Mac: https://help.github.com/articles/updating-credentials-from-the-osx-keychain/
  • Linux: https://wiki.archlinux.org/index.php/GNOME/Keyring (or equivalent)
  • Windows: ???

I've switched back from using the ssh solution on Linux to using Gnome keyring (even though I don't use Gnome) to great effect... not least because it can be used to unify all credentials.

@FiloSottile are there are any security implications that I'm unaware of with respect to the use of keychain/keyrings for this sort of thing?

myitcv avatar Aug 08 '18 16:08 myitcv

With Go tip (f2131f6e0c) I can use private repos without modules (with the url "ssh://git insteadOf config above), but not with modules:

dev:barlogaamp $ GO111MODULE=on go install -x -v .
# /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456 for git2 https://github.com/bradfitz/private
go: finding github.com/bradfitz/private v0.0.0-20180808000000-9069f54cff2af5e9fc291df126155504d71d1fd9
cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git -c log.showsignature=false log -n1 '--format=format:%H %ct %D' 9069f54cff2af5e9fc291df126155504d71d1fd9
0.002s # cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git -c log.showsignature=false log -n1 '--format=format:%H %ct %D' 9069f54cff2af5e9fc291df126155504d71d1fd9
cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git tag -l
0.002s # cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git tag -l
cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git ls-remote -q https://github.com/bradfitz/private
0.177s # cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git ls-remote -q https://github.com/bradfitz/private
cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git fetch -f --depth=1 https://github.com/bradfitz/private 9069f54cff2af5e9fc291df126155504d71d1fd9:refs/dummy
0.165s # cd /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456; git fetch -f --depth=1 https://github.com/bradfitz/private 9069f54cff2af5e9fc291df126155504d71d1fd9:refs/dummy
go: github.com/bradfitz/private@v0.0.0-20180808000000-9069f54cff2af5e9fc291df126155504d71d1fd9: git fetch -f --depth=1 https://github.com/bradfitz/private 9069f54cff2af5e9fc291df126155504d71d1fd9:refs/dummy in /home/bradfitz/pkg/mod/cache/vcs/61e3c76780847e514802ec6af8f940f641c6017f711444f05c59cb17ac46d456: exit status 1
go: error loading module requirements

That final git fetch fails, but that hash exists in the private repo:

$ git cat-file -t 9069f54cff2af5e9fc291df126155504d71d1fd9
commit

And it's on the remote (it's remote/origin/master^), but it doesn't have a remote tag or other ref, if that's the problem.

dev:src $ git --version
git version 2.11.0

bradfitz avatar Aug 09 '18 14:08 bradfitz

@bradfitz I think you're running up against https://github.com/golang/go/issues/26894

myitcv avatar Aug 09 '18 14:08 myitcv

Is it possible to add a flag that causes go to clone over ssh (or any other potential future protocol)?

A flag would be easy to use in CI where necessary and is more easily explained than editing a .gitconfig or .netrc.

twmb avatar Oct 30 '18 21:10 twmb

Wrote a script if any of you guys need to containerize a similar app using private github repo imports: https://github.com/anuragdhingra/pdocker-go

anuragdhingra avatar Jan 29 '19 08:01 anuragdhingra

Note that this issue only applies to the hard-coded hosting sites.

If we have some sort of general HTTPS auth mechanism (#26232), HTTPS servers that use <meta> tags should provide ssh URLs as appropriate to begin with.

bcmills avatar Feb 06 '19 14:02 bcmills

Issue #31376 was duplicated here, but is not using one of the hard-coded hosting sites. The matching HTTPS server provides no tags, and documented methods to make 'go get' skip VCS detection step do not seem to be working.

stub42 avatar Apr 11 '19 01:04 stub42

@stub42, my apologies. We do have a special case for launchpad.net; I had missed the fact that git.launchpad.net should not match that special case.

bcmills avatar Apr 11 '19 14:04 bcmills

Thank you for this issue, I was debugging the access to my private github repos for a week..

$HOME/.gitconfig:

[url "ssh://[email protected]/MYORGANIZATION/"]
insteadOf = https://github.com/MYORGANIZATION/

hazcod avatar Jun 05 '19 11:06 hazcod

@rsc I have a huntch that capturing private repo information in the go.mod file might help. This information and auth details can get used directly or passed to Athens.

Maybe instead of insteadOf

Add to $HOME/.gitconfig:

[url "ssh://[email protected]/MYORGANIZATION/"] insteadOf = https://github.com/MYORGANIZATION/

we could write something like

module my/package

replace github.com/MYORGANIZATION => ssh://[email protected]/MYORGANIZATION/someprivatepackage v1.1.1 

require github.com/MYORGANIZATION/someprivatepackage v1.1.1

or

module my/package

require github.com/MYORGANIZATION/someprivatepackage v1.1.1 at [email protected]:MYORGANIZATION/someprivatepackage

millergarym avatar Jul 28 '19 23:07 millergarym

I'd also like to see a solution to this where the private repo information can be stored in the repository. This is currently holding me back from using Go modules for projects that depend on private repositories because it's not seamless enough (requires modifying $HOME/.gitconfig locally).

marksamman avatar Jul 29 '19 09:07 marksamman

@marksamman any ideas on how authentication should be done?

Is putting a public key in the go.mod file a security issue?

eg

module my/package

require github.com/MYORGANIZATION/someprivatepackage v1.1.1 at [email protected]:MYORGANIZATION/someprivatepackage using ssh-rsa AAAAB3NzaC1yc2EAAAADAQA...2JN millergarym@development_machine_and_ci

millergarym avatar Jul 29 '19 13:07 millergarym

@marksamman any ideas on how authentication should be done? ...

@millergarym if you mean a private key, yes.

hazcod avatar Jul 29 '19 15:07 hazcod

I am not suggesting including authentication credentials in the repository, just a way of pulling over SSH instead of HTTPS and leaving the rest for Git to handle.

EDIT: I've learned that my problem can be solved with the go-import meta tag, so this is no longer a blocker for me to use Go modules with private repositories.

marksamman avatar Jul 29 '19 16:07 marksamman

@marksamman any ideas on how authentication should be done? ...

@millergarym if you mean a private key, yes.

No, only public keys

millergarym avatar Jul 30 '19 00:07 millergarym

EDIT: I've learned that my problem can be solved with the go-import meta tag, so this is no longer a blocker for me to use Go modules with private repositories.

Can meta tags point to private repos? If so please provide an example.

millergarym avatar Jul 30 '19 00:07 millergarym

Meta tags require serving public document referencing the private branch or repo, which is data leakage and not acceptable at some sites. The Launchpad web site returns a 404 for private branches, unless you are both logged in and have been granted read access. A tool can't tell if the repo exists unless it has a valid oauth token or speaks SSH.

My current workaround is to embed my private branches as git subtrees, as 'replace' in go.mod already allows me to reference a relative local path:

replace api/fooclient v0.0.0 => ../api/fooclient
require api/fooclient v0.0.0

I think allowing 'replace' to specify full URLs would be a workable solution, or a new command, ideally without the v0.0.0 version pin. Say, theoretically:

rewrite api/fooclient => git+ssh://git.launchpad.net/~stub/foo/+git/foo-client
require api/fooclient

(Interestingly, you should be able to use the existing replace to force use of a fork without changing imports, perhaps even a fork of parts of the standard library)

stub42 avatar Jul 30 '19 05:07 stub42

The first option, adding

[url "ssh://[email protected]/MYORGANIZATION/"]
    insteadOf = https://github.com/MYORGANIZATION/

to $HOME/.gitconfig work like a charm!! Thanks!

DO NOT MISSING THE LAST '/' CHAR!

DeaglePC avatar Jul 07 '20 07:07 DeaglePC

Note that this issue only applies to the hard-coded hosting sites.

I have reason to believe that this statement may have been mistaken. I plan to investigate further.

This issue somehow ended up in the Proposals queue in Feb. 2021, but I'm not sure why — I think it may be just a bug.

bcmills avatar Jan 19 '23 21:01 bcmills

I've started to suspect that this may just be a problem in the way that we probe for which protocol to use.

It appears that both GitHub and GitLab support SSH by having everyone use the username git, and then treating the public key presented by the user as the “effective user ID”. So probably when we probe for SSH support, in addition to trying ssh with the user's actual username, we should also try ssh with the hard-coded username git.

bcmills avatar Mar 07 '24 19:03 bcmills

I'm a little surprised this is still an issue, I've encountered this at 3 different companies over the last 6 years, and we're always doing the .gitconfig InsteadOf dance.

I got here because if you have the following setup this does NOT work:

~/.gitconfig

[includeIf "gitdir:/company/"]
        path = /company/.gitconfig-company

/company/.gitconfig-company

[url "[email protected]:"]
        insteadOf = https://github.com

[url "[email protected]:company"]
        insteadOf = https://github.com:company

I guess because the git commands are being run with the gitdir being inside the GOENV rather than in the project's repo under /company/... ?

rlabrecquefsg avatar Mar 28 '24 16:03 rlabrecquefsg