1
0
Fork 0
telegraf/config/secret_test.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

845 lines
21 KiB
Go

package config
import (
"bytes"
"errors"
"fmt"
"log"
"testing"
"github.com/awnumar/memguard"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"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 retrieved.Destroy()
require.EqualValues(t, mysecret, retrieved.TemporaryString())
}
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 retrieved.Destroy()
require.EqualValues(t, "a resolved secret", retrieved.TemporaryString())
}
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 = make([]string, 0)
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 = make([]string, 0)
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)
defer retrieved.Destroy()
require.Empty(t, retrieved.Bytes())
}
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 = make([]string, 0)
_, 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, EmptySourcePath))
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 secret.Destroy()
require.EqualValues(t, tt.expected, secret.TemporaryString())
})
}
}
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, EmptySourcePath))
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 secret.Destroy()
require.EqualValues(t, plugin.Expected, secret.TemporaryString())
})
}
}
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, EmptySourcePath)
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 secret.Destroy()
require.EqualValues(t, "an env secret", secret.TemporaryString())
}
func TestSecretCount(t *testing.T) {
secretCount.Store(0)
cfg := []byte(`
[[inputs.mockup]]
[[inputs.mockup]]
secret = "a secret"
[[inputs.mockup]]
secret = "another secret"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
require.Len(t, c.Inputs, 3)
require.Equal(t, int64(2), secretCount.Load())
// Remove all secrets and check
for _, ri := range c.Inputs {
input := ri.Input.(*MockupSecretPlugin)
input.Secret.Destroy()
}
require.Equal(t, int64(0), secretCount.Load())
}
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, EmptySourcePath)
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.TemporaryString())
secret.Destroy()
}
}
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, EmptySourcePath)
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.TemporaryString())
secret.Destroy()
}
}
func TestSecretStoreDeclarationMissingID(t *testing.T) {
defer func() { unlinkedSecrets = make([]*Secret, 0) }()
cfg := []byte(`[[secretstores.mockup]]`)
c := NewConfig()
err := c.LoadConfigData(cfg, EmptySourcePath)
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, EmptySourcePath)
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, EmptySourcePath)
require.NoError(t, err)
})
}
}
type SecretImplTestSuite struct {
suite.Suite
protected bool
}
func (tsuite *SecretImplTestSuite) SetupSuite() {
if tsuite.protected {
EnableSecretProtection()
} else {
DisableSecretProtection()
}
}
func (*SecretImplTestSuite) TearDownSuite() {
EnableSecretProtection()
}
func (*SecretImplTestSuite) TearDownTest() {
unlinkedSecrets = make([]*Secret, 0)
}
func (tsuite *SecretImplTestSuite) TestSecretEqualTo() {
t := tsuite.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 (tsuite *SecretImplTestSuite) TestSecretStoreInvalidReference() {
t := tsuite.T()
cfg := []byte(
`
[[inputs.mockup]]
secret = "@{mock:test}"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
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 (tsuite *SecretImplTestSuite) TestSecretStoreStaticChanging() {
t := tsuite.T()
cfg := []byte(
`
[[inputs.mockup]]
secret = "@{mock:secret}"
`)
c := NewConfig()
err := c.LoadConfigData(cfg, EmptySourcePath)
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 secret.Destroy()
require.EqualValues(t, "Ood Bnar", secret.TemporaryString())
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.TemporaryString())
secret.Destroy()
}
}
func (tsuite *SecretImplTestSuite) TestSecretStoreDynamic() {
t := tsuite.T()
cfg := []byte(
`
[[inputs.mockup]]
secret = "@{mock:secret}"
`)
c := NewConfig()
err := c.LoadConfigData(cfg, EmptySourcePath)
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.TemporaryString())
secret.Destroy()
}
}
func (tsuite *SecretImplTestSuite) TestSecretSet() {
t := tsuite.T()
cfg := []byte(`
[[inputs.mockup]]
secret = "a secret"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
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 secret.Destroy()
require.EqualValues(t, "a secret", secret.TemporaryString())
require.NoError(t, plugin.Secret.Set([]byte("another secret")))
newsecret, err := plugin.Secret.Get()
require.NoError(t, err)
defer newsecret.Destroy()
require.EqualValues(t, "another secret", newsecret.TemporaryString())
}
func (tsuite *SecretImplTestSuite) TestSecretSetResolve() {
t := tsuite.T()
cfg := []byte(`
[[inputs.mockup]]
secret = "@{mock:secret}"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
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 secret.Destroy()
require.EqualValues(t, "Ood Bnar", secret.TemporaryString())
require.NoError(t, plugin.Secret.Set([]byte("@{mock:secret} is cool")))
newsecret, err := plugin.Secret.Get()
require.NoError(t, err)
defer newsecret.Destroy()
require.EqualValues(t, "Ood Bnar is cool", newsecret.TemporaryString())
}
func (tsuite *SecretImplTestSuite) TestSecretSetResolveInvalid() {
t := tsuite.T()
cfg := []byte(`
[[inputs.mockup]]
secret = "@{mock:secret}"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
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 secret.Destroy()
require.EqualValues(t, "Ood Bnar", secret.TemporaryString())
err = plugin.Secret.Set([]byte("@{mock:another_secret}"))
require.ErrorContains(t, err, `linking new secrets failed: unlinked part "@{mock:another_secret}"`)
}
func (tsuite *SecretImplTestSuite) TestSecretInvalidWarn() {
t := tsuite.T()
// Intercept the log output
var buf bytes.Buffer
backup := log.Writer()
log.SetOutput(&buf)
defer log.SetOutput(backup)
cfg := []byte(`
[[inputs.mockup]]
secret = "server=a user=@{mock:secret-with-invalid-chars} pass=@{mock:secret_pass}"
`)
c := NewConfig()
require.NoError(t, c.LoadConfigData(cfg, EmptySourcePath))
require.Len(t, c.Inputs, 1)
require.Contains(t, buf.String(), `W! Secret "@{mock:secret-with-invalid-chars}" contains invalid character(s)`)
require.NotContains(t, buf.String(), "@{mock:secret_pass}")
}
func TestSecretImplUnprotected(t *testing.T) {
impl := &unprotectedSecretImpl{}
container := impl.Container([]byte("foobar"))
require.NotNil(t, container)
c, ok := container.(*unprotectedSecretContainer)
require.True(t, ok)
require.Equal(t, "foobar", string(c.buf.content))
buf, err := container.Buffer()
require.NoError(t, err)
require.NotNil(t, buf)
require.Equal(t, []byte("foobar"), buf.Bytes())
require.Equal(t, "foobar", buf.TemporaryString())
require.Equal(t, "foobar", buf.String())
}
func TestSecretImplTestSuiteUnprotected(t *testing.T) {
suite.Run(t, &SecretImplTestSuite{protected: false})
}
func TestSecretImplTestSuiteProtected(t *testing.T) {
suite.Run(t, &SecretImplTestSuite{protected: true})
}
// 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 (*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(string) telegraf.SecretStore {
return &MockupSecretStore{}
})
}