diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 769dc48dcb..40db1defc0 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -32,6 +32,10 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v6 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: "1.25.0" # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 @@ -40,8 +44,19 @@ jobs: build-mode: manual - name: Install Taskfile support uses: arduino/setup-task@v2 - - shell: bash - run: task build + - name: Install libmongocrypt + run: task install-libmongocrypt + - name: Build (CodeQL-instrumented) + shell: bash + env: + GOTOOLCHAIN: local + run: | + # TODO(GODRIVER-3723): Run using taskfile targets. + go build ./... + go build ${BUILD_TAGS} ./... + go test -short ${BUILD_TAGS} -run ^$$ ./... + + go test -v ./internal/test/compilecheck -run '^TestCompileCheck/golang:1\.19$' - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 with: diff --git a/.gitignore b/.gitignore index c4a9fcbfad..7c96c9c291 100644 --- a/.gitignore +++ b/.gitignore @@ -31,10 +31,6 @@ bin internal/cmd/faas/awslambda/.aws-sam internal/cmd/faas/awslambda/events/event.json -# Ignore compiled binaries from the compilecheck -internal/cmd/compilecheck/compilecheck -internal/cmd/compilecheck/compilecheck.so - # Ignore api report files api-report.md api-report.txt diff --git a/Taskfile.yml b/Taskfile.yml index 73842ab9c9..f094604cd5 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -17,19 +17,15 @@ tasks: - go build ./... - go build ${BUILD_TAGS} ./... - task: build-tests - - task: build-compile-check - - task: cross-compile + - task: compilecheck-119 build-tests: go test -short ${BUILD_TAGS} -run ^$$ ./... - build-compile-check: bash etc/compile_check.sh + compilecheck-119: + dir: internal/test/compilecheck + cmds: + - go mod download + - GOTOOLCHAIN=auto go test -v -run '^TestCompileCheck/golang:1\.19$' build-compile-check-all: bash etc/run-compile-check-test.sh build-aws-ecs-test: go test -c ./internal/test/aws -o aws.testbin - cross-compile: - - GOOS=linux GOARCH=386 go build ./... - - GOOS=linux GOARCH=arm go build ./... - - GOOS=linux GOARCH=arm64 go build ./... - - GOOS=linux GOARCH=amd64 go build ./... - - GOOS=linux GOARCH=ppc64le go build ./... - - GOOS=linux GOARCH=s390x go build ./... check-fmt: deps: [install-lll] cmds: diff --git a/etc/compile_check.sh b/etc/compile_check.sh deleted file mode 100755 index 457b8e9e92..0000000000 --- a/etc/compile_check.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -set -e # exit when any command fails -set -x # show all commands being run - -: ${GC:=go${GO_VERSION="1.19"}} - -COMPILE_CHECK_DIR="internal/cmd/compilecheck" -ARCHITECTURES=("386" "arm" "arm64" "ppc64le" "s390x") -BUILD_CMD="${GC} build -buildvcs=false" - -# compile_check will attempt to build the internal/test/compilecheck project -# using the provided Go version. This is to simulate an end-to-end use case. -function compile_check { - # Change the directory to the compilecheck test directory. - pushd "${COMPILE_CHECK_DIR}" >/dev/null - - # If a custom Go version is set using the GO_VERSION env var (e.g. "1.18"), - # add the GOPATH bin directory to PATH and then install that Go version. - if [ ! -z "$GO_VERSION" ]; then - PATH=$(go env GOPATH)/bin:$PATH - export PATH - - go install golang.org/dl/go$GO_VERSION@latest - ${GC} download - fi - - ${GC} version - ${GC} mod tidy - - # Standard build - $BUILD_CMD ./... - - # Dynamic linking - $BUILD_CMD -buildmode=plugin - - # Check build with tags. - [[ -n "$BUILD_TAGS" ]] && $BUILD_CMD $BUILD_TAGS ./... - - # Check build with various architectures. - for ARCH in "${ARCHITECTURES[@]}"; do - GOOS=linux GOARCH=$ARCH $BUILD_CMD ./... - done - - # Change the directory back to the working directory. - popd >/dev/null -} - -compile_check diff --git a/etc/run-compile-check-test.sh b/etc/run-compile-check-test.sh index abd8b73bc6..4aa808c3ea 100755 --- a/etc/run-compile-check-test.sh +++ b/etc/run-compile-check-test.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash # run-compile-check-test -# Run compile check tests. +# Run compile check tests for all supported Go versions. set -eu set +x echo "Running internal/test/compilecheck" pushd internal/test/compilecheck -GOWORK=off go test -timeout 30m -v ./... >>../../../test.suite +go test -timeout 30m -v ./... >>../../../test.suite popd diff --git a/go.work b/go.work index 43568f4aa7..5f684346ec 100644 --- a/go.work +++ b/go.work @@ -6,7 +6,6 @@ use ( ./examples/_logger/zap ./examples/_logger/zerolog ./internal/cmd/benchmark - ./internal/cmd/compilecheck ./internal/cmd/faas/awslambda/mongodb ./internal/test/compilecheck ./internal/test/goleak diff --git a/internal/cmd/compilecheck/go.mod b/internal/cmd/compilecheck/go.mod deleted file mode 100644 index 7328f4c1a6..0000000000 --- a/internal/cmd/compilecheck/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module go.mongodb.go/mongo-driver/v2/internal/cmd/compilecheck - -go 1.19 - -replace go.mongodb.org/mongo-driver/v2 => ../../../ - -// Note that the Go driver version is replaced with the local Go driver code by -// the replace directive above. -require go.mongodb.org/mongo-driver/v2 v2.0.0-alpha2 - -require ( - github.com/klauspost/compress v1.17.6 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.2.0 // indirect - github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect - golang.org/x/crypto v0.33.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/text v0.22.0 // indirect -) diff --git a/internal/cmd/compilecheck/go.sum b/internal/cmd/compilecheck/go.sum deleted file mode 100644 index b71abc26e7..0000000000 --- a/internal/cmd/compilecheck/go.sum +++ /dev/null @@ -1,42 +0,0 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI= -github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs= -github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= -github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/cmd/compilecheck/go.work b/internal/cmd/compilecheck/go.work deleted file mode 100644 index 6da44691e9..0000000000 --- a/internal/cmd/compilecheck/go.work +++ /dev/null @@ -1,5 +0,0 @@ -go 1.19 - -use ( - . -) diff --git a/internal/cmd/compilecheck/main.go b/internal/cmd/compilecheck/main.go deleted file mode 100644 index 1661c6e097..0000000000 --- a/internal/cmd/compilecheck/main.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) MongoDB, Inc. 2023-present. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -package main - -import ( - "fmt" - - "go.mongodb.org/mongo-driver/v2/bson" - "go.mongodb.org/mongo-driver/v2/mongo" - "go.mongodb.org/mongo-driver/v2/mongo/options" - "go.mongodb.org/mongo-driver/v2/x/mongo/driver/xoptions" -) - -func main() { - opts := options.Client() - xoptions.SetInternalClientOptions(opts, "foo", "bar") - - _, _ = mongo.Connect(options.Client()) - fmt.Println(bson.D{{Key: "key", Value: "value"}}) -} diff --git a/internal/test/compilecheck/compile_check_test.go b/internal/test/compilecheck/compile_check_test.go index 2eef836190..ca8d804396 100644 --- a/internal/test/compilecheck/compile_check_test.go +++ b/internal/test/compilecheck/compile_check_test.go @@ -7,6 +7,7 @@ package main import ( + "bytes" "context" "fmt" "io" @@ -14,19 +15,46 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" + "github.com/docker/docker/api/types/container" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" ) -var versions = []string{ - "1.19", - "1.20", - "1.21", - "1.22", - "1.23", - "1.24", - "1.25", +const mainGo = `package main + +import ( + "fmt" + + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" +) + +func main() { + _, _ = mongo.Connect(options.Client()) + fmt.Println(bson.D{{Key: "key", Value: "value"}}) +} +` + +// goVersions is the list of Go versions to test compilation against. +// To run tests for specific version(s), use the -run flag: +// +// go test -v -run '^TestCompileCheck/golang:1.19$' +// go test -v -run '^TestCompileCheck/golang:1\.(19|20)$' +var goVersions = []string{"1.19", "1.20", "1.21", "1.22", "1.23", "1.24", "1.25"} +var architectures = []string{ + "386", + "amd64", + "arm", + "arm64", + "mips", + "mips64", + "mips64le", + "mipsle", + "ppc64", + "ppc64le", + "riscv64", + "s390x", } func TestCompileCheck(t *testing.T) { @@ -35,7 +63,7 @@ func TestCompileCheck(t *testing.T) { rootDir := filepath.Dir(filepath.Dir(filepath.Dir(cwd))) - for _, version := range versions { + for _, version := range goVersions { version := version // Capture range variable. image := fmt.Sprintf("golang:%s", version) @@ -44,17 +72,17 @@ func TestCompileCheck(t *testing.T) { req := testcontainers.ContainerRequest{ Image: image, - Cmd: []string{"tail", "-f", "/dev/null"}, - Mounts: []testcontainers.ContainerMount{ - testcontainers.BindMount(rootDir, "/workspace"), + // Keep container running so we can Exec commands into it. + Cmd: []string{"tail", "-f", "/dev/null"}, + WorkingDir: "/app", + HostConfigModifier: func(hostConfig *container.HostConfig) { + hostConfig.Binds = []string{fmt.Sprintf("%s:/driver", rootDir)} }, - WorkingDir: "/workspace", - Env: map[string]string{ - "GC": "go", - // Compilation modules are not part of the workspace as testcontainers requires - // a version of klauspost/compress not supported by the Go Driver / other modules - // in the workspace. - "GOWORK": "off", + Files: []testcontainers.ContainerFile{ + { + ContainerFilePath: "/app/main.go", + Reader: bytes.NewReader([]byte(mainGo)), + }, }, } @@ -71,14 +99,87 @@ func TestCompileCheck(t *testing.T) { require.NoError(t, err) }() - exitCode, outputReader, err := container.Exec(context.Background(), []string{"bash", "etc/compile_check.sh"}) + // Initialize go module and set up replace directive to use local driver. + setupCmds := [][]string{ + {"go", "mod", "init", "app"}, + {"go", "mod", "edit", "-replace", "go.mongodb.org/mongo-driver/v2=/driver"}, + {"go", "mod", "tidy"}, + } + + for _, cmd := range setupCmds { + exitCode, outputReader, err := container.Exec(context.Background(), cmd) + require.NoError(t, err) + + output, err := io.ReadAll(outputReader) + require.NoError(t, err) + + require.Equal(t, 0, exitCode, "command %v failed: %s", cmd, output) + } + + // Standard build. + exitCode, outputReader, err := container.Exec(context.Background(), []string{"go", "build", "-buildvcs=false", "./..."}) require.NoError(t, err) output, err := io.ReadAll(outputReader) require.NoError(t, err) - t.Logf("output: %s", output) - assert.Equal(t, 0, exitCode) + require.Equal(t, 0, exitCode, "standard build failed: %s", output) + + exitCode, outputReader, err = container.Exec(context.Background(), []string{"go", "build", "-buildvcs=false", "-buildmode=plugin", "./..."}) + require.NoError(t, err) + + output, err = io.ReadAll(outputReader) + require.NoError(t, err) + + require.Equal(t, 0, exitCode, "dynamic linking build failed: %s", output) + + // Build with tags (install libmongocrypt and gssapi headers). + // Use the driver's install-libmongocrypt.sh script which is mounted at /driver. + installCmds := [][]string{ + {"apt-get", "update"}, + {"apt-get", "install", "-y", "libkrb5-dev", "cmake", "libssl-dev", "git", "pkg-config"}, + {"bash", "/driver/etc/install-libmongocrypt.sh"}, + {"sh", "-c", "test -d install || test -d /cygdrive/c/libmongocrypt/bin"}, + } + + for _, cmd := range installCmds { + exitCode, outputReader, err = container.Exec(context.Background(), cmd) + require.NoError(t, err) + + output, err = io.ReadAll(outputReader) + require.NoError(t, err) + + require.Equal(t, 0, exitCode, "install command %v failed: %s", cmd, output) + } + + // The install script creates an "install" directory in the current working directory (/app). + // libmongocrypt may install to lib or lib64 depending on the system. + exitCode, outputReader, err = container.Exec(context.Background(), []string{ + "sh", "-c", "PKG_CONFIG_PATH=/app/install/lib/pkgconfig:/app/install/lib64/pkgconfig " + + "LD_LIBRARY_PATH=/app/install/lib:/app/install/lib64 " + + "go build -buildvcs=false -tags=cse,gssapi,mongointernal ./...", + }) + require.NoError(t, err) + + output, err = io.ReadAll(outputReader) + require.NoError(t, err) + + require.Equal(t, 0, exitCode, "build with build tags failed: %s", output) + + for _, architecture := range architectures { + exitCode, outputReader, err := container.Exec( + context.Background(), + []string{"sh", "-c", fmt.Sprintf("GOOS=linux GOARCH=%s go build -buildvcs=false ./...", architecture)}, + ) + require.NoError(t, err) + + output, err := io.ReadAll(outputReader) + require.NoError(t, err) + + require.Equal(t, 0, exitCode, "build failed for architecture %s: %s", architecture, output) + } + + t.Logf("compilation checks passed for %s", image) }) } } diff --git a/internal/test/compilecheck/go.mod b/internal/test/compilecheck/go.mod index 393c44756a..7b6ab46f7d 100644 --- a/internal/test/compilecheck/go.mod +++ b/internal/test/compilecheck/go.mod @@ -5,6 +5,7 @@ go 1.25.0 toolchain go1.25.3 require ( + github.com/docker/docker v28.0.0+incompatible github.com/stretchr/testify v1.10.0 github.com/testcontainers/testcontainers-go v0.35.0 ) @@ -20,7 +21,6 @@ require ( github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v28.0.0+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect