Skip to content

Commit

Permalink
Merge pull request #6877 from Checkmarx/kics-1317
Browse files Browse the repository at this point in the history
fix(flag): validating if output path is valid
  • Loading branch information
ArturRibeiro-CX authored Feb 21, 2024
2 parents 430830c + 1268b94 commit e3c9f8f
Show file tree
Hide file tree
Showing 9 changed files with 344 additions and 1 deletion.
55 changes: 55 additions & 0 deletions e2e/fixtures/E2E_CLI_081_RESULT.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"kics_version": "development",
"files_scanned": 1,
"lines_scanned": 78,
"files_parsed": 1,
"lines_parsed": 78,
"lines_ignored": 0,
"files_failed_to_scan": 0,
"queries_total": 43,
"queries_failed_to_execute": 0,
"queries_failed_to_compute_similarity_id": 0,
"scan_id": "console",
"severity_counters": {
"HIGH": 1,
"INFO": 0,
"LOW": 0,
"MEDIUM": 0,
"TRACE": 0
},
"total_counter": 1,
"total_bom_resources": 0,
"start": "2024-02-12T12:34:07.3154393Z",
"end": "2024-02-12T12:34:25.658434Z",
"paths": [
"/path/test/fixtures/test_output_path"
],
"queries": [
{
"query_name": "Azure Instance Using Basic Authentication",
"query_id": "6797f581-0433-4768-ae3e-7ceb2f8b138e",
"query_url": "https://docs.microsoft.com/en-us/azure/templates/microsoft.compute/virtualmachines?tabs=json#linuxconfiguration-object",
"severity": "HIGH",
"platform": "AzureResourceManager",
"category": "Best Practices",
"experimental": false,
"description": "Azure Instances should use SSH Key instead of basic authentication",
"description_id": "98ba05ca",
"files": [
{
"file_name": "..\\test\\fixtures\\test_output_path\\positive1.json",
"similarity_id": "42d73d5b2fa1fbcb1145ea43b7dc4ec20f92adda85c61161b6a7714b6cd86219",
"line": 53,
"resource_type": "Microsoft.Compute/virtualMachines",
"resource_name": "[variables('vmName')]",
"issue_type": "IncorrectValue",
"search_key": "resources.name=[variables('vmName')].properties.osProfile.linuxConfiguration.disablePasswordAuthentication",
"search_line": 53,
"search_value": "",
"expected_value": "'disablePasswordAuthentication' should be set to true",
"actual_value": "'disablePasswordAuthentication' property value is set to false"
}
]
}
]
}
2 changes: 2 additions & 0 deletions e2e/fixtures/E2E_CLI_082_RESULT
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Error: the directory name you provided for the output-path flag contains invalid characters
{{.ScanHelp}}
26 changes: 26 additions & 0 deletions e2e/testcases/e2e-cli-081_output_path_valid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package testcases

// E2E-CLI-081 - KICS scan
// should check if output path is valid
func init() { //nolint
testSample := TestCase{
Name: "should check if output path is valid [E2E-CLI-081]",
Args: args{
Args: []cmdArgs{
[]string{"scan", "-o", "/path/e2e/output",
"--output-name", "E2E_CLI_081_RESULT",
"-p", "\"/path/test/fixtures/test_output_path\"",
},
},
ExpectedResult: []ResultsValidation{
{
ResultsFile: "E2E_CLI_081_RESULT",
ResultsFormats: []string{"json"},
},
},
},
WantStatus: []int{50},
}

Tests = append(Tests, testSample)
}
23 changes: 23 additions & 0 deletions e2e/testcases/e2e-cli-082_output_path_invalid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package testcases

