Skip to content
Next Next commit
Restructure code to allow tests to reuse the underlying command defin…
…ition

Signed-off-by: Jannik Hollenbach <jannik@hollenbach.de>
  • Loading branch information
J12934 committed Jun 22, 2024
commit 6ac51577a7825691bf01adff424e4f71f818c6df
26 changes: 26 additions & 0 deletions scbctl/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cmd

import (
kubernetes "github.com/secureCodeBox/secureCodeBox/scbctl/pkg"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
)

var kubeconfigArgs = genericclioptions.NewConfigFlags(false)

var (
clientProvider kubernetes.ClientProvider = &kubernetes.DefaultClientProvider{}
)

func NewRootCommand() *cobra.Command {
rootCmd := &cobra.Command{
Use: "scbctl",
Short: "cli app to manage scans & other secureCodeBox resources",
Long: ``,
}
kubeconfigArgs.AddFlags(rootCmd.PersistentFlags())

rootCmd.AddCommand(NewScanCommand())

return rootCmd
}
127 changes: 57 additions & 70 deletions scbctl/cmd/scans.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,92 +5,79 @@ package cmd

import (
"context"
"errors"
"fmt"
"strings"

v1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1"
kubernetes "github.com/secureCodeBox/secureCodeBox/scbctl/pkg"

"github.com/spf13/cobra"
metav2 "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
)

var (
kubeconfigArgs = genericclioptions.NewConfigFlags(false)
clientProvider kubernetes.ClientProvider = &kubernetes.DefaultClientProvider{}
scheme = runtime.NewScheme()
)

func init() {
utilruntime.Must(v1.AddToScheme(scheme))
ScanCmd.Flags().StringP("namespace", "n", "", "Namespace in which to create the scan")
}

