mirror of
https://github.com/docker/compose.git
synced 2025-07-23 13:45:00 +02:00
add warning message when a remote configuration include an another remote config
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
This commit is contained in:
parent
66a47169d5
commit
41e6094041
@ -29,6 +29,7 @@ import (
|
|||||||
"github.com/compose-spec/compose-go/v2/template"
|
"github.com/compose-spec/compose-go/v2/template"
|
||||||
"github.com/compose-spec/compose-go/v2/types"
|
"github.com/compose-spec/compose-go/v2/types"
|
||||||
"github.com/docker/cli/cli/command"
|
"github.com/docker/cli/cli/command"
|
||||||
|
"github.com/docker/compose/v2/internal/tracing"
|
||||||
ui "github.com/docker/compose/v2/pkg/progress"
|
ui "github.com/docker/compose/v2/pkg/progress"
|
||||||
"github.com/docker/compose/v2/pkg/prompt"
|
"github.com/docker/compose/v2/pkg/prompt"
|
||||||
"github.com/docker/compose/v2/pkg/utils"
|
"github.com/docker/compose/v2/pkg/utils"
|
||||||
@ -103,6 +104,11 @@ func checksForRemoteStack(ctx context.Context, dockerCli command.Cli, project *t
|
|||||||
if !isRemoteConfig(dockerCli, options) {
|
if !isRemoteConfig(dockerCli, options) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if metrics, ok := ctx.Value(tracing.MetricsKey{}).(tracing.Metrics); ok && metrics.CountIncludesRemote > 0 {
|
||||||
|
if err := confirmRemoteIncludes(dockerCli, options, assumeYes); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
displayLocationRemoteStack(dockerCli, project, options)
|
displayLocationRemoteStack(dockerCli, project, options)
|
||||||
return promptForInterpolatedVariables(ctx, dockerCli, options.ProjectOptions, assumeYes, cmdEnvs)
|
return promptForInterpolatedVariables(ctx, dockerCli, options.ProjectOptions, assumeYes, cmdEnvs)
|
||||||
}
|
}
|
||||||
@ -245,3 +251,41 @@ func displayLocationRemoteStack(dockerCli command.Cli, project *types.Project, o
|
|||||||
_, _ = fmt.Fprintf(dockerCli.Out(), "Your compose stack %q is stored in %q\n", mainComposeFile, project.WorkingDir)
|
_, _ = fmt.Fprintf(dockerCli.Out(), "Your compose stack %q is stored in %q\n", mainComposeFile, project.WorkingDir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func confirmRemoteIncludes(dockerCli command.Cli, options buildOptions, assumeYes bool) error {
|
||||||
|
if assumeYes {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var remoteIncludes []string
|
||||||
|
remoteLoaders := options.ProjectOptions.remoteLoaders(dockerCli)
|
||||||
|
for _, cf := range options.ProjectOptions.ConfigPaths {
|
||||||
|
for _, loader := range remoteLoaders {
|
||||||
|
if loader.Accept(cf) {
|
||||||
|
remoteIncludes = append(remoteIncludes, cf)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(remoteIncludes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _ = fmt.Fprintln(dockerCli.Out(), "\nWarning: This Compose project includes files from remote sources:")
|
||||||
|
for _, include := range remoteIncludes {
|
||||||
|
_, _ = fmt.Fprintf(dockerCli.Out(), " - %s\n", include)
|
||||||
|
}
|
||||||
|
_, _ = fmt.Fprintln(dockerCli.Out(), "\nRemote includes could potentially be malicious. Make sure you trust the source.")
|
||||||
|
|
||||||
|
msg := "Do you want to continue? [y/N]: "
|
||||||
|
confirmed, err := prompt.NewPrompt(dockerCli.In(), dockerCli.Out()).Confirm(msg, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !confirmed {
|
||||||
|
return fmt.Errorf("operation cancelled by user")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -280,3 +281,114 @@ services:
|
|||||||
normalizeSpaces(actualOutput),
|
normalizeSpaces(actualOutput),
|
||||||
"\nExpected:\n%s\nGot:\n%s", expected, actualOutput)
|
"\nExpected:\n%s\nGot:\n%s", expected, actualOutput)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfirmRemoteIncludes(t *testing.T) {
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
defer ctrl.Finish()
|
||||||
|
cli := mocks.NewMockCli(ctrl)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
opts buildOptions
|
||||||
|
assumeYes bool
|
||||||
|
userInput string
|
||||||
|
wantErr bool
|
||||||
|
errMessage string
|
||||||
|
wantPrompt bool
|
||||||
|
wantOutput string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no remote includes",
|
||||||
|
opts: buildOptions{
|
||||||
|
ProjectOptions: &ProjectOptions{
|
||||||
|
ConfigPaths: []string{
|
||||||
|
"docker-compose.yaml",
|
||||||
|
"./local/path/compose.yaml",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assumeYes: false,
|
||||||
|
wantErr: false,
|
||||||
|
wantPrompt: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "assume yes with remote includes",
|
||||||
|
opts: buildOptions{
|
||||||
|
ProjectOptions: &ProjectOptions{
|
||||||
|
ConfigPaths: []string{
|
||||||
|
"oci://registry.example.com/stack:latest",
|
||||||
|
"git://github.com/user/repo.git",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assumeYes: true,
|
||||||
|
wantErr: false,
|
||||||
|
wantPrompt: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user confirms remote includes",
|
||||||
|
opts: buildOptions{
|
||||||
|
ProjectOptions: &ProjectOptions{
|
||||||
|
ConfigPaths: []string{
|
||||||
|
"oci://registry.example.com/stack:latest",
|
||||||
|
"git://github.com/user/repo.git",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assumeYes: false,
|
||||||
|
userInput: "y\n",
|
||||||
|
wantErr: false,
|
||||||
|
wantPrompt: true,
|
||||||
|
wantOutput: "\nWarning: This Compose project includes files from remote sources:\n" +
|
||||||
|
" - oci://registry.example.com/stack:latest\n" +
|
||||||
|
" - git://github.com/user/repo.git\n" +
|
||||||
|
"\nRemote includes could potentially be malicious. Make sure you trust the source.\n" +
|
||||||
|
"Do you want to continue? [y/N]: ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user rejects remote includes",
|
||||||
|
opts: buildOptions{
|
||||||
|
ProjectOptions: &ProjectOptions{
|
||||||
|
ConfigPaths: []string{
|
||||||
|
"oci://registry.example.com/stack:latest",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
assumeYes: false,
|
||||||
|
userInput: "n\n",
|
||||||
|
wantErr: true,
|
||||||
|
errMessage: "operation cancelled by user",
|
||||||
|
wantPrompt: true,
|
||||||
|
wantOutput: "\nWarning: This Compose project includes files from remote sources:\n" +
|
||||||
|
" - oci://registry.example.com/stack:latest\n" +
|
||||||
|
"\nRemote includes could potentially be malicious. Make sure you trust the source.\n" +
|
||||||
|
"Do you want to continue? [y/N]: ",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
cli.EXPECT().Out().Return(streams.NewOut(buf)).AnyTimes()
|
||||||
|
|
||||||
|
if tt.wantPrompt {
|
||||||
|
inbuf := io.NopCloser(bytes.NewBufferString(tt.userInput))
|
||||||
|
cli.EXPECT().In().Return(streams.NewIn(inbuf)).AnyTimes()
|
||||||
|
}
|
||||||
|
|
||||||
|
err := confirmRemoteIncludes(cli, tt.opts, tt.assumeYes)
|
||||||
|
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, tt.errMessage, err.Error())
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.wantOutput != "" {
|
||||||
|
require.Equal(t, tt.wantOutput, buf.String())
|
||||||
|
}
|
||||||
|
buf.Reset()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -96,6 +96,6 @@ type Pipe struct {
|
|||||||
func (u Pipe) Confirm(message string, defaultValue bool) (bool, error) {
|
func (u Pipe) Confirm(message string, defaultValue bool) (bool, error) {
|
||||||
_, _ = fmt.Fprint(u.stdout, message)
|
_, _ = fmt.Fprint(u.stdout, message)
|
||||||
var answer string
|
var answer string
|
||||||
_, _ = fmt.Scanln(&answer)
|
_, _ = fmt.Fscanln(u.stdin, &answer)
|
||||||
return utils.StringToBool(answer), nil
|
return utils.StringToBool(answer), nil
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user