[MM-28692] Include config diffs in audit record for config changing API calls (#17623)

* Replace config generator

* Cleanup

* Some renaming and docs additions to add clarity

* Cleanup logging related methods

* Cleanup emitter

* Fix TestDefaultsGenerator

* Move feature flags synchronization logic out of config package

* Remove unnecessary util functions

* Simplify load/set logic

* Refine semantics and add some test to cover them

* Remove unnecessary deep copies

* Improve logic further

* Fix license header

* Review file store tests

* Fix test

* Fix test

* Avoid additional write during initialization

* More consistent naming

* Update app/feature_flags.go

Co-authored-by: Christopher Speller <crspeller@gmail.com>

* Update config/store.go

Co-authored-by: Christopher Speller <crspeller@gmail.com>

* Update config/store.go

Co-authored-by: Christopher Speller <crspeller@gmail.com>

* Update config/store.go

Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>

* Make ConfigStore.Set() return both old and new configs

* Implement config diff function

* Make app.SaveConfig return previous and current configs

* Add config diff to audit record

* Fix returned configs

* Include high level test

* Move FF synchronizer to its own package

* Remove unidiomatic use of sync.Once

* Add some comments

* Rename function

* More comment

* Save config diff in audit record for local endpoints

* Enable audit for config set/reset commands

* Improve tests output

Co-authored-by: Christopher Speller <crspeller@gmail.com>
Co-authored-by: Ibrahim Serdar Acikgoz <serdaracikgoz86@gmail.com>
Этот коммит содержится в:
Claudio Costa
2021-05-21 09:04:39 +02:00
коммит произвёл GitHub
родитель ca9d8ab0a4
Коммит e1b13c10fc
23 изменённых файлов: 841 добавлений и 136 удалений

Просмотреть файл

@@ -14,6 +14,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/mattermost/mattermost-server/v5/audit"
"github.com/mattermost/mattermost-server/v5/config"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/shared/i18n"
@@ -236,8 +237,8 @@ func configSetCmdF(command *cobra.Command, args []string) error {
newVal := args[1:]
// create the function to update config
oldConfig := configStore.Get()
newConfig := configStore.Get()
oldConfig := configStore.Get().Clone()
newConfig := configStore.Get().Clone()
f := updateConfigValue(configSetting, newVal, oldConfig, newConfig)
f(newConfig)
@@ -249,22 +250,24 @@ func configSetCmdF(command *cobra.Command, args []string) error {
return errors.New("Invalid locale configuration")
}
if _, errSet := configStore.Set(newConfig); errSet != nil {
oldCfg, newCfg, errSet := configStore.Set(newConfig)
if errSet != nil {
return errors.Wrap(errSet, "failed to set config")
}
/*
Uncomment when CI unit test fail resolved.
a, errInit := InitDBCommandContextCobra(command)
if errInit != nil {
return errInit
}
defer a.Srv().Shutdown()
a, errInit := InitDBCommandContextCobra(command)
if errInit == nil {
auditRec := a.MakeAuditRecord("configSet", audit.Success)
auditRec.AddMeta("setting", configSetting)
auditRec.AddMeta("new_value", newVal)
a.LogAuditRec(auditRec, nil)
a.Srv().Shutdown()
}
*/
auditRec := a.MakeAuditRecord("configSet", audit.Success)
defer a.LogAuditRec(auditRec, nil)
diffs, diffErr := config.Diff(oldCfg, newCfg)
if diffErr != nil {
return errors.Wrap(diffErr, "failed to diff configs")
}
auditRec.AddMeta("diff", diffs)
return nil
}
@@ -423,14 +426,37 @@ func configResetCmdF(command *cobra.Command, args []string) error {
return err
}
a, errInit := InitDBCommandContextCobra(command)
if errInit != nil {
return errInit
}
defer a.Srv().Shutdown()
var oldCfg *model.Config
var newCfg *model.Config
defer func() {
auditRec := a.MakeAuditRecord("configReset", audit.Success)
if oldCfg != nil && newCfg != nil {
diffs, diffErr := config.Diff(oldCfg, newCfg)
if diffErr != nil {
mlog.Warn("Failed to diff configs", mlog.Err(diffErr))
return
}
auditRec.AddMeta("diff", diffs)
}
a.LogAuditRec(auditRec, nil)
}()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
confirmFlag, _ := command.Flags().GetBool("confirm")
if confirmFlag {
if _, err = configStore.Set(defaultConfig); err != nil {
if oldCfg, newCfg, err = configStore.Set(defaultConfig); err != nil {
return errors.Wrap(err, "failed to set config")
}
return nil
}
if !confirmFlag && len(args) == 0 {
@@ -438,13 +464,14 @@ func configResetCmdF(command *cobra.Command, args []string) error {
CommandPrettyPrintln("Are you sure you want to reset all the configuration settings?(YES/NO): ")
fmt.Scanln(&confirmResetAll)
if confirmResetAll == "YES" {
if _, err = configStore.Set(defaultConfig); err != nil {
if oldCfg, newCfg, err = configStore.Set(defaultConfig); err != nil {
return errors.Wrap(err, "failed to set config")
}
}
return nil
}
tempConfig := configStore.Get()
tempConfig := configStore.Get().Clone()
tempConfigMap := configToMap(*tempConfig)
defaultConfigMap := configToMap(*defaultConfig)
for _, arg := range args {
@@ -467,21 +494,11 @@ func configResetCmdF(command *cobra.Command, args []string) error {
return errors.New("Invalid locale configuration")
}
if _, errSet := configStore.Set(tempConfig); errSet != nil {
return errors.Wrap(errSet, "failed to set config")
oldCfg, newCfg, err = configStore.Set(tempConfig)
if err != nil {
return errors.Wrap(err, "failed to set config")
}
/*
Uncomment when CI unit test fail resolved.
a, errInit := InitDBCommandContextCobra(command)
if errInit == nil {
auditRec := a.MakeAuditRecord("configReset", audit.Success)
a.LogAuditRec(auditRec, nil)
a.Srv().Shutdown()
}
*/
return nil
}

Просмотреть файл

@@ -207,6 +207,8 @@ func TestConfigReset(t *testing.T) {
})
t.Run("Success when the confirm boolean flag is given", func(t *testing.T) {
th := Setup(t)
defer th.TearDown()
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "PrivacySettings.ShowFullName", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "--confirm"))
@@ -217,10 +219,20 @@ func TestConfigReset(t *testing.T) {
})
t.Run("Success when a configuration section is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunScheduler", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "PrivacySettings.ShowFullName", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings"))
th := Setup(t)
defer th.TearDown()
output, err := th.RunCommandWithOutput(t, "config", "set", "JobSettings.RunJobs", "false")
assert.NoErrorf(t, err, "output %s", output)
output, err = th.RunCommandWithOutput(t, "config", "set", "JobSettings.RunScheduler", "false")
assert.NoErrorf(t, err, "output %s", output)
output, err = th.RunCommandWithOutput(t, "config", "set", "PrivacySettings.ShowFullName", "false")
assert.NoErrorf(t, err, "output %s", output)
output, err = th.RunCommandWithOutput(t, "config", "reset", "JobSettings")
assert.NoErrorf(t, err, "output %s", output)
output1 := th.CheckCommand(t, "config", "get", "JobSettings.RunJobs")
output2 := th.CheckCommand(t, "config", "get", "JobSettings.RunScheduler")
output3 := th.CheckCommand(t, "config", "get", "PrivacySettings.ShowFullName")
@@ -230,9 +242,18 @@ func TestConfigReset(t *testing.T) {
})
t.Run("Success when a configuration setting is given", func(t *testing.T) {
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunJobs", "false"))
assert.NoError(t, th.RunCommand(t, "config", "set", "JobSettings.RunScheduler", "false"))
assert.NoError(t, th.RunCommand(t, "config", "reset", "JobSettings.RunJobs"))
th := Setup(t)
defer th.TearDown()
output, err := th.RunCommandWithOutput(t, "config", "set", "JobSettings.RunJobs", "false")
assert.NoErrorf(t, err, "output %s", output)
output, err = th.RunCommandWithOutput(t, "config", "set", "JobSettings.RunScheduler", "false")
assert.NoErrorf(t, err, "output %s", output)
output, err = th.RunCommandWithOutput(t, "config", "reset", "JobSettings.RunJobs")
assert.NoErrorf(t, err, "output %s", output)
output1 := th.CheckCommand(t, "config", "get", "JobSettings.RunJobs")
output2 := th.CheckCommand(t, "config", "get", "JobSettings.RunScheduler")
assert.Contains(t, output1, "true")