diff --git a/cmd/compose/compose.go b/cmd/compose/compose.go index 7fb0991efd1..83d84fde4d1 100644 --- a/cmd/compose/compose.go +++ b/cmd/compose/compose.go @@ -348,9 +348,7 @@ func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, b Compatibility: o.Compatibility, ProjectOptionsFns: po, LoadListeners: []api.LoadListener{metricsListener}, - OCI: api.OCIOptions{ - InsecureRegistries: o.insecureRegistries, - }, + OCI: o.ociOptions(), } project, err := backend.LoadProject(ctx, loadOpts) @@ -369,10 +367,21 @@ func (o *ProjectOptions) remoteLoaders(dockerCli command.Cli) []loader.ResourceL return nil } git := remote.NewGitRemoteLoader(dockerCli, o.Offline) - oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline, api.OCIOptions{}) + oci := remote.NewOCIRemoteLoader(dockerCli, o.Offline, o.ociOptions()) return []loader.ResourceLoader{git, oci} } +// ociOptions builds the OCI loader configuration from the project options. +// Both the primary project load and the loaders returned by remoteLoaders +// must use this so the --insecure-registry flag is honored on every path +// that pulls an OCI compose artifact (e.g. the interpolation-variable +// re-load that `up` runs via ToModel). See docker/compose#13824. +func (o *ProjectOptions) ociOptions() api.OCIOptions { + return api.OCIOptions{ + InsecureRegistries: o.insecureRegistries, + } +} + func (o *ProjectOptions) toProjectOptions(po ...cli.ProjectOptionsFn) (*cli.ProjectOptions, error) { opts := []cli.ProjectOptionsFn{ cli.WithWorkingDirectory(o.ProjectDir), diff --git a/pkg/e2e/fixtures/publish/oci/compose-interpolated.yaml b/pkg/e2e/fixtures/publish/oci/compose-interpolated.yaml new file mode 100644 index 00000000000..bae8e7a8208 --- /dev/null +++ b/pkg/e2e/fixtures/publish/oci/compose-interpolated.yaml @@ -0,0 +1,5 @@ +services: + app: + image: alpine + environment: + GREETING: ${GREETING:-hello} diff --git a/pkg/e2e/publish_test.go b/pkg/e2e/publish_test.go index 143df23caa0..7d365c783dd 100644 --- a/pkg/e2e/publish_test.go +++ b/pkg/e2e/publish_test.go @@ -205,4 +205,25 @@ networks: default: name: oci_default `) + + // `up` loads the project twice: once through ToProject, then again through + // ToModel (checksForRemoteStack -> promptForInterpolatedVariables) to list + // the interpolation variables when --yes is not passed. That second load + // builds its own OCI loader, which used to drop --insecure-registry and so + // talked HTTPS to a plain-HTTP registry. See docker/compose#13824. + res = c.RunDockerComposeCmd(t, "-f", "./fixtures/publish/oci/compose-interpolated.yaml", + "-p", projectName, "publish", "--with-env", "--yes", "--insecure-registry", registry+"/test:interpolated") + res.Assert(t, icmd.Expected{ExitCode: 0}) + + // Declining the prompt keeps the test hermetic: nothing is created, but the + // re-load has already happened by then, which is what we want to cover. + cmd = c.NewDockerComposeCmd(t, "--project-name=oci-reload", + "--insecure-registry", registry, + "-f", fmt.Sprintf("oci://%s/test:interpolated", registry), "up") + cmd.Stdin = strings.NewReader("n\n") + res = icmd.RunCmd(cmd, func(cmd *icmd.Cmd) { + cmd.Env = append(cmd.Env, "XDG_CACHE_HOME="+t.TempDir()) + }) + assert.Assert(t, !strings.Contains(res.Combined(), "server gave HTTP response to HTTPS client"), res.Combined()) + res.Assert(t, icmd.Expected{ExitCode: 1, Err: "operation cancelled by user"}) }