From b1430bc2d10ae9b579c8f03fe17910907e4380da Mon Sep 17 00:00:00 2001 From: Guiheux Steven Date: Wed, 7 Jun 2023 17:39:33 +0200 Subject: [PATCH] fix(api): manage variable deletion and env keys as code (#6563) --- engine/api/environment.go | 55 +++++++++++++++---- engine/api/environment/dao_key.go | 6 ++ .../api/environment/environment_importer.go | 52 ++++++------------ .../environment/environment_importer_test.go | 2 +- engine/worker/internal/plugin/socket.go | 2 +- sdk/messages.go | 2 + 6 files changed, 70 insertions(+), 49 deletions(-) diff --git a/engine/api/environment.go b/engine/api/environment.go index e88023f6cd..9d63ef7261 100644 --- a/engine/api/environment.go +++ b/engine/api/environment.go @@ -240,12 +240,33 @@ func (api *API) updateAsCodeEnvironmentHandler() service.Handler { return err } - // check application name pattern + // check environment name pattern regexp := sdk.NamePatternRegex if !regexp.MatchString(env.Name) { return sdk.WrapError(sdk.ErrInvalidApplicationPattern, "Environment name %s do not respect pattern", env.Name) } + envDB, err := environment.LoadEnvironmentByName(api.mustDB(), key, environmentName) + if err != nil { + return sdk.WrapError(err, "cannot load environment %s", environmentName) + } + + // replace placeholder before export + envVarsClear, err := environment.LoadAllVariablesWithDecrytion(api.mustDB(), envDB.ID) + if err != nil { + return err + } + for i := range env.Variables { + v := &env.Variables[i] + if v.Type == sdk.SecretVariable && v.Value == sdk.PasswordPlaceholder { + for _, dbvar := range envVarsClear { + if dbvar.ID == v.ID { + v.Value = dbvar.Value + } + } + } + } + tx, err := api.mustDB().Begin() if err != nil { return sdk.WithStack(err) @@ -257,11 +278,6 @@ func (api *API) updateAsCodeEnvironmentHandler() service.Handler { return err } - envDB, err := environment.LoadEnvironmentByName(tx, key, environmentName) - if err != nil { - return sdk.WrapError(err, "cannot load environment %s", environmentName) - } - if envDB.FromRepository == "" { return sdk.NewErrorFrom(sdk.ErrForbidden, "current environment is not ascode") } @@ -302,15 +318,30 @@ func (api *API) updateAsCodeEnvironmentHandler() service.Handler { } // create keys + envKeys, err := environment.LoadAllKeysWithPrivateContent(tx, env.ID) + if err != nil { + return err + } for i := range env.Keys { k := &env.Keys[i] - newKey, err := keys.GenerateKey(k.Name, k.Type) - if err != nil { - return err + if k.ID == 0 { + newKey, err := keys.GenerateKey(k.Name, k.Type) + if err != nil { + return err + } + k.Public = newKey.Public + k.Private = newKey.Private + k.KeyID = newKey.KeyID + } else { + for _, kClear := range envKeys { + if kClear.ID == k.ID { + k.Public = kClear.Public + k.Private = kClear.Private + k.KeyID = kClear.KeyID + break + } + } } - k.Public = newKey.Public - k.Private = newKey.Private - k.KeyID = newKey.KeyID } u := getUserConsumer(ctx) diff --git a/engine/api/environment/dao_key.go b/engine/api/environment/dao_key.go index 4e5b724162..8fb0a22cf2 100644 --- a/engine/api/environment/dao_key.go +++ b/engine/api/environment/dao_key.go @@ -135,3 +135,9 @@ func DeleteEnvironmentKey(db gorp.SqlExecutor, envID int64, keyName string) erro _, err := db.Exec("DELETE FROM environment_key WHERE environment_id = $1 AND name = $2", envID, keyName) return sdk.WrapError(err, "Cannot delete key %s", keyName) } + +// DeleteAllEnvironmentKeys Delete all environment keys for the given env +func DeleteAllEnvironmentKeys(db gorp.SqlExecutor, envID int64) error { + _, err := db.Exec("DELETE FROM environment_key WHERE environment_id = $1", envID) + return sdk.WrapError(err, "Cannot delete keys from %d", envID) +} diff --git a/engine/api/environment/environment_importer.go b/engine/api/environment/environment_importer.go index 3f4b3b73c5..1fd99ebca6 100644 --- a/engine/api/environment/environment_importer.go +++ b/engine/api/environment/environment_importer.go @@ -67,53 +67,35 @@ func Import(db gorpmapper.SqlExecutorWithTx, proj sdk.Project, env *sdk.Environm // ImportInto import variables and groups on an existing environment func ImportInto(ctx context.Context, db gorpmapper.SqlExecutorWithTx, env *sdk.Environment, into *sdk.Environment, msgChan chan<- sdk.Message, u sdk.Identifiable) error { - var updateVar = func(v *sdk.EnvironmentVariable) { - log.Debug(ctx, "ImportInto> Updating var %q with value %q", v.Name, v.Value) - - varBefore, errV := LoadVariable(db, into.ID, v.Name) - if errV != nil { - msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCannotBeUpdated, v.Name, into.Name, errV) - return - } - - if err := UpdateVariable(db, into.ID, v, varBefore, u); err != nil { - msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCannotBeUpdated, v.Name, into.Name, err) - return - } - msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableUpdated, v.Name, into.Name) + //Delete all Variables + if err := DeleteAllVariables(db, into.ID); err != nil { + return err } - var insertVar = func(v *sdk.EnvironmentVariable) { - log.Debug(ctx, "ImportInto> Creating var %s", v.Name) - if err := InsertVariable(db, into.ID, v, u); err != nil { - msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCannotBeCreated, v.Name, into.Name, err) - return - } - msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCreated, v.Name, into.Name) + ///Delete all Keys + if err := DeleteAllEnvironmentKeys(db, into.ID); err != nil { + return err } for i := range env.Variables { - log.Debug(ctx, "ImportInto> Checking >> %s", env.Variables[i].Name) - var found bool - for j := range into.Variables { - log.Debug(ctx, "ImportInto> \t with >> %s", into.Variables[j].Name) - if env.Variables[i].Name == into.Variables[j].Name { - env.Variables[i].ID = into.Variables[j].ID - found = true - updateVar(&env.Variables[i]) - break - } + if err := InsertVariable(db, into.ID, &env.Variables[i], u); err != nil { + msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCannotBeCreated, env.Variables[i].Name, into.Name, err) + return err } - if !found { - insertVar(&env.Variables[i]) + msgChan <- sdk.NewMessage(sdk.MsgEnvironmentVariableCreated, env.Variables[i].Name, into.Name) + } + + for i := range env.Keys { + if err := InsertKey(db, &env.Keys[i]); err != nil { + msgChan <- sdk.NewMessage(sdk.MsgEnvironmentKeyCannotBeCreated, sdk.SSHKeyVariable, env.Keys[i].Name, into.Name, err) + return err } + msgChan <- sdk.NewMessage(sdk.MsgEnvironmentKeyCreated, sdk.SSHKeyVariable, env.Keys[i].Name, into.Name) } if err := UpdateEnvironment(db, env); err != nil { return sdk.WrapError(err, "unable to update environment") } - log.Debug(ctx, "ImportInto> Done") - return nil } diff --git a/engine/api/environment/environment_importer_test.go b/engine/api/environment/environment_importer_test.go index a5d69cd5c3..35fb75bf52 100644 --- a/engine/api/environment/environment_importer_test.go +++ b/engine/api/environment/environment_importer_test.go @@ -129,7 +129,7 @@ func TestImportInto_Variable(t *testing.T) { } } - assert.True(t, v0found) + assert.False(t, v0found) assert.True(t, v1found) assert.True(t, v2found) assert.True(t, v3found) diff --git a/engine/worker/internal/plugin/socket.go b/engine/worker/internal/plugin/socket.go index 779751f38b..f70a45b460 100644 --- a/engine/worker/internal/plugin/socket.go +++ b/engine/worker/internal/plugin/socket.go @@ -50,7 +50,7 @@ func createGRPCPluginSocket(ctx context.Context, pluginType string, pluginName s //If the file doesn't exist. Download it. fi, err := w.BaseDir().OpenFile(pluginBinaryInfos.Name, os.O_CREATE|os.O_RDWR, os.FileMode(pluginBinaryInfos.Perm)) if err != nil { - return nil, nil, sdk.WrapError(err, "unable to create the file %s", pluginBinaryInfos) + return nil, nil, sdk.WrapError(err, "unable to create the file %s", pluginBinaryInfos.Name) } log.Debug(ctx, "Get the binary plugin %s", pluginBinaryInfos.PluginName) diff --git a/sdk/messages.go b/sdk/messages.go index 2fe5d35987..89562c17fd 100644 --- a/sdk/messages.go +++ b/sdk/messages.go @@ -40,6 +40,7 @@ var ( MsgEnvironmentGroupDeleted = &Message{"MsgEnvironmentGroupDeleted", trad{FR: "Le groupe %s de l'environnement %s a été supprimé", EN: "Group %s on environment %s has been deleted"}, nil, RunInfoTypInfo} MsgEnvironmentGroupCannotBeDeleted = &Message{"MsgEnvironmentGMsgEnvironmentGroupCannotBeDeletedroupCannotBeCreated", trad{FR: "Le groupe %s de l'environnement %s n'a pu être supprimé : %s", EN: "Group %s on environment %s cannot be deleted: %s"}, nil, RunInfoTypeError} MsgEnvironmentKeyCreated = &Message{"MsgEnvironmentKeyCreated", trad{FR: "La clé %s %s a été créée sur l'environnement %s", EN: "%s key %s created on environment %s"}, nil, RunInfoTypInfo} + MsgEnvironmentKeyCannotBeCreated = &Message{"MsgEnvironmentKeyCannotBeCreated", trad{FR: "La clé %s %s n'a pas été créée sur l'environnement %s", EN: "%s key %s cannot be created on environment %s: %v"}, nil, RunInfoTypeError} MsgJobNotValidActionNotFound = &Message{"MsgJobNotValidActionNotFound", trad{FR: "Erreur de validation du Job %s : L'action %s à l'étape %d n'a pas été trouvée", EN: "Job %s validation Failure: Unknown action %s on step #%d"}, nil, RunInfoTypeError} MsgJobNotValidInvalidActionParameter = &Message{"MsgJobNotValidInvalidActionParameter", trad{FR: "Erreur de validation du Job %s : Le paramètre %s de l'étape %d - %s est invalide", EN: "Job %s validation Failure: Invalid parameter %s on step #%d %s"}, nil, RunInfoTypeError} MsgPipelineGroupUpdated = &Message{"MsgPipelineGroupUpdated", trad{FR: "Les permissions du groupe %s sur le pipeline %s on été mises à jour", EN: "Permission for group %s on pipeline %s has been updated"}, nil, RunInfoTypInfo} @@ -125,6 +126,7 @@ var Messages = map[string]*Message{ MsgEnvironmentGroupDeleted.ID: MsgEnvironmentGroupDeleted, MsgEnvironmentGroupCannotBeDeleted.ID: MsgEnvironmentGroupCannotBeDeleted, MsgEnvironmentKeyCreated.ID: MsgEnvironmentKeyCreated, + MsgEnvironmentKeyCannotBeCreated.ID: MsgEnvironmentKeyCannotBeCreated, MsgJobNotValidActionNotFound.ID: MsgJobNotValidActionNotFound, MsgJobNotValidInvalidActionParameter.ID: MsgJobNotValidInvalidActionParameter, MsgPipelineGroupUpdated.ID: MsgPipelineGroupUpdated,