Skip to content

Commit

Permalink
feat: Add description flag and validation to secrets
Browse files Browse the repository at this point in the history
Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
  • Loading branch information
eamansour committed Oct 29, 2024
1 parent 4ee3ef1 commit c6d416d
Show file tree
Hide file tree
Showing 17 changed files with 440 additions and 86 deletions.
66 changes: 60 additions & 6 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -156,18 +156,72 @@
"verified_result": null
},
{
"hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3",
"hashed_secret": "679d55ddc3c3d0f6ea2d11275a5d084669c98d56",
"is_secret": false,
"is_verified": false,
"line_number": 57,
"line_number": 62,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "3b938c1150a71e71e5f1ffeadbe6475f0f6a2e36",
"is_secret": false,
"is_verified": false,
"line_number": 122,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "2dfbe3ec00a96d6f711d9a70f78be17f6fd574ca",
"is_secret": false,
"is_verified": false,
"line_number": 274,
"line_number": 284,
"type": "Secret Keyword",
"verified_result": null
}
],
"pkg/secrets/secretsSet.go": [
{
"hashed_secret": "28aa91a8e751e5c49714ac040e98812f9110a1fd",
"is_secret": false,
"is_verified": false,
"line_number": 54,
"type": "Secret Keyword",
"verified_result": null
}
],
"pkg/secrets/secretsSet_test.go": [
{
"hashed_secret": "89e7fc0c50091804bfeb26cddefc0e701dd60fab",
"is_secret": false,
"is_verified": false,
"line_number": 316,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "edbd5e119f94badb9f99a67ac6ff4c7a5204ad61",
"is_secret": false,
"is_verified": false,
"line_number": 822,
"type": "Secret Keyword",
"verified_result": null
},
{
"hashed_secret": "ea531d9e3ac1dc2beec9c298fb0026d59e4e2262",
"is_secret": false,
"is_verified": false,
"line_number": 825,
"type": "Secret Keyword",
"verified_result": null
}
],
"pkg/secretsformatter/GalasaSecret.go": [
{
"hashed_secret": "1949c4c92eb313637b3b6f654f5cce42df0dde88",
"is_secret": false,
"is_verified": false,
"line_number": 62,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -187,7 +241,7 @@
"hashed_secret": "11747ed2a3904f82931baf592443772259ea8dc1",
"is_secret": false,
"is_verified": false,
"line_number": 19,
"line_number": 20,
"type": "Secret Keyword",
"verified_result": null
}
Expand All @@ -204,10 +258,10 @@
],
"pkg/secretsformatter/yamlFormatter_test.go": [
{
"hashed_secret": "347cd9c53ff77d41a7b22aa56c7b4efaf54658e3",
"hashed_secret": "679d55ddc3c3d0f6ea2d11275a5d084669c98d56",
"is_secret": false,
"is_verified": false,
"line_number": 25,
"line_number": 29,
"type": "Secret Keyword",
"verified_result": null
}
Expand Down
3 changes: 2 additions & 1 deletion docs/generated/errors-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ The `galasactl` tool can generate the following errors:
- GAL1169E: An attempt to delete a secret named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in a valid json format. Cause: '{}'
- GAL1170E: An attempt to delete a secret named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are: '{}'
- GAL1171E: An attempt to delete a secret named '{}' failed. Unexpected http status code {} received from the server. Error details from the server are not in the json format.
- GAL1172E: Invalid secret name provided. The name provided with the --name flag cannot be empty or contain spaces.
- GAL1172E: Invalid secret name provided. The name provided with the --name flag cannot be empty or contain spaces, and must only contain characters in the Latin-1 character set.
- GAL1173E: An attempt to delete a secret named '{}' failed. Sending the delete request to the Galasa service failed. Cause is {}
- GAL1174E: An attempt to get a secret named '{}' failed. Unexpected http status code {} received from the server.
- GAL1175E: An attempt to get a secret named '{}' failed. Unexpected http status code {} received from the server. Error details from the server could not be read. Cause: {}
Expand All @@ -189,6 +189,7 @@ The `galasactl` tool can generate the following errors:
- GAL1191E: Failed to set a secret named '{}'. Unexpected http status code {} received from the server. Error details from the server are not in the json format.
- GAL1192E: Failed to set a secret named '{}'. Sending the put request to the Galasa service failed. Cause is {}
- GAL1193E: Invalid flag combination provided. --username cannot be provided with --base64-username, --password cannot be provided with --base64-password, and --token cannot be provided with --base64-token. Use the --help flag for more information, or refer to the documentation at https://galasa.dev/docs/reference/cli-commands.
- GAL1194E: Invalid secret description provided. The description provided with the --description flag cannot be an empty string, and must only contain characters in the Latin-1 character set.
- GAL1225E: Failed to open file '{}' cause: {}. Check that this file exists, and that you have read permissions.
- GAL1226E: Internal failure. Contents of gzip could be read, but not decoded. New gzip reader failed: file: {} error: {}
- GAL1227E: Internal failure. Contents of gzip could not be decoded. {} error: {}
Expand Down
1 change: 1 addition & 0 deletions docs/generated/galasactl_secrets_set.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ galasactl secrets set [flags]
--base64-password string a base64-encoded password to set into a secret
--base64-token string a base64-encoded token to set into a secret
--base64-username string a base64-encoded username to set into a secret
--description string the description to associate with the secret being created or updated
-h, --help Displays the options for the 'secrets set' command.
--name string A mandatory flag that identifies the secret to be created or manipulated.
--password string a password to set into a secret
Expand Down
3 changes: 3 additions & 0 deletions pkg/cmd/secretsSet.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type SecretsSetCmdValues struct {
username string
password string
token string
description string
}

type SecretsSetCommand struct {
Expand Down Expand Up @@ -104,6 +105,7 @@ func (cmd *SecretsSetCommand) createCobraCmd(
base64TokenFlag := "base64-token"

secretsSetCobraCmd.Flags().StringVar(&cmd.values.secretType, "type", "", fmt.Sprintf("the desired secret type to convert an existing secret into. Supported types are: %v.", galasaapi.AllowedGalasaSecretTypeEnumValues))
secretsSetCobraCmd.Flags().StringVar(&cmd.values.description, "description", "", "the description to associate with the secret being created or updated")
secretsSetCobraCmd.Flags().StringVar(&cmd.values.username, usernameFlag, "", "a username to set into a secret")
secretsSetCobraCmd.Flags().StringVar(&cmd.values.password, passwordFlag, "", "a password to set into a secret")
secretsSetCobraCmd.Flags().StringVar(&cmd.values.token, tokenFlag, "", "a token to set into a secret")
Expand Down Expand Up @@ -186,6 +188,7 @@ func (cmd *SecretsSetCommand) executeSecretsSet(
cmd.values.base64Password,
cmd.values.base64Token,
cmd.values.secretType,
cmd.values.description,
console,
apiClient,
byteReader,
Expand Down
4 changes: 3 additions & 1 deletion pkg/errors/errorMessage.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ var (
GALASA_ERROR_DELETE_SECRET_UNPARSEABLE_CONTENT = NewMessageType("GAL1169E: An attempt to delete a secret named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1169, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_DELETE_SECRET_SERVER_REPORTED_ERROR = NewMessageType("GAL1170E: An attempt to delete a secret named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1170, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_DELETE_SECRET_EXPLANATION_NOT_JSON = NewMessageType("GAL1171E: An attempt to delete a secret named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1171, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_INVALID_SECRET_NAME = NewMessageType("GAL1172E: Invalid secret name provided. The name provided with the --name flag cannot be empty or contain spaces.", 1172, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_INVALID_SECRET_NAME = NewMessageType("GAL1172E: Invalid secret name provided. The name provided with the --name flag cannot be empty or contain spaces, and must only contain characters in the Latin-1 character set.", 1172, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_DELETE_SECRET_REQUEST_FAILED = NewMessageType("GAL1173E: An attempt to delete a secret named '%s' failed. Sending the delete request to the Galasa service failed. Cause is %v", 1173, STACK_TRACE_NOT_WANTED)

GALASA_ERROR_GET_SECRET_NO_RESPONSE_CONTENT = NewMessageType("GAL1174E: An attempt to get a secret named '%s' failed. Unexpected http status code %v received from the server.", 1174, STACK_TRACE_NOT_WANTED)
Expand All @@ -294,6 +294,8 @@ var (
GALASA_ERROR_SET_SECRET_REQUEST_FAILED = NewMessageType("GAL1192E: Failed to set a secret named '%s'. Sending the put request to the Galasa service failed. Cause is %v", 1192, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_SET_SECRET_INVALID_FLAG_COMBINATION = NewMessageType("GAL1193E: Invalid flag combination provided. --username cannot be provided with --base64-username, --password cannot be provided with --base64-password, and --token cannot be provided with --base64-token."+SEE_COMMAND_REFERENCE, 1193, STACK_TRACE_NOT_WANTED)

GALASA_ERROR_INVALID_SECRET_DESCRIPTION = NewMessageType("GAL1194E: Invalid secret description provided. The description provided with the --description flag cannot be an empty string, and must only contain characters in the Latin-1 character set.", 1194, STACK_TRACE_NOT_WANTED)

// Warnings...
GALASA_WARNING_MAVEN_NO_GALASA_OBR_REPO = NewMessageType("GAL2000W: Warning: Maven configuration file settings.xml should contain a reference to a Galasa repository so that the galasa OBR can be resolved. The official release repository is '%s', and 'pre-release' repository is '%s'", 2000, STACK_TRACE_WANTED)

Expand Down
29 changes: 26 additions & 3 deletions pkg/secrets/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,35 @@ import (
galasaErrors "github.com/galasa-dev/cli/pkg/errors"
)

func validateSecretName(secretName string) error {
func validateSecretName(secretName string) (string, error) {
var err error
secretName = strings.TrimSpace(secretName)

if secretName == "" || strings.ContainsAny(secretName, " \n\t") {
if secretName == "" || strings.ContainsAny(secretName, " .\n\t") || !isLatin1(secretName) {
err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_SECRET_NAME)
}
return err
return secretName, err
}

func validateDescription(description string) (string, error) {
var err error
description = strings.TrimSpace(description)

if description == "" || !isLatin1(description) {
err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_SECRET_DESCRIPTION)
}
return description, err
}

// Checks if a given string contains only characters in the Latin-1 character set (codepoints 0-255),
// returning true if so, and false otherwise
func isLatin1(str string) bool {
isValidLatin1 := true
for _, character := range str {
if character > 255 {
isValidLatin1 = false
break
}
}
return isValidLatin1
}
2 changes: 1 addition & 1 deletion pkg/secrets/secretsDelete.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func DeleteSecret(
) error {
var err error

err = validateSecretName(secretName)
secretName, err = validateSecretName(secretName)
if err == nil {
log.Printf("Secret name validated OK")
err = sendDeleteSecretRequest(secretName, apiClient, byteReader)
Expand Down
2 changes: 1 addition & 1 deletion pkg/secrets/secretsGet.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func getSecretByName(
) (*galasaapi.GalasaSecret, error) {
var err error
var secret *galasaapi.GalasaSecret
err = validateSecretName(secretName)
secretName, err = validateSecretName(secretName)
if err == nil {
secret, err = getSecretFromRestApi(secretName, apiClient, byteReader)
}
Expand Down
62 changes: 36 additions & 26 deletions pkg/secrets/secretsGet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
package secrets

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"testing"

"github.com/galasa-dev/cli/pkg/api"
"github.com/galasa-dev/cli/pkg/galasaapi"
"github.com/galasa-dev/cli/pkg/utils"
"github.com/stretchr/testify/assert"
"encoding/json"
"fmt"
"net/http"
"strconv"
"testing"

"github.com/galasa-dev/cli/pkg/api"
"github.com/galasa-dev/cli/pkg/galasaapi"
"github.com/galasa-dev/cli/pkg/utils"
"github.com/stretchr/testify/assert"
)

const (
Expand All @@ -25,7 +25,7 @@ const (
DUMMY_PASSWORD = "dummy-password"
)

func createMockGalasaSecret(secretName string) galasaapi.GalasaSecret {
func createMockGalasaSecret(secretName string, description string) galasaapi.GalasaSecret {
secret := *galasaapi.NewGalasaSecret()

secret.SetApiVersion(API_VERSION)
Expand All @@ -36,6 +36,10 @@ func createMockGalasaSecret(secretName string) galasaapi.GalasaSecret {
secretMetadata.SetEncoding(DUMMY_ENCODING)
secretMetadata.SetType("UsernamePassword")

if description != "" {
secretMetadata.SetDescription(description)
}

secretData := *galasaapi.NewGalasaSecretData()
secretData.SetUsername(DUMMY_USERNAME)
secretData.SetPassword(DUMMY_PASSWORD)
Expand All @@ -45,26 +49,27 @@ func createMockGalasaSecret(secretName string) galasaapi.GalasaSecret {
return secret
}

func generateExpectedSecretYaml(secretName string) string {
func generateExpectedSecretYaml(secretName string, description string) string {
return fmt.Sprintf(`apiVersion: %s
kind: GalasaSecret
metadata:
name: %s
description: %s
encoding: %s
type: UsernamePassword
data:
username: %s
password: %s
token: null`, API_VERSION, secretName, DUMMY_ENCODING, DUMMY_USERNAME, DUMMY_PASSWORD)
password: %s`, API_VERSION, secretName, description, DUMMY_ENCODING, DUMMY_USERNAME, DUMMY_PASSWORD)
}

func TestCanGetASecretByName(t *testing.T) {
// Given...
secretName := "SYSTEM1"
description := "my SYSTEM1 secret"
outputFormat := "summary"

// Create the mock secret to return
secret := createMockGalasaSecret(secretName)
secret := createMockGalasaSecret(secretName, description)
secretBytes, _ := json.Marshal(secret)
secretJson := string(secretBytes)

Expand Down Expand Up @@ -97,22 +102,24 @@ func TestCanGetASecretByName(t *testing.T) {
mockByteReader)

// Then...
expectedOutput := fmt.Sprintf(`name type
%s UsernamePassword
expectedOutput := fmt.Sprintf(
`name type description
%s UsernamePassword %s
Total:1
`, secretName)
`, secretName, description)
assert.Nil(t, err, "GetSecrets returned an unexpected error")
assert.Equal(t, expectedOutput, console.ReadText())
}

func TestCanGetASecretByNameInYamlFormat(t *testing.T) {
// Given...
secretName := "SYSTEM1"
description := "my SYSTEM1 secret"
outputFormat := "yaml"

// Create the mock secret to return
secret := createMockGalasaSecret(secretName)
secret := createMockGalasaSecret(secretName, description)
secretBytes, _ := json.Marshal(secret)
secretJson := string(secretBytes)

Expand Down Expand Up @@ -145,7 +152,7 @@ func TestCanGetASecretByNameInYamlFormat(t *testing.T) {
mockByteReader)

// Then...
expectedOutput := generateExpectedSecretYaml(secretName) + "\n"
expectedOutput := generateExpectedSecretYaml(secretName, description) + "\n"
assert.Nil(t, err, "GetSecrets returned an unexpected error")
assert.Equal(t, expectedOutput, console.ReadText())
}
Expand All @@ -160,8 +167,10 @@ func TestCanGetAllSecretsOk(t *testing.T) {
secrets := make([]galasaapi.GalasaSecret, 0)
secret1Name := "BOB"
secret2Name := "BLAH"
secret1 := createMockGalasaSecret(secret1Name)
secret2 := createMockGalasaSecret(secret2Name)
description1 := "my BOB secret"
description2 := "my BLAH secret"
secret1 := createMockGalasaSecret(secret1Name, description1)
secret2 := createMockGalasaSecret(secret2Name, description2)

secrets = append(secrets, secret1, secret2)
secretsBytes, _ := json.Marshal(secrets)
Expand Down Expand Up @@ -196,12 +205,13 @@ func TestCanGetAllSecretsOk(t *testing.T) {
mockByteReader)

// Then...
expectedOutput := fmt.Sprintf(`name type
%s UsernamePassword
%s UsernamePassword
expectedOutput := fmt.Sprintf(
`name type description
%s UsernamePassword %s
%s UsernamePassword %s
Total:2
`, secret1Name, secret2Name)
`, secret1Name, description1, secret2Name, description2)
assert.Nil(t, err, "GetSecrets returned an unexpected error")
assert.Equal(t, expectedOutput, console.ReadText())
}
Expand Down
Loading

0 comments on commit c6d416d

Please sign in to comment.