From 14ea4951b4341e6896f34df2e691152af4aada8f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Apr 2024 08:22:56 +0200 Subject: [PATCH 1/4] chore(deps): bump github/codeql-action from 2.22.12 to 3.24.9 (#2459) Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.12 to 3.24.9. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/v2.22.12...1b1aada464948af03b950897e5eb522f92603cc2) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +++--- .github/workflows/scorecards.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0d75b54976..8919663257 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 + uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -67,7 +67,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 + uses: github/codeql-action/autobuild@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -80,6 +80,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # v3.23.0 + uses: github/codeql-action/analyze@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 67f61c28e3..73c657d3c4 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -51,6 +51,6 @@ jobs: # required for Code scanning alerts - name: "Upload SARIF results to code scanning" - uses: github/codeql-action/upload-sarif@1500a131381b66de0c52ac28abb13cd79f4b7ecc # v2.22.12 + uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 with: sarif_file: results.sarif From f599979daaf1dc51b214600be76bb4e8bb366bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 3 Apr 2024 10:21:07 +0200 Subject: [PATCH 2/4] chore: use "docker compose" (v2) instead of "docker-compose" (v1) (#2464) * chore: migrate from docker-compose (v1) to compose (v2) * chore: lowercase error message * chore: lint --- docs/features/docker_compose.md | 20 +++++++++---------- modules/compose/compose.go | 5 +++-- modules/compose/compose_api.go | 3 +-- modules/compose/compose_local.go | 34 +++++++++++++++++++++++++------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/docs/features/docker_compose.md b/docs/features/docker_compose.md index ea2a56bc19..352f2c84eb 100644 --- a/docs/features/docker_compose.md +++ b/docs/features/docker_compose.md @@ -7,7 +7,7 @@ This is intended to be useful on projects where Docker Compose is already used in dev or other environments to define services that an application may be dependent upon. -## Using `docker-compose` directly +## Using `docker compose` directly !!!warning The minimal version of Go required to use this module is **1.21**. @@ -16,9 +16,9 @@ dependent upon. go get github.com/testcontainers/testcontainers-go/modules/compose ``` -Because `docker-compose` v2 is implemented in Go it's possible for _Testcontainers for Go_ to +Because `compose` v2 is implemented in Go it's possible for _Testcontainers for Go_ to use [`github.com/docker/compose`](https://github.com/docker/compose) directly and skip any process execution/_docker-compose-in-a-container_ scenario. -The `ComposeStack` API exposes this variant of using `docker-compose` in an easy way. +The `ComposeStack` API exposes this variant of using `docker compose` in an easy way. ### Basic examples @@ -88,14 +88,14 @@ func TestSomethingElse(t *testing.T) { To interact with service containers after a stack was started it is possible to get an `*tc.DockerContainer` instance via the `ServiceContainer(...)` function. The function takes a **service name** (and a `context.Context`) and returns either a `*tc.DockerContainer` or an `error`. -This is different to the previous `LocalDockerCompose` API where service containers were accessed via their **container name** e.g. `mysql_1` or `mysql-1` (depending on the version of `docker-compose`). +This is different to the previous `LocalDockerCompose` API where service containers were accessed via their **container name** e.g. `mysql_1` or `mysql-1` (depending on the version of `docker compose`). Furthermore, there's the convenience function `Serices()` to get a list of all services **defined** by the current project. Note that not all of them need necessarily be correctly started as the information is based on the given compose files. ### Wait strategies -Just like with regular test containers you can also apply wait strategies to `docker-compose` services. +Just like with regular test containers you can also apply wait strategies to `docker compose` services. The `ComposeStack.WaitForService(...)` function allows you to apply a wait strategy to **a service by name**. All wait strategies are executed in parallel to both improve startup performance by not blocking too long and to fail early if something's wrong. @@ -139,7 +139,7 @@ func TestSomethingWithWaiting(t *testing.T) { ### Compose environment -`docker-compose` supports expansion based on environment variables. +`docker compose` supports expansion based on environment variables. The `ComposeStack` supports this as well in two different variants: - `ComposeStack.WithEnv(m map[string]string) ComposeStack` to parameterize stacks from your test code @@ -150,14 +150,14 @@ The `ComposeStack` supports this as well in two different variants: Also have a look at [ComposeStack](https://pkg.go.dev/github.com/testcontainers/testcontainers-go#ComposeStack) docs for further information. -## Usage of `docker-compose` binary +## Usage of the `docker compose` binary -_Node:_ this API is deprecated and superseded by `ComposeStack` which takes advantage of `docker-compose` v2 being +_Node:_ this API is deprecated and superseded by `ComposeStack` which takes advantage of `compose` v2 being implemented in Go as well by directly using the upstream project. You can override Testcontainers' default behaviour and make it use a -docker-compose binary installed on the local machine. This will generally yield -an experience that is closer to running docker-compose locally, with the caveat +docker compose binary installed on the local machine. This will generally yield +an experience that is closer to running docker compose locally, with the caveat that Docker Compose needs to be present on dev and CI machines. ### Examples diff --git a/modules/compose/compose.go b/modules/compose/compose.go index 75bf55e0aa..242caef501 100644 --- a/modules/compose/compose.go +++ b/modules/compose/compose.go @@ -155,11 +155,12 @@ func NewLocalDockerCompose(filePaths []string, identifier string, opts ...LocalD opts[idx].ApplyToLocalCompose(dc.LocalDockerComposeOptions) } - dc.Executable = "docker-compose" + dc.Executable = "docker" if runtime.GOOS == "windows" { - dc.Executable = "docker-compose.exe" + dc.Executable = "docker.exe" } + dc.composeSubcommand = "compose" dc.ComposeFilePaths = filePaths dc.absComposeFilePaths = make([]string, len(filePaths)) diff --git a/modules/compose/compose_api.go b/modules/compose/compose_api.go index b0ec87ed29..409875537c 100644 --- a/modules/compose/compose_api.go +++ b/modules/compose/compose_api.go @@ -34,7 +34,7 @@ func (f stackDownOptionFunc) applyToStackDown(do *api.DownOptions) { f(do) } -// RunServices is comparable to 'docker-compose run' as it only creates a subset of containers +// RunServices is comparable to 'docker compose run' as it only creates a subset of containers // instead of all services defined by the project func RunServices(serviceNames ...string) StackUpOption { return stackUpOptionFunc(func(o *stackUpOptions) { @@ -231,7 +231,6 @@ func (d *dockerCompose) Up(ctx context.Context, opts ...StackUpOption) error { Wait: upOptions.Wait, }, }) - if err != nil { return err } diff --git a/modules/compose/compose_local.go b/modules/compose/compose_local.go index c008e2ec9d..2be2daf152 100644 --- a/modules/compose/compose_local.go +++ b/modules/compose/compose_local.go @@ -41,12 +41,14 @@ func (c composeVersion2) Format(parts ...string) string { return strings.Join(parts, "-") } +// Deprecated: use ComposeStack instead // LocalDockerCompose represents a Docker Compose execution using local binary -// docker-compose or docker-compose.exe, depending on the underlying platform +// docker compose or docker.exe compose, depending on the underlying platform type LocalDockerCompose struct { ComposeVersion *LocalDockerComposeOptions Executable string + composeSubcommand string ComposeFilePaths []string absComposeFilePaths []string Identifier string @@ -58,17 +60,20 @@ type LocalDockerCompose struct { } type ( + // Deprecated: it will be removed in the next major release // LocalDockerComposeOptions defines options applicable to LocalDockerCompose LocalDockerComposeOptions struct { Logger testcontainers.Logging } + // Deprecated: it will be removed in the next major release // LocalDockerComposeOption defines a common interface to modify LocalDockerComposeOptions // These options can be passed to NewLocalDockerCompose in a variadic way to customize the returned LocalDockerCompose instance LocalDockerComposeOption interface { ApplyToLocalCompose(opts *LocalDockerComposeOptions) } + // Deprecated: it will be removed in the next major release // LocalDockerComposeOptionsFunc is a shorthand to implement the LocalDockerComposeOption interface LocalDockerComposeOptionsFunc func(opts *LocalDockerComposeOptions) ) @@ -86,6 +91,7 @@ func WithLogger(logger testcontainers.Logging) ComposeLoggerOption { } } +// Deprecated: it will be removed in the next major release func (o ComposeLoggerOption) ApplyToLocalCompose(opts *LocalDockerComposeOptions) { opts.Logger = o.logger } @@ -94,15 +100,18 @@ func (o ComposeLoggerOption) applyToComposeStack(opts *composeStackOptions) { opts.Logger = o.logger } +// Deprecated: it will be removed in the next major release func (f LocalDockerComposeOptionsFunc) ApplyToLocalCompose(opts *LocalDockerComposeOptions) { f(opts) } -// Down executes docker-compose down +// Deprecated: it will be removed in the next major release +// Down executes docker compose down func (dc *LocalDockerCompose) Down() ExecError { return executeCompose(dc, []string{"down", "--remove-orphans", "--volumes"}) } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) getDockerComposeEnvironment() map[string]string { environment := map[string]string{} @@ -117,10 +126,12 @@ func (dc *LocalDockerCompose) getDockerComposeEnvironment() map[string]string { return environment } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) containerNameFromServiceName(service, separator string) string { return dc.Identifier + separator + service } +// Deprecated: it will be removed in the next major release func (dc *LocalDockerCompose) applyStrategyToRunningContainer() error { cli, err := testcontainers.NewDockerClientWithOpts(context.Background()) if err != nil { @@ -163,17 +174,19 @@ func (dc *LocalDockerCompose) applyStrategyToRunningContainer() error { err = strategy.WaitUntilReady(context.Background(), dockercontainer) if err != nil { - return fmt.Errorf("Unable to apply wait strategy %v to service %s due to %w", strategy, k.service, err) + return fmt.Errorf("unable to apply wait strategy %v to service %s due to %w", strategy, k.service, err) } } return nil } +// Deprecated: it will be removed in the next major release // Invoke invokes the docker compose func (dc *LocalDockerCompose) Invoke() ExecError { return executeCompose(dc, dc.Cmd) } +// Deprecated: it will be removed in the next major release // WaitForService sets the strategy for the service that is to be waited on func (dc *LocalDockerCompose) WaitForService(service string, strategy wait.Strategy) DockerCompose { dc.waitStrategySupplied = true @@ -181,18 +194,21 @@ func (dc *LocalDockerCompose) WaitForService(service string, strategy wait.Strat return dc } +// Deprecated: it will be removed in the next major release // WithCommand assigns the command func (dc *LocalDockerCompose) WithCommand(cmd []string) DockerCompose { dc.Cmd = cmd return dc } +// Deprecated: it will be removed in the next major release // WithEnv assigns the environment func (dc *LocalDockerCompose) WithEnv(env map[string]string) DockerCompose { dc.Env = env return dc } +// Deprecated: it will be removed in the next major release // WithExposedService sets the strategy for the service that is to be waited on. If multiple strategies // are given for a single service running on different ports, both strategies will be applied on the same container func (dc *LocalDockerCompose) WithExposedService(service string, port int, strategy wait.Strategy) DockerCompose { @@ -201,7 +217,8 @@ func (dc *LocalDockerCompose) WithExposedService(service string, port int, strat return dc } -// determineVersion checks which version of docker-compose is installed +// Deprecated: it will be removed in the next major release +// determineVersion checks which version of docker compose is installed // depending on the version services names are composed in a different way func (dc *LocalDockerCompose) determineVersion() error { execErr := executeCompose(dc, []string{"version", "--short"}) @@ -232,6 +249,7 @@ func (dc *LocalDockerCompose) determineVersion() error { return nil } +// Deprecated: it will be removed in the next major release // validate checks if the files to be run in the compose are valid YAML files, setting up // references to all services in them func (dc *LocalDockerCompose) validate() error { @@ -336,11 +354,12 @@ func execute( } } +// Deprecated: it will be removed in the next major release func executeCompose(dc *LocalDockerCompose, args []string) ExecError { if which(dc.Executable) != nil { return ExecError{ Command: []string{dc.Executable}, - Error: fmt.Errorf("Local Docker Compose not found. Is %s on the PATH?", dc.Executable), + Error: fmt.Errorf("Local Docker not found. Is %s on the PATH?", dc.Executable), } } @@ -349,7 +368,8 @@ func executeCompose(dc *LocalDockerCompose, args []string) ExecError { environment[k] = v } - var cmds []string + // initialise the command with the compose subcommand + cmds := []string{dc.composeSubcommand} pwd := "." if len(dc.absComposeFilePaths) > 0 { pwd, _ = filepath.Split(dc.absComposeFilePaths[0]) @@ -367,7 +387,7 @@ func executeCompose(dc *LocalDockerCompose, args []string) ExecError { if err != nil { args := strings.Join(dc.Cmd, " ") return ExecError{ - Command: []string{dc.Executable}, + Command: []string{dc.Executable, args}, Error: fmt.Errorf("Local Docker compose exited abnormally whilst running %s: [%v]. %s", dc.Executable, args, err.Error()), } } From d24cf912cedcb991f79f1088ce6c652e2fab7f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 3 Apr 2024 10:22:27 +0200 Subject: [PATCH 3/4] chore: more compose updates in comments --- docker_test.go | 2 +- modules/compose/compose_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker_test.go b/docker_test.go index 45e276b1ed..bc29e854d0 100644 --- a/docker_test.go +++ b/docker_test.go @@ -1854,7 +1854,7 @@ func TestContainerWithNoUserID(t *testing.T) { } func TestGetGatewayIP(t *testing.T) { - // When using docker-compose with DinD mode, and using host port or http wait strategy + // When using docker compose with DinD mode, and using host port or http wait strategy // It's need to invoke GetGatewayIP for get the host provider, err := providerType.GetProvider(WithLogger(TestLogger(t))) if err != nil { diff --git a/modules/compose/compose_test.go b/modules/compose/compose_test.go index bffec7bd94..c87e204725 100644 --- a/modules/compose/compose_test.go +++ b/modules/compose/compose_test.go @@ -33,7 +33,7 @@ func ExampleNewLocalDockerCompose() { func ExampleLocalDockerCompose() { _ = LocalDockerCompose{ - Executable: "docker-compose", + Executable: "docker compose", ComposeFilePaths: []string{ "/path/to/docker-compose.yml", "/path/to/docker-compose-1.yml", From 2d89e90485fc319beb0ad18ecd4c04e9d68b6648 Mon Sep 17 00:00:00 2001 From: Barrett Strausser Date: Wed, 3 Apr 2024 04:29:36 -0400 Subject: [PATCH 4/4] bug:Fix AMQPS url (#2462) * Fix AMQPS url * Split off amqps and add failing test for client certs * Adds certs into tests --------- Co-authored-by: bstrausser --- modules/rabbitmq/rabbitmq.go | 2 +- modules/rabbitmq/rabbitmq_test.go | 57 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/modules/rabbitmq/rabbitmq.go b/modules/rabbitmq/rabbitmq.go index 9fb28212e1..a6dec1a779 100644 --- a/modules/rabbitmq/rabbitmq.go +++ b/modules/rabbitmq/rabbitmq.go @@ -48,7 +48,7 @@ func (c *RabbitMQContainer) AmqpURL(ctx context.Context) (string, error) { // AmqpURL returns the URL for AMQPS clients. func (c *RabbitMQContainer) AmqpsURL(ctx context.Context) (string, error) { - endpoint, err := c.PortEndpoint(ctx, nat.Port(DefaultAMQPPort), "") + endpoint, err := c.PortEndpoint(ctx, nat.Port(DefaultAMQPSPort), "") if err != nil { return "", err } diff --git a/modules/rabbitmq/rabbitmq_test.go b/modules/rabbitmq/rabbitmq_test.go index 0c85c66607..7079379421 100644 --- a/modules/rabbitmq/rabbitmq_test.go +++ b/modules/rabbitmq/rabbitmq_test.go @@ -2,8 +2,12 @@ package rabbitmq_test import ( "context" + "crypto/tls" + "crypto/x509" "fmt" "io" + "io/ioutil" + "path/filepath" "strings" "testing" @@ -42,6 +46,59 @@ func TestRunContainer_connectUsingAmqp(t *testing.T) { } } +func TestRunContainer_connectUsingAmqps(t *testing.T) { + ctx := context.Background() + + sslSettings := rabbitmq.SSLSettings{ + CACertFile: filepath.Join("testdata", "certs", "server_ca.pem"), + CertFile: filepath.Join("testdata", "certs", "server_cert.pem"), + KeyFile: filepath.Join("testdata", "certs", "server_key.pem"), + VerificationMode: rabbitmq.SSLVerificationModePeer, + FailIfNoCert: false, + VerificationDepth: 1, + } + + rabbitmqContainer, err := rabbitmq.RunContainer(ctx, rabbitmq.WithSSL(sslSettings)) + if err != nil { + t.Fatal(err) + } + + defer func() { + if err := rabbitmqContainer.Terminate(ctx); err != nil { + t.Fatal(err) + } + }() + + amqpsURL, err := rabbitmqContainer.AmqpsURL(ctx) + if err != nil { + t.Fatal(err) + } + + if !strings.HasPrefix(amqpsURL, "amqps") { + t.Fatal(fmt.Errorf("AMQPS Url should begin with `amqps`")) + } + + certs := x509.NewCertPool() + + pemData, err := ioutil.ReadFile(sslSettings.CACertFile) + if err != nil { + t.Fatal(err) + } + certs.AppendCertsFromPEM(pemData) + + amqpsConnection, err := amqp.DialTLS(amqpsURL, &tls.Config{InsecureSkipVerify: false, RootCAs: certs}) + if err != nil { + t.Fatal(err) + } + + if amqpsConnection.IsClosed() { + t.Fatal(fmt.Errorf("AMQPS Connection unexpectdely closed")) + } + if err = amqpsConnection.Close(); err != nil { + t.Fatal(err) + } +} + func TestRunContainer_withAllSettings(t *testing.T) { ctx := context.Background()