754 lines
18 KiB
Go
754 lines
18 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/awnumar/memguard"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/influxdata/telegraf"
|
|
"github.com/influxdata/telegraf/plugins/inputs"
|
|
"github.com/influxdata/telegraf/plugins/secretstores"
|
|
)
|
|
|
|
func TestSecretConstantManually(t *testing.T) {
|
|
mysecret := "a wonderful test"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
retrieved, err := s.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(retrieved)
|
|
require.EqualValues(t, mysecret, retrieved)
|
|
}
|
|
|
|
func TestLinking(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
resolvers := map[string]telegraf.ResolveFunc{
|
|
"@{referenced:secret}": func() ([]byte, bool, error) {
|
|
return []byte("resolved secret"), false, nil
|
|
},
|
|
}
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
require.NoError(t, s.Link(resolvers))
|
|
retrieved, err := s.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(retrieved)
|
|
require.EqualValues(t, "a resolved secret", retrieved)
|
|
}
|
|
|
|
func TestLinkingResolverError(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
resolvers := map[string]telegraf.ResolveFunc{
|
|
"@{referenced:secret}": func() ([]byte, bool, error) {
|
|
return nil, false, errors.New("broken")
|
|
},
|
|
}
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
expected := `linking secrets failed: resolving "@{referenced:secret}" failed: broken`
|
|
require.EqualError(t, s.Link(resolvers), expected)
|
|
}
|
|
|
|
func TestGettingUnlinked(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
_, err := s.Get()
|
|
require.ErrorContains(t, err, "unlinked parts in secret")
|
|
}
|
|
|
|
func TestGettingMissingResolver(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
s.unlinked = []string{}
|
|
s.resolvers = map[string]telegraf.ResolveFunc{
|
|
"@{a:dummy}": func() ([]byte, bool, error) {
|
|
return nil, false, nil
|
|
},
|
|
}
|
|
_, err := s.Get()
|
|
expected := `replacing secrets failed: no resolver for "@{referenced:secret}"`
|
|
require.EqualError(t, err, expected)
|
|
}
|
|
|
|
func TestGettingResolverError(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
s.unlinked = []string{}
|
|
s.resolvers = map[string]telegraf.ResolveFunc{
|
|
"@{referenced:secret}": func() ([]byte, bool, error) {
|
|
return nil, false, errors.New("broken")
|
|
},
|
|
}
|
|
_, err := s.Get()
|
|
expected := `replacing secrets failed: resolving "@{referenced:secret}" failed: broken`
|
|
require.EqualError(t, err, expected)
|
|
}
|
|
|
|
func TestUninitializedEnclave(t *testing.T) {
|
|
s := Secret{}
|
|
defer s.Destroy()
|
|
require.NoError(t, s.Link(map[string]telegraf.ResolveFunc{}))
|
|
retrieved, err := s.Get()
|
|
require.NoError(t, err)
|
|
require.Empty(t, retrieved)
|
|
ReleaseSecret(retrieved)
|
|
}
|
|
|
|
func TestEnclaveOpenError(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
memguard.Purge()
|
|
err := s.Link(map[string]telegraf.ResolveFunc{})
|
|
require.ErrorContains(t, err, "opening enclave failed")
|
|
|
|
s.unlinked = []string{}
|
|
_, err = s.Get()
|
|
require.ErrorContains(t, err, "opening enclave failed")
|
|
}
|
|
|
|
func TestMissingResolver(t *testing.T) {
|
|
mysecret := "a @{referenced:secret}"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
err := s.Link(map[string]telegraf.ResolveFunc{})
|
|
require.ErrorContains(t, err, "linking secrets failed: unlinked part")
|
|
}
|
|
|
|
func TestSecretConstant(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cfg []byte
|
|
expected string
|
|
}{
|
|
{
|
|
name: "simple string",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "a secret"
|
|
`),
|
|
expected: "a secret",
|
|
},
|
|
{
|
|
name: "mail address",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "someone@mock.org"
|
|
`),
|
|
expected: "someone@mock.org",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(tt.cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"mock": []byte("fail")},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
|
|
require.EqualValues(t, tt.expected, string(secret))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSecretUnquote(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
cfg []byte
|
|
}{
|
|
{
|
|
name: "single quotes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = 'a secret'
|
|
expected = 'a secret'
|
|
`),
|
|
},
|
|
{
|
|
name: "double quotes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "a secret"
|
|
expected = "a secret"
|
|
`),
|
|
},
|
|
{
|
|
name: "triple single quotes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = '''a secret'''
|
|
expected = '''a secret'''
|
|
`),
|
|
},
|
|
{
|
|
name: "triple double quotes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = """a secret"""
|
|
expected = """a secret"""
|
|
`),
|
|
},
|
|
{
|
|
name: "escaped double quotes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "\"a secret\""
|
|
expected = "\"a secret\""
|
|
`),
|
|
},
|
|
{
|
|
name: "mix double-single quotes (single)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "'a secret'"
|
|
expected = "'a secret'"
|
|
`),
|
|
},
|
|
{
|
|
name: "mix single-double quotes (single)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = '"a secret"'
|
|
expected = '"a secret"'
|
|
`),
|
|
},
|
|
{
|
|
name: "mix double-single quotes (triple-single)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = """'a secret'"""
|
|
expected = """'a secret'"""
|
|
`),
|
|
},
|
|
{
|
|
name: "mix single-double quotes (triple-single)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = '''"a secret"'''
|
|
expected = '''"a secret"'''
|
|
`),
|
|
},
|
|
{
|
|
name: "mix double-single quotes (triple)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = """'''a secret'''"""
|
|
expected = """'''a secret'''"""
|
|
`),
|
|
},
|
|
{
|
|
name: "mix single-double quotes (triple)",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = '''"""a secret"""'''
|
|
expected = '''"""a secret"""'''
|
|
`),
|
|
},
|
|
{
|
|
name: "single quotes with backslashes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = 'Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;'
|
|
expected = 'Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;'
|
|
`),
|
|
},
|
|
{
|
|
name: "double quotes with backslashes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;"
|
|
expected = "Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;"
|
|
`),
|
|
},
|
|
{
|
|
name: "triple single quotes with backslashes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = '''Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;'''
|
|
expected = '''Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;'''
|
|
`),
|
|
},
|
|
{
|
|
name: "triple double quotes with backslashes",
|
|
cfg: []byte(`
|
|
[[inputs.mockup]]
|
|
secret = """Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;"""
|
|
expected = """Server=SQLTELEGRAF\\SQL2022;app name=telegraf;log=1;"""
|
|
`),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(tt.cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
|
|
require.EqualValues(t, plugin.Expected, string(secret))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSecretEnvironmentVariable(t *testing.T) {
|
|
cfg := []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "$SOME_ENV_SECRET"
|
|
`)
|
|
t.Setenv("SOME_ENV_SECRET", "an env secret")
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
|
|
require.EqualValues(t, "an env secret", secret)
|
|
}
|
|
|
|
func TestSecretStoreStatic(t *testing.T) {
|
|
cfg := []byte(
|
|
`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret1}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret2}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:a_strange_secret}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:a_weird_secret}"
|
|
`)
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
require.Len(t, c.Inputs, 4)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{
|
|
"secret1": []byte("Ood Bnar"),
|
|
"secret2": []byte("Thon"),
|
|
"a_strange_secret": []byte("Obi-Wan Kenobi"),
|
|
"a_weird_secret": []byte("Arca Jeth"),
|
|
},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
expected := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"}
|
|
for i, input := range c.Inputs {
|
|
plugin := input.Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, expected[i], secret)
|
|
ReleaseSecret(secret)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreInvalidKeys(t *testing.T) {
|
|
cfg := []byte(
|
|
`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:wild?%go}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:a-strange-secret}"
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:a weird secret}"
|
|
`)
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
require.Len(t, c.Inputs, 4)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{
|
|
"": []byte("Ood Bnar"),
|
|
"wild?%go": []byte("Thon"),
|
|
"a-strange-secret": []byte("Obi-Wan Kenobi"),
|
|
"a weird secret": []byte("Arca Jeth"),
|
|
},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
expected := []string{
|
|
"@{mock:}",
|
|
"@{mock:wild?%go}",
|
|
"@{mock:a-strange-secret}",
|
|
"@{mock:a weird secret}",
|
|
}
|
|
for i, input := range c.Inputs {
|
|
plugin := input.Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
require.EqualValues(t, expected[i], secret)
|
|
ReleaseSecret(secret)
|
|
}
|
|
}
|
|
|
|
func TestSecretEqualTo(t *testing.T) {
|
|
mysecret := "a wonderful test"
|
|
s := NewSecret([]byte(mysecret))
|
|
defer s.Destroy()
|
|
|
|
equal, err := s.EqualTo([]byte(mysecret))
|
|
require.NoError(t, err)
|
|
require.True(t, equal)
|
|
|
|
equal, err = s.EqualTo([]byte("some random text"))
|
|
require.NoError(t, err)
|
|
require.False(t, equal)
|
|
}
|
|
|
|
func TestSecretStoreInvalidReference(t *testing.T) {
|
|
// Make sure we clean-up our mess
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(
|
|
`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:test}"
|
|
`)
|
|
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"test": []byte("Arca Jeth")},
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["foo"] = store
|
|
err := c.LinkSecrets()
|
|
require.EqualError(t, err, `unknown secret-store for "@{mock:test}"`)
|
|
|
|
for _, input := range c.Inputs {
|
|
plugin := input.Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.EqualError(t, err, `unlinked parts in secret: @{mock:test}`)
|
|
require.Empty(t, secret)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreStaticChanging(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(
|
|
`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret}"
|
|
`)
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"secret": []byte("Ood Bnar")},
|
|
Dynamic: false,
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
sequence := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"}
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
|
|
require.EqualValues(t, "Ood Bnar", secret)
|
|
|
|
for _, v := range sequence {
|
|
store.Secrets["secret"] = []byte(v)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
|
|
// The secret should not change as the store is marked non-dyamic!
|
|
require.EqualValues(t, "Ood Bnar", secret)
|
|
ReleaseSecret(secret)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreDynamic(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(
|
|
`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret}"
|
|
`)
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"secret": []byte("Ood Bnar")},
|
|
Dynamic: true,
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
sequence := []string{"Ood Bnar", "Thon", "Obi-Wan Kenobi", "Arca Jeth"}
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
for _, v := range sequence {
|
|
store.Secrets["secret"] = []byte(v)
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
|
|
// The secret should not change as the store is marked non-dynamic!
|
|
require.EqualValues(t, v, secret)
|
|
ReleaseSecret(secret)
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreDeclarationMissingID(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(`[[secretstores.mockup]]`)
|
|
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.ErrorContains(t, err, `error parsing mockup, "mockup" secret-store without ID`)
|
|
}
|
|
|
|
func TestSecretStoreDeclarationInvalidID(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
invalidIDs := []string{"foo.bar", "dummy-123", "test!", "wohoo+"}
|
|
tmpl := `
|
|
[[secretstores.mockup]]
|
|
id = %q
|
|
`
|
|
for _, id := range invalidIDs {
|
|
t.Run(id, func(t *testing.T) {
|
|
cfg := []byte(fmt.Sprintf(tmpl, id))
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.ErrorContains(t, err, `error parsing mockup, invalid secret-store ID`)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSecretStoreDeclarationValidID(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
validIDs := []string{"foobar", "dummy123", "test_id", "W0Hoo_lala123"}
|
|
tmpl := `
|
|
[[secretstores.mockup]]
|
|
id = %q
|
|
`
|
|
for _, id := range validIDs {
|
|
t.Run(id, func(t *testing.T) {
|
|
cfg := []byte(fmt.Sprintf(tmpl, id))
|
|
c := NewConfig()
|
|
err := c.LoadConfigData(cfg)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSecretSet(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "a secret"
|
|
`)
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
require.EqualValues(t, "a secret", string(secret))
|
|
|
|
require.NoError(t, plugin.Secret.Set([]byte("another secret")))
|
|
newsecret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(newsecret)
|
|
require.EqualValues(t, "another secret", string(newsecret))
|
|
}
|
|
|
|
func TestSecretSetResolve(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret}"
|
|
`)
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"secret": []byte("Ood Bnar")},
|
|
Dynamic: true,
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
require.EqualValues(t, "Ood Bnar", string(secret))
|
|
|
|
require.NoError(t, plugin.Secret.Set([]byte("@{mock:secret} is cool")))
|
|
newsecret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(newsecret)
|
|
require.EqualValues(t, "Ood Bnar is cool", string(newsecret))
|
|
}
|
|
|
|
func TestSecretSetResolveInvalid(t *testing.T) {
|
|
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
|
|
|
|
cfg := []byte(`
|
|
[[inputs.mockup]]
|
|
secret = "@{mock:secret}"
|
|
`)
|
|
c := NewConfig()
|
|
require.NoError(t, c.LoadConfigData(cfg))
|
|
require.Len(t, c.Inputs, 1)
|
|
|
|
// Create a mockup secretstore
|
|
store := &MockupSecretStore{
|
|
Secrets: map[string][]byte{"secret": []byte("Ood Bnar")},
|
|
Dynamic: true,
|
|
}
|
|
require.NoError(t, store.Init())
|
|
c.SecretStores["mock"] = store
|
|
require.NoError(t, c.LinkSecrets())
|
|
|
|
plugin := c.Inputs[0].Input.(*MockupSecretPlugin)
|
|
|
|
secret, err := plugin.Secret.Get()
|
|
require.NoError(t, err)
|
|
defer ReleaseSecret(secret)
|
|
require.EqualValues(t, "Ood Bnar", string(secret))
|
|
|
|
err = plugin.Secret.Set([]byte("@{mock:another_secret}"))
|
|
require.ErrorContains(t, err, `linking new secrets failed: unlinked part "@{mock:another_secret}"`)
|
|
}
|
|
|
|
/*** Mockup (input) plugin for testing to avoid cyclic dependencies ***/
|
|
type MockupSecretPlugin struct {
|
|
Secret Secret `toml:"secret"`
|
|
Expected string `toml:"expected"`
|
|
}
|
|
|
|
func (*MockupSecretPlugin) SampleConfig() string { return "Mockup test secret plugin" }
|
|
func (*MockupSecretPlugin) Gather(_ telegraf.Accumulator) error { return nil }
|
|
|
|
type MockupSecretStore struct {
|
|
Secrets map[string][]byte
|
|
Dynamic bool
|
|
}
|
|
|
|
func (s *MockupSecretStore) Init() error {
|
|
return nil
|
|
}
|
|
func (*MockupSecretStore) SampleConfig() string {
|
|
return "Mockup test secret plugin"
|
|
}
|
|
|
|
func (s *MockupSecretStore) Get(key string) ([]byte, error) {
|
|
v, found := s.Secrets[key]
|
|
if !found {
|
|
return nil, errors.New("not found")
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
func (s *MockupSecretStore) Set(key, value string) error {
|
|
s.Secrets[key] = []byte(value)
|
|
return nil
|
|
}
|
|
|
|
func (s *MockupSecretStore) List() ([]string, error) {
|
|
keys := make([]string, 0, len(s.Secrets))
|
|
for k := range s.Secrets {
|
|
keys = append(keys, k)
|
|
}
|
|
return keys, nil
|
|
}
|
|
func (s *MockupSecretStore) GetResolver(key string) (telegraf.ResolveFunc, error) {
|
|
return func() ([]byte, bool, error) {
|
|
v, err := s.Get(key)
|
|
return v, s.Dynamic, err
|
|
}, nil
|
|
}
|
|
|
|
// Register the mockup plugin on loading
|
|
func init() {
|
|
// Register the mockup input plugin for the required names
|
|
inputs.Add("mockup", func() telegraf.Input { return &MockupSecretPlugin{} })
|
|
secretstores.Add("mockup", func(id string) telegraf.SecretStore {
|
|
return &MockupSecretStore{}
|
|
})
|
|
}
|