// E2E-CLI-082 - KICS scan
// should check if output path is invalid
func init() { //nolint
testSample := TestCase{
Name: "should check if output path is invalid [E2E-CLI-082]",
Args: args{
Args: []cmdArgs{
[]string{"scan", "-o", "/path/e2e/output?",
"--output-name", "E2E_CLI_082_RESULT",
"-p", "\"/path/test/fixtures/test_output_path\"",
},
},
ExpectedOut: []string{
"E2E_CLI_082_RESULT",
},
},
WantStatus: []int{126},
}

Tests = append(Tests, testSample)
}
3 changes: 2 additions & 1 deletion internal/console/assets/scan-flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@
"flagType": "str",
"shorthandFlag": "o",
"defaultValue": "",
"usage": "directory path to store reports"
"usage": "directory path to store reports",
"validation": "validatePath"
},
"path": {
"flagType": "multiStr",
Expand Down
1 change: 1 addition & 0 deletions internal/console/flags/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var flagValidationFuncs = flagValidationFuncsMap{
"validateMultiStrEnum": validateMultiStrEnum,
"validateStrEnum": validateStrEnum,
"allQueriesID": allQueriesID,
"validatePath": validatePath,
}

func isQueryID(id string) bool {
Expand Down
22 changes: 22 additions & 0 deletions internal/console/flags/validate_path.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package flags

import (
"errors"
"regexp"
)

func validatePath(flagName string) error {
relPath := `^(?:\.\.\\|\.\\|\.\.\/|\.\/|\\|\/)?(?:[^<>:"\/\\|?*]+[\\\/])*[^<>:"\/\\|?*]+(\/|\\)?$`
absPath := `^[a-zA-Z]:[\\\/](?:[^<>:"\/\\|?*]+[\\\/])*[^<>:"\/\\|?*]+(?:\/|\\)?$`
regex := regexp.MustCompile(relPath + `|` + absPath)

path := GetStrFlag(flagName)
isValid := regex.MatchString(path) || path == ""

if !isValid {
errorMsg := "the directory name you provided for the " + flagName + " flag contains invalid characters"
return errors.New(errorMsg)
}

return nil
}
136 changes: 136 additions & 0 deletions internal/console/flags/validate_path_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package flags

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestFlags_validatePathEnum(t *testing.T) {
tests := []struct {
name string
flagName string
flagValue string
wantErr bool
}{
{
name: "should execute fine",
flagName: "output-path",
flagValue: "C:/Users/user/files",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "/file",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "file",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "C:\\Users\\user\\.file",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "/user/files",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "\\user\\file",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "user\\file",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "./user/files",
wantErr: false,
},
{
name: "should execute fine",
flagName: "output-path",
flagValue: "../user/files",
wantErr: false,
},
{
name: "should return an error regarding invalid characters (*)",
flagName: "output-path",
flagValue: "../user/fil*es",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (|)",
flagName: "output-path",
flagValue: "C:/Users/user/files/|",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (\")",
flagName: "output-path",
flagValue: "C:/Users/user/files/\"",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (?)",
flagName: "output-path",
flagValue: "C:/Users/user/files/?",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (?)",
flagName: "output-path",
flagValue: "..\file?",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (>)",
flagName: "output-path",
flagValue: "C:/Users/user/files/>",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (<)",
flagName: "output-path",
flagValue: "C:/Users/user/files/<",
wantErr: true,
},
{
name: "should return an error regarding invalid characters (*)",
flagName: "output-path",
flagValue: "C:/Users/user/files/*",
wantErr: true,
},
{
name: "should return an error regarding invalid characters",
flagName: "output-path",
flagValue: "c:/*<?>*/:??/folder",
wantErr: true,
},
}
for _, test := range tests {
flagsStrReferences[test.flagName] = &test.flagValue
t.Run(test.name, func(t *testing.T) {
gotErr := validatePath(test.flagName)
if !test.wantErr {
require.NoError(t, gotErr)
} else {
require.Error(t, gotErr)
}
})
}
}
77 changes: 77 additions & 0 deletions test/fixtures/test_output_path/positive1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"projectName": {
"type": "string",
"metadata": {
"description": "Specifies a name for generating resource names."
}
},
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Specifies the location for all resources."
}
},
"adminUsername": {
"type": "string",
"metadata": {
"description": "Specifies a username for the Virtual Machine."
}
},
"vmSize": {
"type": "string",
"defaultValue": "Standard_D2s_v3",
"metadata": {
"description": "description"
}
}
},
"variables": {
"vmName": "[concat(parameters('projectName'), '-vm')]",
"networkInterfaceName": "[concat(parameters('projectName'), '-nic')]"
},
"resources": [
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2021-03-01",
"name": "[variables('vmName')]",
"location": "[parameters('location')]",
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
],
"properties": {
"hardwareProfile": {
"vmSize": "[parameters('vmSize')]"
},
"osProfile": {
"computerName": "[variables('vmName')]",
"adminUsername": "[parameters('adminUsername')]",
"linuxConfiguration": {
"disablePasswordAuthentication": false
}
},
"storageProfile": {
"imageReference": {
"publisher": "Canonical",
"offer": "UbuntuServer",
"sku": "18.04-LTS",
"version": "latest"
},
"osDisk": {
"createOption": "FromImage"
}
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('networkInterfaceName'))]"
}
]
}
}
}
]
}

0 comments on commit e3c9f8f

Please sign in to comment.