Skip to content

Commit 2c4818f

Browse files
authored
Merge pull request #573 from pjbgf/bump-libgit2
2 parents 1dae5e7 + 8429708 commit 2c4818f

File tree

14 files changed

+205
-76
lines changed

14 files changed

+205
-76
lines changed

.github/workflows/e2e.yaml

+1-5
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,7 @@ jobs:
5757
with:
5858
go-version: 1.17.x
5959
- name: Run tests
60-
run: |
61-
mkdir tmp-download; cd tmp-download; go mod init go-download;
62-
GOBIN="${GITHUB_WORKSPACE}/build/gobin" go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest
63-
cd ..; rm -rf tmp-download
64-
make test
60+
run: make test
6561
- name: Prepare
6662
id: prep
6763
run: |

ATTRIBUTIONS.md

+12
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,18 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
12031203
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
12041204
OF THE POSSIBILITY OF SUCH DAMAGE.
12051205

1206+
----------------------------------------------------------------------
1207+
1208+
The xoroshiro256** implementation is licensed in the public domain:
1209+
1210+
Written in 2018 by David Blackman and Sebastiano Vigna ([email protected])
1211+
1212+
To the extent possible under law, the author has dedicated all copyright
1213+
and related and neighboring rights to this software to the public domain
1214+
worldwide. This software is distributed without any warranty.
1215+
1216+
See <http://creativecommons.org/publicdomain/zero/1.0/>.
1217+
12061218
***
12071219

12081220
## zlib

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ ARG GO_VERSION=1.17
33
ARG XX_VERSION=1.1.0
44

55
ARG LIBGIT2_IMG=ghcr.io/fluxcd/golang-with-libgit2
6-
ARG LIBGIT2_TAG=libgit2-1.1.1-7
6+
ARG LIBGIT2_TAG=libgit2-1.3.0-2
77

88
FROM ${LIBGIT2_IMG}:${LIBGIT2_TAG} AS libgit2-libs
99

Makefile

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ TAG ?= latest
44

55
# Base image used to build the Go binary
66
LIBGIT2_IMG ?= ghcr.io/fluxcd/golang-with-libgit2
7-
LIBGIT2_TAG ?= libgit2-1.1.1-7
7+
LIBGIT2_TAG ?= libgit2-1.3.0-2
88

99
# Allows for defining additional Docker buildx arguments,
1010
# e.g. '--push'.
@@ -136,6 +136,7 @@ tidy: ## Run go mod tidy
136136
fmt: ## Run go fmt against code
137137
go fmt ./...
138138
cd api; go fmt ./...
139+
cd tests/fuzz; go fmt .
139140

