[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>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
ca9d8ab0a4
Коммит
e1b13c10fc
@@ -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")
|
||||
|
||||
Ссылка в новой задаче
Block a user