Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): valid email addresses for GPG keys #6687

Merged
merged 3 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 7 additions & 6 deletions engine/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,10 @@ type Configuration struct {
CustomServiceJobBookDelay map[string]int64 `toml:"customServiceJobBookDelay" comment:"Set custom job book delay for given CDS Hatchery (in seconds)" json:"customServiceJobBookDelay" commented:"true"`
} `toml:"workflow" comment:"######################\n 'Workflow' global configuration \n######################" json:"workflow"`
Project struct {
CreationDisabled bool `toml:"creationDisabled" comment:"Disable project creation for CDS non admin users." json:"creationDisabled" default:"false" commented:"true"`
InfoCreationDisabled string `toml:"infoCreationDisabled" comment:"Optional message to display if project creation is disabled." json:"infoCreationDisabled" default:"" commented:"true"`
VCSManagementDisabled bool `toml:"vcsManagementDisabled" comment:"Disable VCS management on project for CDS non admin users." json:"vcsManagementDisabled" default:"false" commented:"true"`
CreationDisabled bool `toml:"creationDisabled" comment:"Disable project creation for CDS non admin users." json:"creationDisabled" default:"false" commented:"true"`
InfoCreationDisabled string `toml:"infoCreationDisabled" comment:"Optional message to display if project creation is disabled." json:"infoCreationDisabled" default:"" commented:"true"`
VCSManagementDisabled bool `toml:"vcsManagementDisabled" comment:"Disable VCS management on project for CDS non admin users." json:"vcsManagementDisabled" default:"false" commented:"true"`
GPGKeyEmailAddressTemplate string `toml:"gpgKeyEmailAddressTemplate" comment:"Template for GPG Keys email address" json:"gpgKeyEmailAddressTemplate" default:"noreply+cds-{{.ProjectKey}}-{{.KeyName}}@localhost.local" commented:"true"`
} `toml:"project" comment:"######################\n 'Project' global configuration \n######################" json:"project"`
EventBus event.Config `toml:"events" comment:"######################\n Event bus configuration \n######################" json:"events" mapstructure:"events"`
VCS struct {
Expand Down Expand Up @@ -376,7 +377,7 @@ func (a *API) CheckConfiguration(config interface{}) error {

if ok, err := sdk.DirectoryExists(aConfig.Download.Directory); !ok {
if err := os.MkdirAll(aConfig.Download.Directory, os.FileMode(0700)); err != nil {
return fmt.Errorf("Unable to create directory %s: %v", aConfig.Download.Directory, err)
return fmt.Errorf("unable to create directory %s: %v", aConfig.Download.Directory, err)
}
log.Info(context.Background(), "Directory %s has been created", aConfig.Download.Directory)
} else if err != nil {
Expand All @@ -395,7 +396,7 @@ func (a *API) CheckConfiguration(config interface{}) error {
}
if ok, err := sdk.DirectoryExists(aConfig.Artifact.Local.BaseDirectory); !ok {
if err := os.MkdirAll(aConfig.Artifact.Local.BaseDirectory, os.FileMode(0700)); err != nil {
return fmt.Errorf("Unable to create directory %s: %v", aConfig.Artifact.Local.BaseDirectory, err)
return fmt.Errorf("unable to create directory %s: %v", aConfig.Artifact.Local.BaseDirectory, err)
}
log.Info(context.Background(), "Directory %s has been created", aConfig.Artifact.Local.BaseDirectory)
} else if err != nil {
Expand All @@ -411,7 +412,7 @@ func (a *API) CheckConfiguration(config interface{}) error {
}

if (aConfig.DefaultOS == "" && aConfig.DefaultArch != "") || (aConfig.DefaultOS != "" && aConfig.DefaultArch == "") {
return fmt.Errorf("You can't specify just defaultArch without defaultOS in your configuration and vice versa")
return fmt.Errorf("you can't specify just defaultArch without defaultOS in your configuration and vice versa")
}

if aConfig.Auth.RSAPrivateKey == "" && len(aConfig.Auth.RSAPrivateKeys) == 0 {
Expand Down
14 changes: 13 additions & 1 deletion engine/api/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,7 +500,19 @@ func (api *API) updateAsCodeApplicationHandler() service.Handler {
// create keys
for i := range a.Keys {
k := &a.Keys[i]
newKey, err := keys.GenerateKey(k.Name, k.Type)
var newKey sdk.Key
var err error
switch k.Type {
case sdk.KeyTypePGP:
var email string
email, err = api.gpgKeyEmailAddress(ctx, key, k.Name)
if err != nil {
return err
}
newKey, err = keys.GeneratePGPKeyPair(k.Name, "Application key generated by CDS", email)
case sdk.KeyTypeSSH:
newKey, err = keys.GenerateSSHKey(k.Name)
}
if err != nil {
return err
}
Expand Down
12 changes: 10 additions & 2 deletions engine/api/application/application_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type ImportOptions struct {
}

// ParseAndImport parse an exportentities.Application and insert or update the application in database
func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, cache cache.Store, proj sdk.Project, eapp *exportentities.Application, opts ImportOptions, decryptFunc keys.DecryptFunc, u sdk.Identifiable) (*sdk.Application, []sdk.Variable, []sdk.Message, error) {
func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, cache cache.Store, proj sdk.Project, eapp *exportentities.Application, opts ImportOptions, decryptFunc keys.DecryptFunc, u sdk.Identifiable, emailFunc keys.EmailFunc) (*sdk.Application, []sdk.Variable, []sdk.Message, error) {
log.Info(ctx, "ParseAndImport>> Import application %s in project %s (force=%v)", eapp.Name, proj.Key, opts.Force)
msgList := []sdk.Message{}

Expand Down Expand Up @@ -124,7 +124,15 @@ func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, cache
keepOldValue = true
}

kk, err := keys.Parse(ctx, db, proj.ID, kname, kval, decryptFunc)
var gpgEmail string
if kval.Type == sdk.KeyPGPParameter {
gpgEmail, err = emailFunc(ctx, proj.Key, kname)
if err != nil {
return app, nil, msgList, sdk.ErrorWithFallback(err, sdk.ErrWrongRequest, "unable to parse key %s", kname)
}
}

kk, err := keys.Parse(ctx, db, proj.ID, kname, kval, decryptFunc, gpgEmail)
if err != nil {
return app, nil, msgList, sdk.ErrorWithFallback(err, sdk.ErrWrongRequest, "unable to parse key %s", kname)
}
Expand Down
8 changes: 4 additions & 4 deletions engine/api/application/application_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ name: ` + appName + `
require.NoError(t, errapp)

// try to import without force, it must give an error
_, _, _, globalError := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: false}, nil, u)
_, _, _, globalError := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: false}, nil, u, nil)
require.Error(t, globalError)

// try to import with force, but with another repository, it must give an error
_, _, _, globalError2 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true, FromRepository: "bar"}, nil, u)
_, _, _, globalError2 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true, FromRepository: "bar"}, nil, u, nil)
require.Error(t, globalError2)

