Repository: datreeio/datree
Pull request #597 (2022-05-01 12:44:45)

feat: pass cli flags as headers on requests


Patch:
diff --git a/pkg/cliClient/cliClient.go b/pkg/cliClient/cliClient.go
index b85eb88..f3f129b 100644
--- a/pkg/cliClient/cliClient.go
+++ b/pkg/cliClient/cliClient.go
@@ -18,6 +18,7 @@ type CliClient struct {
 	timeoutClient    HTTPClient
 	httpErrors       []string
 	networkValidator NetworkValidator
+	flagsHeaders     map[string]string
 }
 
 func NewCliClient(url string, networkValidator NetworkValidator) *CliClient {
@@ -28,5 +29,6 @@ func NewCliClient(url string, networkValidator NetworkValidator) *CliClient {
 		timeoutClient:    nil,
 		httpErrors:       []string{},
 		networkValidator: networkValidator,
+		flagsHeaders:     make(map[string]string),
 	}
 }
diff --git a/pkg/cliClient/evaluation.go b/pkg/cliClient/evaluation.go
index 4c2bff4..8b749ac 100644
--- a/pkg/cliClient/evaluation.go
+++ b/pkg/cliClient/evaluation.go
@@ -4,11 +4,24 @@ import (
 	"encoding/json"
 	"net/http"
 	"strconv"
+	"strings"
 
 	"github.com/datreeio/datree/pkg/ciContext"
 	"github.com/datreeio/datree/pkg/extractor"
 )
 
