Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 6 additions & 23 deletions cmd/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/spf13/cobra"
"github.com/windsorcli/cli/pkg/di"
"github.com/windsorcli/cli/pkg/pipelines"
"github.com/windsorcli/cli/pkg/shell"
)

var (
Expand All @@ -17,34 +16,18 @@ var (
)

var downCmd = &cobra.Command{
Use: "down",
Short: "Tear down the Windsor environment",
Long: "Tear down the Windsor environment by executing necessary shell commands.",
SilenceUsage: true,
Use: "down",
Short: "Tear down the Windsor environment",
Long: "Tear down the Windsor environment by executing necessary shell commands.",
SilenceUsage: true,
PersistentPreRunE: checkTrust,
RunE: func(cmd *cobra.Command, args []string) error {
// Get shared dependency injector from context
injector := cmd.Context().Value(injectorKey).(di.Injector)

// First, initialize a base pipeline to set up core dependencies (shell, config, etc.)
_, err := pipelines.WithPipeline(injector, cmd.Context(), "basePipeline")
if err != nil {
return fmt.Errorf("failed to initialize dependencies: %w", err)
}

// Now check if directory is trusted using the initialized shell
shellInstance := injector.Resolve("shell")
if shellInstance != nil {
if s, ok := shellInstance.(shell.Shell); ok {
if err := s.CheckTrustedDirectory(); err != nil {
return fmt.Errorf("not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve")
}
}
}

// Directory is trusted, proceed with normal pipeline execution
// First, run the env pipeline in quiet mode to set up environment variables
var envPipeline pipelines.Pipeline
envPipeline, err = pipelines.WithPipeline(injector, cmd.Context(), "envPipeline")
envPipeline, err := pipelines.WithPipeline(injector, cmd.Context(), "envPipeline")
if err != nil {
return fmt.Errorf("failed to set up env pipeline: %w", err)
}
Expand Down
24 changes: 0 additions & 24 deletions cmd/down_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,28 +333,4 @@ func TestDownCmd(t *testing.T) {
}
})

t.Run("FailsWhenDirectoryNotTrusted", func(t *testing.T) {
// Given a temporary directory with mocked dependencies
mocks := setupDownMocks(t)

// And shell CheckTrustedDirectory returns an error
mocks.Shell.CheckTrustedDirectoryFunc = func() error {
return fmt.Errorf("directory not trusted")
}

// When executing the down command
cmd := createTestDownCmd()
ctx := context.WithValue(context.Background(), injectorKey, mocks.Injector)
cmd.SetArgs([]string{})
cmd.SetContext(ctx)
err := cmd.Execute()

// Then an error should occur about untrusted directory
if err == nil {
t.Error("Expected error when directory is not trusted, got nil")
}
if !strings.Contains(err.Error(), "not in a trusted directory") {
t.Errorf("Expected error about untrusted directory, got: %v", err)
}
})
}
9 changes: 5 additions & 4 deletions cmd/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (
)