// try to import with force, without a repo, it's ok
_, _, _, globalError3 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true}, nil, u)
_, _, _, globalError3 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true}, nil, u, nil)
require.NoError(t, globalError3)

}
Expand Down Expand Up @@ -96,7 +96,7 @@ name: ` + appName + `
assert.Equal(t, 1, len(events))

// try to import with force, without a repo, it's ok
_, _, _, globalError3 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true}, nil, u)
_, _, _, globalError3 := application.ParseAndImport(context.TODO(), db, cache, *proj, eapp, application.ImportOptions{Force: true}, nil, u, nil)
require.NoError(t, globalError3)

events, err = ascode.LoadEventsByWorkflowID(context.TODO(), db, wf.ID)
Expand Down
2 changes: 1 addition & 1 deletion engine/api/application_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func Test_getApplicationExportHandler(t *testing.T) {
Type: sdk.KeyTypePGP,
ApplicationID: app.ID,
}
kk, err := keys.GeneratePGPKeyPair(k.Name)
kk, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
require.NoError(t, err)

k.Public = kk.Public
Expand Down
2 changes: 1 addition & 1 deletion engine/api/application_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (api *API) postApplicationImportHandler() service.Handler {
}
defer tx.Rollback() // nolint

newApp, _, msgList, globalError := application.ParseAndImport(ctx, tx, api.Cache, *proj, eapp, application.ImportOptions{Force: force}, project.DecryptWithBuiltinKey, getUserConsumer(ctx))
newApp, _, msgList, globalError := application.ParseAndImport(ctx, tx, api.Cache, *proj, eapp, application.ImportOptions{Force: force}, project.DecryptWithBuiltinKey, getUserConsumer(ctx), api.gpgKeyEmailAddress)
msgListString := translate(msgList)
if globalError != nil {
globalError = sdk.WrapError(globalError, "Unable to import application %s", eapp.Name)
Expand Down
6 changes: 3 additions & 3 deletions engine/api/application_import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func Test_postApplicationImportHandler_NewAppFromYAMLWithKeysAndSecrets(t *testi
ApplicationID: app.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
require.NoError(t, err)
k.Public = kpgp.Public
k.Private = kpgp.Private
Expand Down Expand Up @@ -219,7 +219,7 @@ func Test_postApplicationImportHandler_NewAppFromYAMLWithKeysAndSecretsAndReImpo
ApplicationID: app.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
require.NoError(t, err)
k.Public = kpgp.Public
k.Private = kpgp.Private
Expand Down Expand Up @@ -383,7 +383,7 @@ func Test_postApplicationImportHandler_NewAppFromYAMLWithKeysAndSecretsAndReImpo
ApplicationID: app.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k1.Name)
kpgp, err := keys.GeneratePGPKeyPair(k1.Name, "", "test@cds")
require.NoError(t, err)
k1.Public = kpgp.Public
k1.Private = kpgp.Private
Expand Down
13 changes: 12 additions & 1 deletion engine/api/application_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,18 @@ func (api *API) addKeyInApplicationHandler() service.Handler {
newKey.Name = "app-" + newKey.Name
}

k, err := keys.GenerateKey(newKey.Name, newKey.Type)
var k sdk.Key
switch newKey.Type {
case sdk.KeyTypePGP:
var email string
email, err = api.gpgKeyEmailAddress(ctx, key, newKey.Name)
if err != nil {
return err
}
k, err = keys.GeneratePGPKeyPair(newKey.Name, "Application Key generated by CDS", email)
case sdk.KeyTypeSSH:
k, err = keys.GenerateSSHKey(newKey.Name)
}
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion engine/api/application_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func Test_getKeysInApplicationHandler(t *testing.T) {
ApplicationID: app.ID,
}

pgpK, err := keys.GeneratePGPKeyPair(k.Name)
pgpK, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
if err != nil {
t.Fatal(err)
}
Expand Down
2 changes: 1 addition & 1 deletion engine/api/ascode.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (api *API) postPerformImportAsCodeHandler() service.Handler {
if err != nil {
return err
}
msgPush, wrkflw, _, _, err := workflow.Push(ctx, api.mustDB(), api.Cache, proj, data, opt, getUserConsumer(ctx), project.DecryptWithBuiltinKey)
msgPush, wrkflw, _, _, err := workflow.Push(ctx, api.mustDB(), api.Cache, proj, data, opt, getUserConsumer(ctx), project.DecryptWithBuiltinKey, api.gpgKeyEmailAddress)
allMsg = append(allMsg, msgPush...)
if err != nil {
return sdk.WrapError(err, "unable to push workflow")
Expand Down
2 changes: 1 addition & 1 deletion engine/api/ascode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ vcs_ssh_key: proj-blabla
`
var eapp = new(exportentities.Application)
assert.NoError(t, yaml.Unmarshal([]byte(appS), eapp))
app, _, _, globalError := application.ParseAndImport(context.Background(), db, api.Cache, *p, eapp, application.ImportOptions{Force: true}, nil, u)
app, _, _, globalError := application.ParseAndImport(context.Background(), db, api.Cache, *p, eapp, application.ImportOptions{Force: true}, nil, u, nil)
assert.NoError(t, globalError)

app.FromRepository = repoURL
Expand Down
14 changes: 13 additions & 1 deletion engine/api/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,19 @@ func (api *API) updateAsCodeEnvironmentHandler() service.Handler {
for i := range env.Keys {
k := &env.Keys[i]
if k.ID == 0 {
newKey, err := keys.GenerateKey(k.Name, k.Type)
var newKey sdk.Key
var err error
switch k.Type {
case sdk.KeyTypePGP:
var email string
email, err = api.gpgKeyEmailAddress(ctx, key, k.Name)
if err != nil {
return err
}
newKey, err = keys.GeneratePGPKeyPair(k.Name, "Environment Key generated by CDS", email) // TODO email address
case sdk.KeyTypeSSH:
newKey, err = keys.GenerateSSHKey(k.Name)
}
if err != nil {
return err
}
Expand Down
12 changes: 10 additions & 2 deletions engine/api/environment/environment_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type ImportOptions struct {
}

// ParseAndImport parse an exportentities.Environment and insert or update the environment in database
func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, proj sdk.Project, eenv exportentities.Environment, opts ImportOptions, decryptFunc keys.DecryptFunc, u sdk.Identifiable) (*sdk.Environment, []sdk.Variable, []sdk.Message, error) {
func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, proj sdk.Project, eenv exportentities.Environment, opts ImportOptions, decryptFunc keys.DecryptFunc, u sdk.Identifiable, emailFunc keys.EmailFunc) (*sdk.Environment, []sdk.Variable, []sdk.Message, error) {
log.Debug(ctx, "ParseAndImport>> Import environment %s in project %s from repository %q (force=%v)", eenv.Name, proj.Key, opts.FromRepository, opts.Force)
log.Debug(ctx, "ParseAndImport>> Env: %+v", eenv)

Expand Down Expand Up @@ -124,7 +124,15 @@ func ParseAndImport(ctx context.Context, db gorpmapper.SqlExecutorWithTx, proj s
keepOldValue = true
}

kk, err := keys.Parse(ctx, db, proj.ID, kname, kval, decryptFunc)
var gpgEmail string
if kval.Type == sdk.KeyPGPParameter {
gpgEmail, err = emailFunc(ctx, proj.Key, kname)
if err != nil {
return env, nil, nil, sdk.ErrorWithFallback(err, sdk.ErrWrongRequest, "unable to parse key %s", kname)
}
}

kk, err := keys.Parse(ctx, db, proj.ID, kname, kval, decryptFunc, gpgEmail)
if err != nil {
return env, nil, nil, sdk.WrapError(err, "Unable to parse key")
}
Expand Down
8 changes: 4 additions & 4 deletions engine/api/environment/environment_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ name: ` + envName + `
errenv := yaml.Unmarshal(body, eenv)
require.NoError(t, errenv)

_, _, _, globalError := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: false}, nil, u)
_, _, _, globalError := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: false}, nil, u, nil)
require.Error(t, globalError)

_, _, _, globalError2 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true, FromRepository: "bar"}, nil, u)
_, _, _, globalError2 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true, FromRepository: "bar"}, nil, u, nil)
require.Error(t, globalError2)

_, _, _, globalError3 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true}, nil, u)
_, _, _, globalError3 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true}, nil, u, nil)
require.NoError(t, globalError3)
}
func TestParseAndImportCleanAsCode(t *testing.T) {
Expand Down Expand Up @@ -95,7 +95,7 @@ name: ` + envName + `
assert.Equal(t, 1, len(events))

// try to import with force, without a repo, it's ok
_, _, _, globalError3 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true}, nil, u)
_, _, _, globalError3 := environment.ParseAndImport(context.TODO(), db, *proj, *eenv, environment.ImportOptions{Force: true}, nil, u, nil)
require.NoError(t, globalError3)

events, err = ascode.LoadEventsByWorkflowID(context.TODO(), db, wf.ID)
Expand Down
2 changes: 1 addition & 1 deletion engine/api/environment_export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func Test_getEnvironmentExportHandler(t *testing.T) {
Type: sdk.KeyTypePGP,
EnvironmentID: env.ID,
}
kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
test.NoError(t, err)

k.Public = kpgp.Public
Expand Down
2 changes: 1 addition & 1 deletion engine/api/environment_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (api *API) postEnvironmentImportHandler() service.Handler {
}
defer tx.Rollback() // nolint

_, _, msgList, globalError := environment.ParseAndImport(ctx, tx, *proj, data, environment.ImportOptions{Force: force}, project.DecryptWithBuiltinKey, getUserConsumer(ctx))
_, _, msgList, globalError := environment.ParseAndImport(ctx, tx, *proj, data, environment.ImportOptions{Force: force}, project.DecryptWithBuiltinKey, getUserConsumer(ctx), api.gpgKeyEmailAddress)
msgListString := translate(msgList)
if globalError != nil {
globalError = sdk.WrapError(globalError, "Unable to import environment %s", data.Name)
Expand Down
4 changes: 2 additions & 2 deletions engine/api/environment_import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func Test_postEnvironmentImportHandler_NewEnvFromYAMLWithKeysAndSecrets(t *testi
EnvironmentID: env.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
require.NoError(t, err)
k.Public = kpgp.Public
k.Private = kpgp.Private
Expand Down Expand Up @@ -222,7 +222,7 @@ func Test_postEnvironmentImportHandler_NewEnvFromYAMLWithKeysAndSecretsAndReImpo
EnvironmentID: env.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
require.NoError(t, err)
k.Public = kpgp.Public
k.Private = kpgp.Private
Expand Down
15 changes: 14 additions & 1 deletion engine/api/environment_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,23 @@ func (api *API) addKeyInEnvironmentHandler() service.Handler {
newKey.Name = "env-" + newKey.Name
}

k, err := keys.GenerateKey(newKey.Name, newKey.Type)
var k sdk.Key
var err error
switch newKey.Type {
case sdk.KeyTypePGP:
var email string
email, err = api.gpgKeyEmailAddress(ctx, key, newKey.Name)
if err != nil {
return err
}
k, err = keys.GeneratePGPKeyPair(newKey.Name, "Environment Key generated by CDS", email) // TODO email address
case sdk.KeyTypeSSH:
k, err = keys.GenerateSSHKey(newKey.Name)
}
if err != nil {
return err
}

newKey.Public = k.Public
newKey.Private = k.Private
newKey.ID = k.ID
Expand Down
2 changes: 1 addition & 1 deletion engine/api/environment_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func Test_getKeysInEnvironmentHandler(t *testing.T) {
EnvironmentID: env.ID,
}

kpgp, err := keys.GeneratePGPKeyPair(k.Name)
kpgp, err := keys.GeneratePGPKeyPair(k.Name, "", "test@cds")
if err != nil {
t.Fatal(err)
}
Expand Down
14 changes: 0 additions & 14 deletions engine/api/keys/key.go

This file was deleted.