Repository: hashicorp/nomad
File: client/allocrunner/taskrunner/secrets/plugin_provider.go (Go)

Code before:
	// pluginName refers to the provider parameter of the secret block
	// and is here mainly for debugging purposes
	pluginName string

	// secretName is the secret block name executing the plugin
	secretName string

	// path is the secret location used in Fetch
	path string
}

type Response struct {
	Result map[string]string `json:"result"`
	Error  *string           `json:"error,omitempty"`
}

func NewExternalPluginProvider(plugin commonplugins.SecretsPlugin, pluginName, secretName, path string) *ExternalPluginProvider {
	return &ExternalPluginProvider{
		plugin:     plugin,
		pluginName: pluginName,
		secretName: secretName,
		path:       path,
	}
}

func (p *ExternalPluginProvider) Fetch(ctx context.Context, env map[string]string) (map[string]string, error) {
	resp, err := p.plugin.Fetch(ctx, p.path, env)
	if err != nil {
		return nil, fmt.Errorf("failed executing plugin %q for secret %q: %w", p.pluginName, p.secretName, err)
	}
	if resp.Error != nil {
		return nil, fmt.Errorf("provider %q for secret %q response contained error: %q", p.pluginName, p.secretName, *resp.Error)
	}

	formatted := make(map[string]string, len(resp.Result))
	for k, v := range resp.Result {
		formatted[fmt.Sprintf("secret.%s.%s", p.secretName, k)] = v
	}

	return formatted, nil
}


Review comment (security):
What I was trying to get at here is that when we call:
`secrets.NewExternalPluginProvider(plug, s.Provider, s.Name, s.Path))` you could pass the env there and store it as a field on the `ExternalPluginProvider`. That way you don't have to return the `rawEnvMap`. Then you can call something like `plugin.InterpolateEnv(taskEnv.ReplaceEnv)`, similar to what you had before.

Code after:
	// pluginName refers to the provider parameter of the secret block
	// and is here mainly for debugging purposes
	pluginName string

	// secretName is the secret block name executing the plugin
	secretName string

	// path is the secret location used in Fetch
	path string

	// env is the set of environment variables passed into plugin
	env map[string]string
}

type Response struct {
	Result map[string]string `json:"result"`
	Error  *string           `json:"error,omitempty"`
}

func NewExternalPluginProvider(plugin commonplugins.SecretsPlugin, pluginName, secretName, path string, env map[string]string) *ExternalPluginProvider {
	return &ExternalPluginProvider{
		plugin:     plugin,
		pluginName: pluginName,
		secretName: secretName,
		path:       path,
		env:        env,
	}
}

func (p *ExternalPluginProvider) InterpolateEnv(interpolate func(string) string) {
	for key, value := range p.env {
		p.env[key] = interpolate(value)
	}
}

func (p *ExternalPluginProvider) Fetch(ctx context.Context) (map[string]string, error) {
	resp, err := p.plugin.Fetch(ctx, p.path, p.env)
	if err != nil {
		return nil, fmt.Errorf("failed executing plugin %q for secret %q: %w", p.pluginName, p.secretName, err)
	}
	if resp.Error != nil {
		return nil, fmt.Errorf("provider %q for secret %q response contained error: %q", p.pluginName, p.secretName, *resp.Error)
	}

	formatted := make(map[string]string, len(resp.Result))
	for k, v := range resp.Result {
		formatted[fmt.Sprintf("secret.%s.%s", p.secretName, k)] = v
	}

	return formatted, nil
}