var envCmd = &cobra.Command{
Use: "env",
Short: "Output commands to set environment variables",
Long: "Output commands to set environment variables for the application.",
SilenceUsage: true,
Use: "env",
Short: "Output commands to set environment variables",
Long: "Output commands to set environment variables for the application.",
SilenceUsage: true,
PersistentPreRunE: checkTrust,
RunE: func(cmd *cobra.Command, args []string) error {
// Get shared dependency injector from context
injector := cmd.Context().Value(injectorKey).(di.Injector)
Expand Down
18 changes: 15 additions & 3 deletions cmd/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ func TestEnvCmd(t *testing.T) {
}

t.Run("Success", func(t *testing.T) {
// Given proper output capture
// Given proper output capture and mock setup
_, stderr := setup(t)

// Set up mocks with trusted directory
mocks := setupMocks(t)
_ = mocks

rootCmd.SetArgs([]string{"env"})

// When executing the command
Expand All @@ -35,9 +39,13 @@ func TestEnvCmd(t *testing.T) {
})

t.Run("SuccessWithDecrypt", func(t *testing.T) {
// Given proper output capture
// Given proper output capture and mock setup
_, stderr := setup(t)

// Set up mocks with trusted directory
mocks := setupMocks(t)
_ = mocks

rootCmd.SetArgs([]string{"env", "--decrypt"})

// When executing the command
Expand Down Expand Up @@ -75,9 +83,13 @@ func TestEnvCmd(t *testing.T) {
})

t.Run("SuccessWithVerbose", func(t *testing.T) {
// Given proper output capture
// Given proper output capture and mock setup
_, stderr := setup(t)

// Set up mocks with trusted directory
mocks := setupMocks(t)
_ = mocks

rootCmd.SetArgs([]string{"env", "--verbose"})

// When executing the command
Expand Down
30 changes: 5 additions & 25 deletions cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import (
"github.com/spf13/cobra"
"github.com/windsorcli/cli/pkg/di"
"github.com/windsorcli/cli/pkg/pipelines"
"github.com/windsorcli/cli/pkg/shell"
)

// execCmd represents the exec command
var execCmd = &cobra.Command{
Use: "exec [command] [args...]",
Short: "Execute a command with environment variables",
Long: "Execute a command with environment variables loaded from configuration and secrets",
Args: cobra.MinimumNArgs(1),
Use: "exec [command] [args...]",
Short: "Execute a command with environment variables",
Long: "Execute a command with environment variables loaded from configuration and secrets",
Args: cobra.MinimumNArgs(1),
PersistentPreRunE: checkTrust,
RunE: func(cmd *cobra.Command, args []string) error {
// Safety check for arguments
if len(args) == 0 {
Expand All @@ -25,26 +25,6 @@ var execCmd = &cobra.Command{
// Get shared dependency injector from context
injector := cmd.Context().Value(injectorKey).(di.Injector)

// Initialize base pipeline to set up dependencies
basePipeline, err := pipelines.WithPipeline(injector, cmd.Context(), "basePipeline")
if err != nil {
return fmt.Errorf("failed to set up base pipeline: %w", err)
}

if err := basePipeline.Execute(cmd.Context()); err != nil {
return fmt.Errorf("failed to initialize base pipeline: %w", err)
}

// Now check if directory is trusted using the initialized shell
shellInstance := injector.Resolve("shell")
if shellInstance != nil {
if s, ok := shellInstance.(shell.Shell); ok {
if err := s.CheckTrustedDirectory(); err != nil {
return fmt.Errorf("not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve")
}
}
}

// First, run the env pipeline in quiet mode to set up environment variables
envPipeline, err := pipelines.WithPipeline(injector, cmd.Context(), "envPipeline")
if err != nil {
Expand Down
39 changes: 0 additions & 39 deletions cmd/exec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,45 +63,6 @@ func TestExecCmd(t *testing.T) {
}
})

t.Run("UntrustedDirectory", func(t *testing.T) {
tmpDir := t.TempDir()
originalDir, _ := os.Getwd()
defer func() {
os.Chdir(originalDir)
}()
os.Chdir(tmpDir)

injector := di.NewInjector()

// Register mock shell that fails trust check
mockShell := shell.NewMockShell()
mockShell.CheckTrustedDirectoryFunc = func() error {
return fmt.Errorf("directory not trusted")
}
injector.Register("shell", mockShell)

// Register mock base pipeline
mockBasePipeline := pipelines.NewMockBasePipeline()
injector.Register("basePipeline", mockBasePipeline)

cmd := createTestCmd()
ctx := context.WithValue(context.Background(), injectorKey, injector)
cmd.SetContext(ctx)

args := []string{"go", "version"}
cmd.SetArgs(args)

err := cmd.Execute()

if err == nil {
t.Error("Expected error for untrusted directory, got nil")
}
expectedMsg := "not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve"
if fmt.Sprintf("%v", err) != expectedMsg {
t.Errorf("Expected error message '%s', got '%v'", expectedMsg, err)
}
})

t.Run("NoCommandProvided", func(t *testing.T) {
tmpDir := t.TempDir()
originalDir, _ := os.Getwd()
Expand Down
7 changes: 4 additions & 3 deletions cmd/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ import (
var installWaitFlag bool

var installCmd = &cobra.Command{
Use: "install",
Short: "Install the blueprint's cluster-level services",
SilenceUsage: true,
Use: "install",
Short: "Install the blueprint's cluster-level services",
SilenceUsage: true,
PersistentPreRunE: checkTrust,
RunE: func(cmd *cobra.Command, args []string) error {
// Get shared dependency injector from context
injector := cmd.Context().Value(injectorKey).(di.Injector)
Expand Down
52 changes: 52 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package cmd

import (
"context"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"github.com/windsorcli/cli/pkg/di"
Expand Down Expand Up @@ -50,3 +54,51 @@ func init() {
// Define the --verbose flag
rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "Enable verbose output")
}

// checkTrust performs trust validation for Windsor CLI commands requiring a trusted project directory.
// It verifies directory trust status by checking if the current project directory is in the trusted file list.
// For the "init" command, or for the "env" command with the --hook flag set, trust validation is skipped.
// Returns an error if the directory is untrusted.
func checkTrust(cmd *cobra.Command, args []string) error {
if cmd.Name() == "init" {
return nil
}

if cmd.Name() == "env" {
if hook, _ := cmd.Flags().GetBool("hook"); hook {
return nil
}
}

// Use shims to allow mocking in tests
currentDir, err := shims.Getwd()
if err != nil {
return fmt.Errorf("Error getting current directory: %w", err)
}

homeDir, err := shims.UserHomeDir()
if err != nil {
return fmt.Errorf("Error getting user home directory: %w", err)
}

trustedDirPath := filepath.Join(homeDir, ".config", "windsor")
trustedFilePath := filepath.Join(trustedDirPath, ".trusted")

data, err := shims.ReadFile(trustedFilePath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve")
}
return fmt.Errorf("not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve")
}

trustedDirs := strings.Split(strings.TrimSpace(string(data)), "\n")
for _, trustedDir := range trustedDirs {
trimmedDir := strings.TrimSpace(trustedDir)
if trimmedDir != "" && strings.HasPrefix(currentDir, trimmedDir) {
return nil
}
}

return fmt.Errorf("not in a trusted directory. If you are in a Windsor project, run 'windsor init' to approve")
}
Loading
Loading