+type TestCommandFlags struct {
+	Output               string
+	K8sVersion           string
+	IgnoreMissingSchemas bool
+	OnlyK8sFiles         bool
+	Verbose              bool
+	PolicyName           string
+	SchemaLocations      []string
+	PolicyConfig         string
+	NoRecord             bool
+}
+
 type Metadata struct {
 	CliVersion      string               `json:"cliVersion"`
 	Os              string               `json:"os"`
@@ -108,7 +121,7 @@ func (c *CliClient) RequestEvaluationPrerunData(tokenId string, isCi bool) (*Eva
 	}
 
 	isCiQueryParam := "isCi=" + strconv.FormatBool(isCi)
-	res, err := c.httpClient.Request(http.MethodGet, "/cli/evaluation/tokens/"+tokenId+"/prerun?"+isCiQueryParam, nil, nil)
+	res, err := c.httpClient.Request(http.MethodGet, "/cli/evaluation/tokens/"+tokenId+"/prerun?"+isCiQueryParam, nil, c.flagsHeaders)
 
 	if err != nil {
 		networkErr := c.networkValidator.IdentifyNetworkError(err.Error())
@@ -170,12 +183,32 @@ type EvaluationResultRequest struct {
 	PolicyCheckResults map[string]map[string]*FailedRule `json:"policyCheckResults"`
 }
 
+func (c *CliClient) AddFlags(flags map[string]interface{}) {
+	headers := make(map[string]string)
+
+	for key, value := range flags {
+		headerKey := "x-cli-flags-" + key
+		switch value.(type) {
+		case string:
+			headers[headerKey] = value.(string)
+		case bool:
+			headers[headerKey] = strconv.FormatBool(value.(bool))
+		case []string:
+			headers[headerKey] = strings.Join(value.([]string), ",")
+		case int:
+			headers[headerKey] = strconv.Itoa(value.(int))
+		}
+	}
+
+	c.flagsHeaders = headers
+}
+
 func (c *CliClient) SendEvaluationResult(request *EvaluationResultRequest) (*SendEvaluationResultsResponse, error) {
 	if c.networkValidator.IsLocalMode() {
 		return &SendEvaluationResultsResponse{}, nil
 	}
 
-	httpRes, err := c.httpClient.Request(http.MethodPost, "/cli/evaluation/result", request, nil)
+	httpRes, err := c.httpClient.Request(http.MethodPost, "/cli/evaluation/result", request, c.flagsHeaders)
 	if err != nil {
 		networkErr := c.networkValidator.IdentifyNetworkError(err.Error())
 		if networkErr != nil {
diff --git a/scripts/deploy_release_candidate.sh b/scripts/deploy_release_candidate.sh
index 9d53385..d0179d0 100644
--- a/scripts/deploy_release_candidate.sh
+++ b/scripts/deploy_release_candidate.sh
@@ -2,7 +2,7 @@
 set -ex
 
 MAJOR_VERSION=1
-MINOR_VERSION=3
+MINOR_VERSION=4
 
 latestRcTag=$(git tag --sort=-version:refname | grep -E "^${MAJOR_VERSION}\.${MINOR_VERSION}.[0-9]+-rc" | head -n 1 | grep --only-matching "^${MAJOR_VERSION}\.${MINOR_VERSION}.[0-9]\+" || true)
 


Test patch:
diff --git a/cmd/test/main.go b/cmd/test/main.go
index dd0babe..a273ebf 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -6,6 +6,7 @@ import (
 	"io/ioutil"
 	"os"
 	"path/filepath"
+	"reflect"
 	"regexp"
 	"strings"
 	"sync"
@@ -109,6 +110,7 @@ var ViolationsFoundError = errors.New("")
 
 type CliClient interface {
 	RequestEvaluationPrerunData(token string, isCi bool) (*cliClient.EvaluationPrerunDataResponse, error)
+	AddFlags(flags map[string]interface{})
 }
 
 type TestCommandData struct {
@@ -196,6 +198,7 @@ func New(ctx *TestCommandContext) *cobra.Command {
 				return err
 			}
 
+			ctx.CliClient.AddFlags(testCommandFlags.ToMapping())
 			evaluationPrerunData, err := ctx.CliClient.RequestEvaluationPrerunData(localConfigContent.Token, ctx.CiContext.IsCI)
 			saveDefaultRulesAsFile(ctx, evaluationPrerunData.DefaultRulesYaml)
 
@@ -219,6 +222,19 @@ func New(ctx *TestCommandContext) *cobra.Command {
 	return testCommand
 }
 
+func (flags *TestCommandFlags) ToMapping() map[string]interface{} {
+	val := reflect.Indirect(reflect.ValueOf(flags))
+	fieldsAmount := val.Type().NumField()
+	flagsByString := make(map[string]interface{})
+
+	for i := 0; i < fieldsAmount; i++ {
+		field := val.Type().Field(i)
+		flagsByString[field.Name] = val.Field(i).Interface()
+	}
+
+	return flagsByString
+}
+
 // AddFlags registers flags for a cli
 func (flags *TestCommandFlags) AddFlags(cmd *cobra.Command) {
 	if ciContext.Extract() != nil && ciContext.Extract().CIMetadata.ShouldHideEmojis {
diff --git a/cmd/test/main_test.go b/cmd/test/main_test.go
index 5af025e..f079af4 100644
--- a/cmd/test/main_test.go
+++ b/cmd/test/main_test.go
@@ -174,6 +174,9 @@ func (c *CliClientMock) RequestEvaluationPrerunData(token string, isCi bool) (*c
 	return args.Get(0).(*cliClient.EvaluationPrerunDataResponse), nil
 }
 
+func (c *CliClientMock) AddFlags(flags map[string]interface{}) {
+}
+
 type ReaderMock struct {
 	mock.Mock
 }
@@ -690,6 +693,7 @@ func setup() {
 
 	mockedCliClient = &CliClientMock{}
 	mockedCliClient.On("RequestEvaluationPrerunData", mock.Anything).Return(prerunData, nil)
+	mockedCliClient.On("AddFlags", mock.Anything).Return()
 
 	ciContext := &ciContext.CIContext{
 		IsCI: false,
diff --git a/pkg/cliClient/cliClient_test.go b/pkg/cliClient/cliClient_test.go
index 5ffae2b..470fbfa 100644
--- a/pkg/cliClient/cliClient_test.go
+++ b/pkg/cliClient/cliClient_test.go
@@ -307,6 +307,21 @@ func TestPublishPolicies(t *testing.T) {
 	}
 }
 
+func TestAddFlags(t *testing.T) {
+	httpClientMock := mockHTTPClient{}
+	flagsToAdd := map[string]interface{}{"flag-key": "flag-value", "flag-key-bool": true, "bad-flag-key": []int{1, 3}}
+	cliClient := &CliClient{
+		baseUrl:      "http://cli-service.test.io",
+		httpClient:   &httpClientMock,
+		flagsHeaders: make(map[string]string),
+	}
+
+	cliClient.AddFlags(flagsToAdd)
+	assert.Equal(t, "flag-value", cliClient.flagsHeaders["x-cli-flags-flag-key"])
+	assert.Equal(t, "true", cliClient.flagsHeaders["x-cli-flags-flag-key-bool"])
+	assert.Equal(t, "", cliClient.flagsHeaders["x-cli-flags-bad-flag-key"])
+}
+
 func readMock(path string) ([]extractor.Configuration, error) {
 	var configurations []extractor.Configuration