140141
vet: $(LIBGIT2) ## Run go vet against code
141142
go vet ./...
@@ -208,6 +209,12 @@ ifneq ($(shell grep -o 'LIBGIT2_IMG ?= \w.*' Makefile | cut -d ' ' -f 3):$(shell
208209
exit 1; \
209210
}
210211
endif
212+
ifneq ($(shell grep -o 'LIBGIT2_TAG ?= \w.*' Makefile | cut -d ' ' -f 3), $(shell grep -o "LIBGIT2_TAG=.*" tests/fuzz/oss_fuzz_build.sh | sed 's;LIBGIT2_TAG="$${LIBGIT2_TAG:-;;g' | sed 's;}";;g'))
213+
@{ \
214+
echo "LIBGIT2_TAG must match in both Makefile and tests/fuzz/oss_fuzz_build.sh"; \
215+
exit 1; \
216+
}
217+
endif
211218
ifneq (, $(shell git status --porcelain --untracked-files=no))
212219
@{ \
213220
echo "working directory is dirty:"; \
@@ -224,7 +231,7 @@ TMP_DIR=$$(mktemp -d) ;\
224231
cd $$TMP_DIR ;\
225232
go mod init tmp ;\
226233
echo "Downloading $(2)" ;\
227-
go install $(2) ;\
234+
env -i bash -c "GOBIN=$(GOBIN) PATH=$(PATH) GOPATH=$(shell go env GOPATH) GOCACHE=$(shell go env GOCACHE) go install $(2)" ;\
228235
rm -rf $$TMP_DIR ;\
229236
}
230237
endef

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ require (
2323
github.com/go-git/go-billy/v5 v5.3.1
2424
github.com/go-git/go-git/v5 v5.4.2
2525
github.com/go-logr/logr v1.2.2
26-
github.com/libgit2/git2go/v31 v31.7.6
26+
github.com/libgit2/git2go/v33 v33.0.6
2727
github.com/minio/minio-go/v7 v7.0.15
2828
github.com/onsi/ginkgo v1.16.5
2929
github.com/onsi/gomega v1.17.0

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,8 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm
622622
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
623623
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
624624
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
625-
github.com/libgit2/git2go/v31 v31.7.6 h1:jg/pNomrQULnafmfF6XTkozPX5ypyELoWErWkJuYPcI=
626-
github.com/libgit2/git2go/v31 v31.7.6/go.mod h1:c/rkJcBcUFx6wHaT++UwNpKvIsmPNqCeQ/vzO4DrEec=
625+
github.com/libgit2/git2go/v33 v33.0.6 h1:F//bA3/pgSTVq2hLNahhnof9NxyCzFF/c3MB6lb93Qo=
626+
github.com/libgit2/git2go/v33 v33.0.6/go.mod h1:KdpqkU+6+++4oHna/MIOgx4GCQ92IPCdpVRMRI80J+4=
627627
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
628628
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
629629
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=

hack/install-libraries.sh

-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,6 @@ function setup_current() {
4545
mkdir -p "./build/libgit2"
4646
if [[ $OSTYPE == 'darwin'* ]]; then
4747
# For MacOS development environments, download the amd64 static libraries released from from golang-with-libgit2.
48-
49-
#TODO: update URL with official URL + TAG:
5048
curl -o output.tar.gz -LO "https://github.com/fluxcd/golang-with-libgit2/releases/download/${TAG}/darwin-libs.tar.gz"
5149

5250
DIR=libgit2-darwin

pkg/git/libgit2/checkout.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import (
2525

2626
"github.com/Masterminds/semver/v3"
2727
"github.com/go-logr/logr"
28-
git2go "github.com/libgit2/git2go/v31"
28+
git2go "github.com/libgit2/git2go/v33"
2929

3030
"github.com/fluxcd/pkg/gitutil"
3131
"github.com/fluxcd/pkg/version"
@@ -61,7 +61,7 @@ type CheckoutBranch struct {
6161

6262
func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
6363
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
64-
FetchOptions: &git2go.FetchOptions{
64+
FetchOptions: git2go.FetchOptions{
6565
DownloadTags: git2go.DownloadTagsNone,
6666
RemoteCallbacks: RemoteCallbacks(ctx, opts),
6767
ProxyOptions: git2go.ProxyOptions{Type: git2go.ProxyTypeAuto},
@@ -91,7 +91,7 @@ type CheckoutTag struct {
9191

9292
func (c *CheckoutTag) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
9393
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
94-
FetchOptions: &git2go.FetchOptions{
94+
FetchOptions: git2go.FetchOptions{
9595
DownloadTags: git2go.DownloadTagsAll,
9696
RemoteCallbacks: RemoteCallbacks(ctx, opts),
9797
ProxyOptions: git2go.ProxyOptions{Type: git2go.ProxyTypeAuto},
@@ -115,7 +115,7 @@ type CheckoutCommit struct {
115115

116116
func (c *CheckoutCommit) Checkout(ctx context.Context, path, url string, opts *git.AuthOptions) (*git.Commit, error) {
117117
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
118-
FetchOptions: &git2go.FetchOptions{
118+
FetchOptions: git2go.FetchOptions{
119119
DownloadTags: git2go.DownloadTagsNone,
120120
RemoteCallbacks: RemoteCallbacks(ctx, opts),
121121
ProxyOptions: git2go.ProxyOptions{Type: git2go.ProxyTypeAuto},
@@ -147,7 +147,7 @@ func (c *CheckoutSemVer) Checkout(ctx context.Context, path, url string, opts *g
147147
}
148148

149149
repo, err := git2go.Clone(url, path, &git2go.CloneOptions{
150-
FetchOptions: &git2go.FetchOptions{
150+
FetchOptions: git2go.FetchOptions{
151151
DownloadTags: git2go.DownloadTagsAll,
152152
RemoteCallbacks: RemoteCallbacks(ctx, opts),
153153
ProxyOptions: git2go.ProxyOptions{Type: git2go.ProxyTypeAuto},

pkg/git/libgit2/checkout_test.go

+73-1
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,20 @@ import (
2020
"context"
2121
"errors"
2222
"fmt"
23+
"net/url"
2324
"os"
2425
"path/filepath"
2526
"testing"
2627
"time"
2728

28-
git2go "github.com/libgit2/git2go/v31"
29+
git2go "github.com/libgit2/git2go/v33"
2930
. "github.com/onsi/gomega"
31+
corev1 "k8s.io/api/core/v1"
32+
33+
"github.com/fluxcd/pkg/gittestserver"
34+
"github.com/fluxcd/pkg/ssh"
35+
36+
"github.com/fluxcd/source-controller/pkg/git"
3037
)
3138

3239
func TestCheckoutBranch_Checkout(t *testing.T) {
@@ -444,3 +451,68 @@ func mockSignature(time time.Time) *git2go.Signature {
444451
When: time,
445452
}
446453
}
454+
455+
// This test is specifically to detect regression in libgit2's ED25519 key
456+
// support for client authentication.
457+
// Refer: https://github.com/fluxcd/source-controller/issues/399
458+
func TestCheckout_ED25519(t *testing.T) {
459+
g := NewWithT(t)
460+
timeout := 5 * time.Second
461+
462+
// Create a git test server.
463+
server, err := gittestserver.NewTempGitServer()
464+
g.Expect(err).ToNot(HaveOccurred())
465+
defer os.RemoveAll(server.Root())
466+
server.Auth("test-user", "test-pswd")
467+
server.AutoCreate()
468+
469+
server.KeyDir(filepath.Join(server.Root(), "keys"))
470+
g.Expect(server.ListenSSH()).To(Succeed())
471+
472+
go func() {
473+
server.StartSSH()
474+
}()
475+
defer server.StopSSH()
476+
477+
repoPath := "test.git"
478+
479+
err = server.InitRepo("testdata/git/repo", git.DefaultBranch, repoPath)
480+
g.Expect(err).NotTo(HaveOccurred())
481+
482+
sshURL := server.SSHAddress()
483+
repoURL := sshURL + "/" + repoPath
484+
485+
// Fetch host key.
486+
u, err := url.Parse(sshURL)
487+
g.Expect(err).NotTo(HaveOccurred())
488+
g.Expect(u.Host).ToNot(BeEmpty())
489+
knownHosts, err := ssh.ScanHostKey(u.Host, timeout)
490+
g.Expect(err).ToNot(HaveOccurred())
491+
492+
kp, err := ssh.NewEd25519Generator().Generate()
493+
g.Expect(err).ToNot(HaveOccurred())
494+
495+
secret := corev1.Secret{
496+
Data: map[string][]byte{
497+
"identity": kp.PrivateKey,
498+
"known_hosts": knownHosts,
499+
},
500+
}
501+
502+
authOpts, err := git.AuthOptionsFromSecret(repoURL, &secret)
503+
g.Expect(err).ToNot(HaveOccurred())
504+
505+
// Prepare for checkout.
506+
branchCheckoutStrat := &CheckoutBranch{Branch: git.DefaultBranch}
507+
tmpDir, _ := os.MkdirTemp("", "test")
508+
defer os.RemoveAll(tmpDir)
509+
510+
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
511+
defer cancel()
512+
513+
// Checkout the repo.
514+
// This should always fail because the generated key above isn't present in
515+
// the git server.
516+
_, err = branchCheckoutStrat.Checkout(ctx, tmpDir, repoURL, authOpts)
517+
g.Expect(err).To(BeNil())
518+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test file

pkg/git/libgit2/transport.go

+21-21
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import (
3131
"strings"
3232
"time"
3333

34-
git2go "github.com/libgit2/git2go/v31"
34+
git2go "github.com/libgit2/git2go/v33"
3535
"golang.org/x/crypto/ssh"
3636
"golang.org/x/crypto/ssh/knownhosts"
3737

@@ -61,16 +61,16 @@ func RemoteCallbacks(ctx context.Context, opts *git.AuthOptions) git2go.RemoteCa
6161
// libgit2 it should stop the transfer when the given context is closed (due to
6262
// e.g. a timeout).
6363
func transferProgressCallback(ctx context.Context) git2go.TransferProgressCallback {
64-
return func(p git2go.TransferProgress) git2go.ErrorCode {
64+
return func(p git2go.TransferProgress) error {
6565
// Early return if all the objects have been received.
6666
if p.ReceivedObjects == p.TotalObjects {
67-
return git2go.ErrorCodeOK
67+
return nil
6868
}
6969
select {
7070
case <-ctx.Done():
71-
return git2go.ErrorCodeUser
71+
return fmt.Errorf("transport close (potentially due to a timeout)")
7272
default:
73-
return git2go.ErrorCodeOK
73+
return nil
7474
}
7575
}
7676
}
@@ -79,12 +79,12 @@ func transferProgressCallback(ctx context.Context) git2go.TransferProgressCallba
7979
// libgit2 it should cancel the network operation when the given context is
8080
// closed.
8181
func transportMessageCallback(ctx context.Context) git2go.TransportMessageCallback {
82-
return func(_ string) git2go.ErrorCode {
82+
return func(_ string) error {
8383
select {
8484
case <-ctx.Done():
85-
return git2go.ErrorCodeUser
85+
return fmt.Errorf("transport closed")
8686
default:
87-
return git2go.ErrorCodeOK
87+
return nil
8888
}
8989
}
9090
}
@@ -93,16 +93,16 @@ func transportMessageCallback(ctx context.Context) git2go.TransportMessageCallba
9393
// signals libgit2 it should stop the push transfer when the given context is
9494
// closed (due to e.g. a timeout).
9595
func pushTransferProgressCallback(ctx context.Context) git2go.PushTransferProgressCallback {
96-
return func(current, total uint32, _ uint) git2go.ErrorCode {
96+
return func(current, total uint32, _ uint) error {
9797
// Early return if current equals total.
9898
if current == total {
99-
return git2go.ErrorCodeOK
99+
return nil
100100
}
101101
select {
102102
case <-ctx.Done():
103-
return git2go.ErrorCodeUser
103+
return fmt.Errorf("transport close (potentially due to a timeout)")
104104
default:
105-
return git2go.ErrorCodeOK
105+
return nil
106106
}
107107
}
108108
}
@@ -155,10 +155,10 @@ func certificateCallback(opts *git.AuthOptions) git2go.CertificateCheckCallback
155155
// x509Callback returns a CertificateCheckCallback that verifies the
156156
// certificate against the given caBundle for git.HTTPS Transports.
157157
func x509Callback(caBundle []byte) git2go.CertificateCheckCallback {
158-
return func(cert *git2go.Certificate, valid bool, hostname string) git2go.ErrorCode {
158+
return func(cert *git2go.Certificate, valid bool, hostname string) error {
159159
roots := x509.NewCertPool()
160160
if ok := roots.AppendCertsFromPEM(caBundle); !ok {
161-
return git2go.ErrorCodeCertificate
161+
return fmt.Errorf("PEM CA bundle could not be appended to x509 certificate pool")
162162
}
163163

164164
opts := x509.VerifyOptions{
@@ -167,20 +167,20 @@ func x509Callback(caBundle []byte) git2go.CertificateCheckCallback {
167167
CurrentTime: now(),
168168
}
169169
if _, err := cert.X509.Verify(opts); err != nil {
170-
return git2go.ErrorCodeCertificate
170+
return fmt.Errorf("verification failed: %w", err)
171171
}
172-
return git2go.ErrorCodeOK
172+
return nil
173173
}
174174
}
175175

176176
// knownHostCallback returns a CertificateCheckCallback that verifies
177177
// the key of Git server against the given host and known_hosts for
178178
// git.SSH Transports.
179179
func knownHostsCallback(host string, knownHosts []byte) git2go.CertificateCheckCallback {
180-
return func(cert *git2go.Certificate, valid bool, hostname string) git2go.ErrorCode {
180+
return func(cert *git2go.Certificate, valid bool, hostname string) error {
181181
kh, err := parseKnownHosts(string(knownHosts))
182182
if err != nil {
183-
return git2go.ErrorCodeCertificate
183+
return fmt.Errorf("failed to parse known_hosts: %w", err)
184184
}
185185

186186
// First, attempt to split the configured host and port to validate
@@ -200,7 +200,7 @@ func knownHostsCallback(host string, knownHosts []byte) git2go.CertificateCheckC
200200
}
201201

202202
if hostnameWithoutPort != hostWithoutPort {
203-
return git2go.ErrorCodeUser
203+
return fmt.Errorf("host mismatch: %q %q", hostWithoutPort, hostnameWithoutPort)
204204
}
205205

206206
// We are now certain that the configured host and the hostname
@@ -210,10 +210,10 @@ func knownHostsCallback(host string, knownHosts []byte) git2go.CertificateCheckC
210210
h := knownhosts.Normalize(host)
211211
for _, k := range kh {
212212
if k.matches(h, cert.Hostkey) {
213-
return git2go.ErrorCodeOK
213+
return nil
214214
}
215215
}
216-
return git2go.ErrorCodeCertificate
216+
return fmt.Errorf("hostkey could not be verified")
217217
}
218218
}
219219

0 commit comments

Comments
 (0)