Skip to content

Commit

Permalink
Add support for customizable secrets (#215)
Browse files Browse the repository at this point in the history
* Add support for customizable secrets

* Edit the appropriate templates

* Adjust tests
  • Loading branch information
marcauberer committed Nov 7, 2021
1 parent 47bc124 commit 1fff09d
Show file tree
Hide file tree
Showing 17 changed files with 81 additions and 15 deletions.
3 changes: 3 additions & 0 deletions .github/scripts/service-validator/config-schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@
'length': {
'type': 'integer',
'required': True
},
'customizable': {
'type': 'boolean'
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion predefined-services/backend/pi-hole/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
{
"name": "Pi-hole password for web interface",
"variable": "_PW_PI_HOLE_WEB_INTERFACE",
"length": 50
"length": 50,
"customizable": true
}
]
}
3 changes: 2 additions & 1 deletion predefined-services/db-admin/pgadmin/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
{
"name": "Default password for pgAdmin",
"variable": "_PW_PGADMIN_DEFAULT",
"length": 30
"length": 30,
"customizable": true
}
]
}
7 changes: 4 additions & 3 deletions src/model/predefined-template.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,10 @@ type Volume struct {

// Secret represents the JSON structure of a secret of a predefined template
type Secret struct {
Name string `json:"name,omitempty"`
Variable string `json:"variable,omitempty"`
Length int `json:"length,omitempty"`
Name string `json:"name,omitempty"`
Variable string `json:"variable,omitempty"`
Length int `json:"length,omitempty"`
Customizable bool `json:"customizable,omitempty"`
}

// Label represents the JSON structure of a label of a predefined template
Expand Down
2 changes: 2 additions & 0 deletions src/pass/generate/gen_choose_backends.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ func GenerateChooseBackends(
askTemplateProxyQuestions(project, &selectedConfig, selected)
// Evaluate proxy labels
evaluateProxyLabels(project, &selectedConfig, selected)
// Ask customizable secrets
askSecretQuestions(project, &selectedConfig)
// Ask volume questions to the user
askForCustomVolumePaths(project, &selectedConfig)
// Save template to the selected templates
Expand Down
3 changes: 3 additions & 0 deletions src/pass/generate/gen_choose_backends_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func TestGenerateChooseBackends2(t *testing.T) {
askTemplateProxyQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig, selectedTemplates *model.SelectedTemplates) {
assert.Equal(t, available.BackendServices[0], *template)
}
askSecretQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.BackendServices[0], *template)
}
askForCustomVolumePaths = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.BackendServices[0], *template)
}
Expand Down
2 changes: 2 additions & 0 deletions src/pass/generate/gen_choose_databases.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ func GenerateChooseDatabases(
askTemplateProxyQuestions(project, &selectedConfig, selected)
// Evaluate proxy labels
evaluateProxyLabels(project, &selectedConfig, selected)
// Ask customizable secrets
askSecretQuestions(project, &selectedConfig)
// Ask volume questions to the user
askForCustomVolumePaths(project, &selectedConfig)
// Save template to the selected templates
Expand Down
3 changes: 3 additions & 0 deletions src/pass/generate/gen_choose_databases_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func TestGenerateChooseDatabases2(t *testing.T) {
askTemplateProxyQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig, selectedTemplates *model.SelectedTemplates) {
assert.Equal(t, available.DatabaseServices[0], *template)
}
askSecretQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.DatabaseServices[0], *template)
}
askForCustomVolumePaths = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.DatabaseServices[0], *template)
}
Expand Down
2 changes: 2 additions & 0 deletions src/pass/generate/gen_choose_db_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ func GenerateChooseDbAdmins(
askTemplateProxyQuestions(project, &selectedConfig, selected)
// Evaluate proxy labels
evaluateProxyLabels(project, &selectedConfig, selected)
// Ask customizable secrets
askSecretQuestions(project, &selectedConfig)
// Ask volume questions to the user
askForCustomVolumePaths(project, &selectedConfig)
// Save template to the selected templates
Expand Down
3 changes: 3 additions & 0 deletions src/pass/generate/gen_choose_db_admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func TestGenerateChooseDbAdmins2(t *testing.T) {
askTemplateProxyQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig, selectedTemplates *model.SelectedTemplates) {
assert.Equal(t, available.DbAdminServices[0], *template)
}
askSecretQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.DbAdminServices[0], *template)
}
askForCustomVolumePaths = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.DbAdminServices[0], *template)
}
Expand Down
2 changes: 2 additions & 0 deletions src/pass/generate/gen_choose_frontends.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ func GenerateChooseFrontends(
askTemplateQuestions(project, &selectedConfig)
// Ask proxy questions to the user
askTemplateProxyQuestions(project, &selectedConfig, selected)
// Ask customizable secrets
askSecretQuestions(project, &selectedConfig)
// Evaluate proxy labels
evaluateProxyLabels(project, &selectedConfig, selected)
// Ask volume questions to the user
Expand Down
3 changes: 3 additions & 0 deletions src/pass/generate/gen_choose_frontends_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ func TestGenerateChooseFrontends2(t *testing.T) {
askTemplateProxyQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig, selectedTemplates *model.SelectedTemplates) {
assert.Equal(t, available.FrontendServices[0], *template)
}
askSecretQuestions = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.FrontendServices[0], *template)
}
askForCustomVolumePaths = func(project *model.CGProject, template *model.PredefinedTemplateConfig) {
assert.Equal(t, available.FrontendServices[0], *template)
}
Expand Down
23 changes: 13 additions & 10 deletions src/pass/generate/gen_secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ func GenerateSecrets(project *model.CGProject, selected *model.SelectedTemplates
spinner := startProcess("Generating secrets ...")
for _, template := range selected.GetAll() {
for _, secret := range template.Secrets {
// Generate secret
res, err := generatePassword(secret.Length, 10, 0, false, false)
if err != nil {
errorLogger.Println("Password generation failed: " + err.Error())
logError("Password generation failed", true)
// Only generate the secrets that are not customizable, the customizable ones are already generated
if !secret.Customizable {
// Generate secret
res, err := generatePassword(secret.Length, 10, 0, false, false)
if err != nil {
errorLogger.Println("Password generation failed: " + err.Error())
logError("Password generation failed", true)
}
project.Secrets = append(project.Secrets, model.ProjectSecret{
Name: secret.Name,
Variable: secret.Variable,
Value: res,
})
}
project.Secrets = append(project.Secrets, model.ProjectSecret{
Name: secret.Name,
Variable: secret.Variable,
Value: res,
})
}
}
stopProcess(spinner)
Expand Down
1 change: 1 addition & 0 deletions src/pass/generate/mock_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var stopProcess = util.StopProcess
var printSecretValue = color.Yellow
var askTemplateQuestions = util.AskTemplateQuestions
var askTemplateProxyQuestions = util.AskTemplateProxyQuestions
var askSecretQuestions = util.AskSecretQuestions
var evaluateProxyLabels = util.EvaluateProxyLabels
var askForCustomVolumePaths = util.AskForCustomVolumePaths
var evaluateConditionalSections = util.EvaluateConditionalSections
Expand Down
2 changes: 2 additions & 0 deletions src/util/mock_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/docker/docker/client"
"github.com/fatih/color"
"github.com/kardianos/osext"
"github.com/sethvargo/go-password/password"
)

// Logging
Expand Down Expand Up @@ -51,3 +52,4 @@ var executeCommand = exec.Command
var getCommandOutput = func(cmd *exec.Cmd) ([]byte, error) {
return cmd.Output()
}
var generatePassword = password.Generate
9 changes: 9 additions & 0 deletions src/util/questions.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ func MultiSelectMenuQuestionIndex(label string, items []string, defaultItems []s
return
}

// PasswordQuestion asks the user for a password and returns it
func PasswordQuestion(question string) (result string) {
prompt := &survey.Password{
Message: question,
}
handleInterrupt(survey.AskOne(prompt, &result))
return
}

// --------------------------------------------------------------- Private functions ---------------------------------------------------------------

func handleInterrupt(err error) {
Expand Down
25 changes: 25 additions & 0 deletions src/util/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,31 @@ func AskTemplateProxyQuestions(project *model.CGProject, template *model.Predefi
}
}

// AskSecretQuestions asks the user password questions for all customizable secrets of the template
func AskSecretQuestions(project *model.CGProject, template *model.PredefinedTemplateConfig) {
for _, secret := range template.Secrets {
// Only generate customizable secrets. Not customizable secrets will be generated later on
if secret.Customizable {
// Ask for password
password := PasswordQuestion(secret.Name + " (recommended length: " + strconv.Itoa(secret.Length) + ", blank to auto-generate)")
if password == "" {
res, err := generatePassword(secret.Length, 10, 0, false, false)
if err != nil {
ErrorLogger.Println("Password generation failed: " + err.Error())
logError("Password generation failed", true)
return
}
password = res
}
project.Secrets = append(project.Secrets, model.ProjectSecret{
Name: secret.Name,
Variable: secret.Variable,
Value: password,
})
}
}
}

// EvaluateProxyLabels adds proxy labels with values to the project based on the answers of the proxy questions
func EvaluateProxyLabels(project *model.CGProject, template *model.PredefinedTemplateConfig, selectedTemplates *model.SelectedTemplates) {
if template.Proxied {
Expand Down

0 comments on commit 1fff09d

Please sign in to comment.