chore: Prevent users overriding configsource
This commit is contained in:
parent
8b8b422c19
commit
b000e82238
|
|
@ -40,7 +40,7 @@ type Action struct {
|
|||
Groups []string `koanf:"groups"`
|
||||
Justification string `koanf:"justification"`
|
||||
// SourceFile is set by OliveTin when loading config (not user YAML).
|
||||
SourceFile string `koanf:"x-olivetin-source-file"`
|
||||
SourceFile string `koanf:"-"`
|
||||
}
|
||||
|
||||
func (action *Action) RequiresJustification() bool {
|
||||
|
|
@ -113,7 +113,7 @@ type EntityFile struct {
|
|||
Icon string `koanf:"icon"`
|
||||
Properties []EntityProperty `koanf:"properties"`
|
||||
// SourceFile is set by OliveTin when loading config (not user YAML).
|
||||
SourceFile string `koanf:"x-olivetin-source-file"`
|
||||
SourceFile string `koanf:"-"`
|
||||
}
|
||||
|
||||
// EntityProperty defines a column shown when listing entity instances in the UI.
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ func AppendSource(cfg *Config, k *koanf.Koanf, configPath string) {
|
|||
return
|
||||
}
|
||||
|
||||
applyStampedSourceFiles(k, cfg)
|
||||
afterLoadFinalize(cfg, configPath)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import (
|
|||
const sourceFileKey = "x-olivetin-source-file"
|
||||
|
||||
// stampSourceOnMaps sets the OliveTin source-file marker on each map in a
|
||||
// koanf slice value (actions or entities).
|
||||
// koanf slice value (actions or entities). Always overwrites so user-provided
|
||||
// x-olivetin-source-file values cannot spoof the real config path.
|
||||
func stampSourceOnMaps(raw any, sourceFile string) any {
|
||||
if sourceFile == "" {
|
||||
return raw
|
||||
|
|
@ -30,9 +31,6 @@ func stampSourceOnMap(item any, sourceFile string) {
|
|||
if !ok {
|
||||
return
|
||||
}
|
||||
if existing, ok := m[sourceFileKey].(string); ok && existing != "" {
|
||||
return
|
||||
}
|
||||
m[sourceFileKey] = sourceFile
|
||||
}
|
||||
|
||||
|
|
@ -49,3 +47,50 @@ func stampConfigKey(k *koanf.Koanf, key, configPath string) {
|
|||
}).Errorf("Failed to persist source stamps: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// applyStampedSourceFiles copies stamped source paths from koanf maps onto
|
||||
// unmarshaled actions/entities. SourceFile uses koanf:"-" so YAML cannot set it.
|
||||
func applyStampedSourceFiles(k *koanf.Koanf, cfg *Config) {
|
||||
actionPaths := stampedSourcePaths(k.Get("actions"))
|
||||
for i, action := range cfg.Actions {
|
||||
if action != nil {
|
||||
action.SourceFile = sourcePathAt(actionPaths, i)
|
||||
}
|
||||
}
|
||||
|
||||
entityPaths := stampedSourcePaths(k.Get("entities"))
|
||||
for i, entity := range cfg.Entities {
|
||||
if entity != nil {
|
||||
entity.SourceFile = sourcePathAt(entityPaths, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func sourcePathAt(paths []string, index int) string {
|
||||
if index >= len(paths) {
|
||||
return ""
|
||||
}
|
||||
return paths[index]
|
||||
}
|
||||
|
||||
func stampedSourcePaths(raw any) []string {
|
||||
items, ok := raw.([]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
paths := make([]string, len(items))
|
||||
for i, item := range items {
|
||||
paths[i] = stampedSourceFromMap(item)
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
func stampedSourceFromMap(item any) string {
|
||||
m, ok := item.(map[string]interface{})
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
path, _ := m[sourceFileKey].(string)
|
||||
return path
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,3 +49,32 @@ entities:
|
|||
require.Len(t, cfg.Entities, 1)
|
||||
assert.Equal(t, includePath, cfg.Entities[0].SourceFile)
|
||||
}
|
||||
|
||||
func TestAppendSourceIgnoresUserProvidedSourceFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
basePath := filepath.Join(dir, "config.yaml")
|
||||
require.NoError(t, os.WriteFile(basePath, []byte(`
|
||||
actions:
|
||||
- title: Spoofed
|
||||
shell: echo hi
|
||||
x-olivetin-source-file: /tmp/fake-user-path.yaml
|
||||
entities:
|
||||
- name: host
|
||||
file: hosts.yaml
|
||||
x-olivetin-source-file: /tmp/fake-entity-path.yaml
|
||||
`), 0o644))
|
||||
|
||||
k := koanf.New(".")
|
||||
require.NoError(t, k.Load(file.Provider(basePath), yaml.Parser()))
|
||||
|
||||
cfg := config.DefaultConfig()
|
||||
config.AppendSource(cfg, k, basePath)
|
||||
|
||||
require.Len(t, cfg.Actions, 1)
|
||||
assert.Equal(t, basePath, cfg.Actions[0].SourceFile)
|
||||
assert.NotEqual(t, "/tmp/fake-user-path.yaml", cfg.Actions[0].SourceFile)
|
||||
|
||||
require.Len(t, cfg.Entities, 1)
|
||||
assert.Equal(t, basePath, cfg.Entities[0].SourceFile)
|
||||
assert.NotEqual(t, "/tmp/fake-entity-path.yaml", cfg.Entities[0].SourceFile)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue