[MM-57194] Allow plugins to mark setting fields as secret (#27986)

Co-authored-by: Claudio Costa <cstcld91@gmail.com>
Этот коммит содержится в:
Ben Schumacher
2024-09-12 19:23:57 +02:00
коммит произвёл GitHub
родитель 84a0c09d56
Коммит 70fe2abea6
13 изменённых файлов: 311 добавлений и 45 удалений

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

@@ -320,6 +320,8 @@ type AppIface interface {
// RevokeSessionsFromAllUsers will go through all the sessions active
// in the server and revoke them
RevokeSessionsFromAllUsers() *model.AppError
// SanitizedConfig sanitizes a given configuration for a system admin without any secrets.
SanitizedConfig(cfg *model.Config)
// SaveConfig replaces the active configuration, optionally notifying cluster peers.
SaveConfig(newCfg *model.Config, sendConfigChangeClusterMessage bool) (*model.Config, *model.Config, *model.AppError)
// SearchAllChannels returns a list of channels, the total count of the results of the search (if the paginate search option is true), and an error.

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

@@ -214,11 +214,25 @@ func (a *App) GetConfigFile(name string) ([]byte, error) {
// GetSanitizedConfig gets the configuration for a system admin without any secrets.
func (a *App) GetSanitizedConfig() *model.Config {
cfg := a.Config().Clone()
cfg.Sanitize()
a.SanitizedConfig(cfg)
return cfg
}
// SanitizedConfig sanitizes a given configuration for a system admin without any secrets.
func (a *App) SanitizedConfig(cfg *model.Config) {
manifests, err := a.getPluginManifests()
if err != nil {
// GetPluginManifests might error, e.g. when plugins are disabled.
// Sanitize all plugin settings in this case.
cfg.Sanitize(nil)
return
}
cfg.Sanitize(manifests)
}
// GetEnvironmentConfig returns a map of configuration keys whose values have been overridden by an environment variable.
// If filter is not nil and returns false for a struct field, that field will be omitted.
func (a *App) GetEnvironmentConfig(filter func(reflect.StructField) bool) map[string]any {

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

@@ -15239,6 +15239,21 @@ func (a *OpenTracingAppLayer) SanitizeTeams(session model.Session, teams []*mode
return resultVar0
}
func (a *OpenTracingAppLayer) SanitizedConfig(cfg *model.Config) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SanitizedConfig")
a.ctx = newCtx
a.app.Srv().Store().SetContext(newCtx)
defer func() {
a.app.Srv().Store().SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
a.app.SanitizedConfig(cfg)
}
func (a *OpenTracingAppLayer) SaveAcknowledgementForPost(c request.CTX, postID string, userID string) (*model.PostAcknowledgement, *model.AppError) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SaveAcknowledgementForPost")

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

@@ -378,6 +378,25 @@ func (ch *Channels) ShutDownPlugins() {
}
}
func (a *App) getPluginManifests() ([]*model.Manifest, error) {
pluginsEnvironment := a.GetPluginsEnvironment()
if pluginsEnvironment == nil {
return nil, model.NewAppError("GetPluginManifests", "app.plugin.disabled.app_error", nil, "", http.StatusNotImplemented)
}
plugins, err := pluginsEnvironment.Available()
if err != nil {
return nil, errors.Wrap(err, "failed to get list of available plugins")
}
manifests := make([]*model.Manifest, len(plugins))
for i := range plugins {
manifests[i] = plugins[i].Manifest
}
return manifests, nil
}
func (a *App) GetActivePluginManifests() ([]*model.Manifest, *model.AppError) {
pluginsEnvironment := a.GetPluginsEnvironment()
if pluginsEnvironment == nil {

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

@@ -813,43 +813,12 @@ func TestPluginAPISavePluginConfig(t *testing.T) {
assert.Equal(t, expectedConfiguration, savedConfiguration)
}
func TestPluginAPIGetPluginConfig(t *testing.T) {
th := Setup(t)
defer th.TearDown()
manifest := &model.Manifest{
Id: "pluginid",
SettingsSchema: &model.PluginSettingsSchema{
Settings: []*model.PluginSetting{
{Key: "MyStringSetting", Type: "text"},
{Key: "MyIntSetting", Type: "text"},
{Key: "MyBoolSetting", Type: "bool"},
},
},
}
api := NewPluginAPI(th.App, th.Context, manifest)
pluginConfigJsonString := `{"mystringsetting": "str", "myintsetting": 32, "myboolsetting": true}`
var pluginConfig map[string]any
err := json.Unmarshal([]byte(pluginConfigJsonString), &pluginConfig)
require.NoError(t, err)
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.Plugins["pluginid"] = pluginConfig
})
savedPluginConfig := api.GetPluginConfig()
assert.Equal(t, pluginConfig, savedPluginConfig)
}
func TestPluginAPILoadPluginConfiguration(t *testing.T) {
th := Setup(t)
defer th.TearDown()
var pluginJson map[string]any
err := json.Unmarshal([]byte(`{"mystringsetting": "str", "MyIntSetting": 32, "myboolsetting": true}`), &pluginJson)
err := json.Unmarshal([]byte(`{"mystringsetting": "str", "MyIntSetting": 32, "myBoolsetting": true}`), &pluginJson)
require.NoError(t, err)
th.App.UpdateConfig(func(cfg *model.Config) {

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

@@ -34,6 +34,7 @@ func (p *MyPlugin) OnConfigurationChange() error {
}
func (p *MyPlugin) MessageWillBePosted(_ *plugin.Context, _ *model.Post) (*model.Post, string) {
// Test API.LoadPluginConfiguration
if p.configuration.MyStringSetting != "str" {
return nil, "MyStringSetting has invalid value"
}
@@ -43,6 +44,22 @@ func (p *MyPlugin) MessageWillBePosted(_ *plugin.Context, _ *model.Post) (*model
if !p.configuration.MyBoolSetting {
return nil, "MyBoolSetting has invalid value"
}
// Test API.GetPluginConfig
pc := p.API.GetPluginConfig()
if pc == nil {
return nil, "GetPluginConfig returned nil"
}
if pc["mystringsetting"] != "str" {
return nil, fmt.Sprintf("MyStringSetting has invalid value: %v", pc["mystringsetting"])
}
if pc["MyIntSetting"] != float64(32) {
return nil, fmt.Sprintf("MyIntSetting has invalid value: %v", pc["MyIntSetting"])
}
if pc["myBoolsetting"] != true {
return nil, fmt.Sprintf("MyBoolSetting has invalid value: %v", pc["myBoolsetting"])
}
return nil, "OK"
}