var ScanCmd = &cobra.Command{
Use: "scan [name] -- [parameters...]",
Short: "Create a new scanner",
Long: `Create a new execution (Scan) in the default namespace if no namespace is provided`,
Example: `
# Create a new scan
scbctl scan nmap
# Create in a different namespace
scbctl scan --namespace foobar nmap -- scanme.nmap.org -p 90
`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {

scanName := args[0]
paramIndex := cmd.ArgsLenAtDash()
if paramIndex == -1 {
return errors.New("You must use '--' to separate scan parameters")
}

parameters := args[paramIndex:]
func NewScanCommand() *cobra.Command {
return &cobra.Command{
Use: "scan [scanType] -- [parameters...]",
Short: "Create a new scan",
Long: `Create a new Scan custom resource in the the current namespace`,
Args: cobra.MinimumNArgs(1),
Example: `
# Create a new scan
scbctl scan nmap -- scanme.nmap.org
# Create in a different namespace
scbctl scan --namespace foobar nmap -- -p 80 scanme.nmap.org
`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {

scanName := args[0]
paramIndex := cmd.ArgsLenAtDash()
if paramIndex == -1 {
return fmt.Errorf("you must use '--' to separate scan parameters")
}

fmt.Println("🎬 Initializing Kubernetes client")
parameters := args[paramIndex:]

kubeclient, namespace, err := clientProvider.GetClient(kubeconfigArgs)
if err != nil {
return fmt.Errorf("Error initializing Kubernetes client: %s", err)
}
fmt.Println("🎬 Initializing Kubernetes client")

if namespaceFlag, err := cmd.Flags().GetString("namespace"); err == nil && namespaceFlag != "" {
namespace = namespaceFlag
}
kubeclient, namespace, err := clientProvider.GetClient(kubeconfigArgs)
if err != nil {
return fmt.Errorf("error initializing kubernetes client: %s", err)
}

fmt.Printf("🆕 Creating a new scan with name '%s' and parameters '%s'\n", scanName, strings.Join(parameters, " "))
if namespaceFlag, err := cmd.Flags().GetString("namespace"); err == nil && namespaceFlag != "" {
namespace = namespaceFlag
}

scan := &v1.Scan{
TypeMeta: metav1.TypeMeta{
Kind: "Scan",
APIVersion: "execution.securecodebox.io/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: scanName,
Namespace: namespace,
},
Spec: v1.ScanSpec{
ScanType: scanName,
Parameters: parameters,
},
}
fmt.Printf("🆕 Creating a new scan with name '%s' and parameters '%s'\n", scanName, strings.Join(parameters, " "))

scan := &v1.Scan{
TypeMeta: metav1.TypeMeta{
Kind: "Scan",
APIVersion: "execution.securecodebox.io/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: scanName,
Namespace: namespace,
},
Spec: v1.ScanSpec{
ScanType: scanName,
Parameters: parameters,
},
}

fmt.Println("🔁 Launching the scan")
fmt.Println("🔁 Launching the scan")

err = kubeclient.Create(context.TODO(), scan)
if err != nil {
if metav2.IsNotFound(err) {
return fmt.Errorf("failed to create Scan: namespace '%s' not found", namespace)
err = kubeclient.Create(context.TODO(), scan)
if err != nil {
if metav2.IsNotFound(err) {
return fmt.Errorf("failed to create Scan: namespace '%s' not found", namespace)
}
return fmt.Errorf("failed to create scan: %s", err)
}
return fmt.Errorf("Failed to create Scan: %s", err)
}

fmt.Printf("🚀 Successfully created a new Scan '%s'\n", args[0])
return nil

},
fmt.Printf("🚀 Successfully created a new Scan '%s'\n", args[0])
return nil
},
}
}
28 changes: 11 additions & 17 deletions scbctl/cmd/scans_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
package cmd

import (
"bytes"
"context"
"errors"
"testing"

v1 "github.com/secureCodeBox/secureCodeBox/operator/apis/execution/v1"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
Expand Down Expand Up @@ -38,12 +38,12 @@ func TestScanCommand(t *testing.T) {
}{
{
name: "Valid entry ",
args: []string{"nmap", "--", "scanme.nmap.org"},
args: []string{"scan", "nmap", "--", "scanme.nmap.org"},
expectedError: nil,
},
{
name: "Valid entry with multiple parameters",
args: []string{"nmap", "--", "scanme.nmap.org", "-p", "90"},
args: []string{"scan", "nmap", "--", "scanme.nmap.org", "-p", "90"},
expectedError: nil,
},
{
Expand All @@ -53,8 +53,8 @@ func TestScanCommand(t *testing.T) {
},
{
name: "No scan parameters provided",
args: []string{"nmap"},
expectedError: errors.New("You must use '--' to separate scan parameters"),
args: []string{"scan", "nmap"},
expectedError: errors.New("you must use '--' to separate scan parameters"),
},
}

Expand All @@ -67,20 +67,14 @@ func TestScanCommand(t *testing.T) {
err: nil,
}

cmd := &cobra.Command{
Use: ScanCmd.Use,
Short: ScanCmd.Short,
Long: ScanCmd.Long,
Example: ScanCmd.Example,
RunE: ScanCmd.RunE,
}

cmd.Flags().AddFlagSet(ScanCmd.Flags())
rootCmd := NewRootCommand()
buf := new(bytes.Buffer)
rootCmd.SetOut(buf)

cmd.SetArgs(tc.args)
cmd.SilenceUsage = true
rootCmd.SetArgs(tc.args)
rootCmd.SilenceUsage = true

err := cmd.Execute()
err := rootCmd.Execute()
if tc.expectedError != nil {
if err == nil || err.Error() != tc.expectedError.Error() {
t.Errorf("expected error: %v, got: %v", tc.expectedError, err)
Expand Down
13 changes: 2 additions & 11 deletions scbctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,19 @@ import (
"os"

"github.com/secureCodeBox/secureCodeBox/scbctl/cmd"
"github.com/spf13/cobra"
v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
)

var kubeconfigArgs = genericclioptions.NewConfigFlags(false)
var scheme = runtime.NewScheme()

var rootCmd = &cobra.Command{
Use: "scbctl",
Short: "cli app to manage scans & other secureCodeBox resources",
Long: ``,
}

func init() {
utilruntime.Must(v1.AddToScheme(scheme))
rootCmd.AddCommand(cmd.ScanCmd)
kubeconfigArgs.AddFlags(rootCmd.PersistentFlags())
}

func main() {
rootCmd := cmd.NewRootCommand()
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
Expand Down