Repository: getporter/porter
Pull request #2729 (2023-04-14 22:54:48)

Refactor secret source data structures
# What does this change
As I was working on advanced dependencies, I kept running into confusion about what some of these structs and fields represented. For example, a source mapping had both a Value field (representing the resolved value) and a Source.Value representing a hint to the secret strategy on how to resolve the value of parameter or credential.

I have renamed the data structures and fields a bit to better align with how they are used.

The renames happened in [pkg/secrets/stragegy.go](https://github.com/getporter/porter/pull/2729/files#diff-b6e26dc07034eb888f5799265f61d9083202c4de42804ec0731f127b32d4db99), the rest of the file just propagate the name changes.

# What issue does it fix
None

# Notes for the reviewer
I can make this a smaller PR by just renaming the top level Value field to ResolvedValue, but I think the other renames may be helpful as well for anyone maintaining the code. Within the same data structure we were using Value to mean 3 different things... 

Let me know what you think, we don't have to do any of this unless it makes the code more clear!

# Checklist
- [ ] Did you write tests?
- [ ] Did you write documentation?
- [ ] Did you change porter.yaml or a storage document record? Update the corresponding schema file.
- [ ] If this is your first pull request, please add your name to the bottom of our [Contributors][contributors] list. Thank you for making Porter better! 🙇‍♀️

# Reviewer Checklist
* Comment with /azp run test-porter-release if a magefile or build script was modified
* Comment with /azp run porter-integration if it's a non-trivial PR

[contributors]: https://getporter.org/src/CONTRIBUTORS.md


Patch:
diff --git a/pkg/generator/credentials.go b/pkg/generator/credentials.go
index b1d5244c..e2d22c12 100644
--- a/pkg/generator/credentials.go
+++ b/pkg/generator/credentials.go
@@ -39,7 +39,7 @@ func GenerateCredentials(opts GenerateCredentialsOptions) (storage.CredentialSet
 
 func genCredentialSet(namespace string, name string, creds map[string]bundle.Credential, fn generator) (storage.CredentialSet, error) {
 	cs := storage.NewCredentialSet(namespace, name)
-	cs.Credentials = []secrets.Strategy{}
+	cs.Credentials = []secrets.SourceMap{}
 
 	if strings.ContainsAny(name, "./\\") {
 		return cs, fmt.Errorf("credentialset name '%s' cannot contain the following characters: './\\'", name)
diff --git a/pkg/generator/generator.go b/pkg/generator/generator.go
index 1e86c76b..9d2484f3 100644
--- a/pkg/generator/generator.go
+++ b/pkg/generator/generator.go
@@ -33,18 +33,18 @@ const (
 	questionCommand = "shell command"
 )
 
-type generator func(name string, surveyType SurveyType) (secrets.Strategy, error)
+type generator func(name string, surveyType SurveyType) (secrets.SourceMap, error)
 
-func genEmptySet(name string, surveyType SurveyType) (secrets.Strategy, error) {
-	return secrets.Strategy{
+func genEmptySet(name string, surveyType SurveyType) (secrets.SourceMap, error) {
+	return secrets.SourceMap{
 		Name:   name,
-		Source: secrets.Source{Value: "TODO"},
+		Source: secrets.Source{Hint: "TODO"},
 	}, nil
 }
 
-func genSurvey(name string, surveyType SurveyType) (secrets.Strategy, error) {
+func genSurvey(name string, surveyType SurveyType) (secrets.SourceMap, error) {
 	if surveyType != surveyCredentials && surveyType != surveyParameters {
-		return secrets.Strategy{}, fmt.Errorf("unsupported survey type: %s", surveyType)
+		return secrets.SourceMap{}, fmt.Errorf("unsupported survey type: %s", surveyType)
 	}
 
 	// extra space-suffix to align question and answer. Unfortunately misaligns help text
@@ -57,7 +57,7 @@ func genSurvey(name string, surveyType SurveyType) (secrets.Strategy, error) {
 	// extra space-suffix to align question and answer. Unfortunately misaligns help text
 	sourceValuePromptTemplate := "Enter the %s that will be used to set %s %q\n "
 
-	c := secrets.Strategy{Name: name}
+	c := secrets.SourceMap{Name: name}
 
 	source := ""
 	if err := survey.AskOne(sourceTypePrompt, &source, nil); err != nil {
@@ -89,20 +89,20 @@ func genSurvey(name string, surveyType SurveyType) (secrets.Strategy, error) {
 
 	switch source {
 	case questionSecret:
-		c.Source.Key = secrets.SourceSecret
-		c.Source.Value = value
+		c.Source.Strategy = secrets.SourceSecret
+		c.Source.Hint = value
 	case questionValue:
-		c.Source.Key = host.SourceValue
-		c.Source.Value = value
+		c.Source.Strategy = host.SourceValue
+		c.Source.Hint = value
 	case questionEnvVar:
-		c.Source.Key = host.SourceEnv
-		c.Source.Value = value
+		c.Source.Strategy = host.SourceEnv
+		c.Source.Hint = value
 	case questionPath:
-		c.Source.Key = host.SourcePath
-		c.Source.Value = value
+		c.Source.Strategy = host.SourcePath
+		c.Source.Hint = value
 	case questionCommand:
-		c.Source.Key = host.SourceCommand
-		c.Source.Value = value
+		c.Source.Strategy = host.SourceCommand
+		c.Source.Hint = value
 	}
 	return c, nil
 }
diff --git a/pkg/porter/credentials.go b/pkg/porter/credentials.go
index de05e8f1..78b64dca 100644
--- a/pkg/porter/credentials.go
+++ b/pkg/porter/credentials.go
@@ -273,7 +273,7 @@ func (p *Porter) ShowCredential(ctx context.Context, opts CredentialShowOptions)
 
 		// Iterate through all CredentialStrategies and add to rows
 		for _, cs := range credSet.Credentials {
-			rows = append(rows, []string{cs.Name, cs.Source.Value, cs.Source.Key})
+			rows = append(rows, []string{cs.Name, cs.Source.Hint, cs.Source.Strategy})
 		}
 
 		// Build and configure our tablewriter
diff --git a/pkg/porter/helpers.go b/pkg/porter/helpers.go
index 23463d8a..92ebdb34 100644
--- a/pkg/porter/helpers.go
+++ b/pkg/porter/helpers.go
@@ -239,7 +239,7 @@ func (p *TestPorter) CompareGoldenFile(goldenFile string, got string) {
 
 // CreateInstallation saves an installation record into claim store and store
 // sensitive parameters into secret store.
-func (p *TestPorter) SanitizeParameters(raw []secrets.Strategy, recordID string, bun cnab.ExtendedBundle) []secrets.Strategy {
+func (p *TestPorter) SanitizeParameters(raw []secrets.SourceMap, recordID string, bun cnab.ExtendedBundle) []secrets.SourceMap {
 	strategies, err := p.Sanitizer.CleanParameters(context.Background(), raw, bun, recordID)
 	require.NoError(p.T(), err)
 
diff --git a/pkg/porter/list.go b/pkg/porter/list.go
index 8672927c..a88109f7 100644
--- a/pkg/porter/list.go
+++ b/pkg/porter/list.go
@@ -178,7 +178,7 @@ func (d DisplayInstallation) ConvertToInstallation() (storage.Installation, erro
 
 // ConvertParamToSet converts a Parameters into a internal ParameterSet.
 func (d DisplayInstallation) ConvertParamToSet() (storage.ParameterSet, error) {
-	strategies := make([]secrets.Strategy, 0, len(d.Parameters))
+	strategies := make([]secrets.SourceMap, 0, len(d.Parameters))
 	for name, value := range d.Parameters {
 		stringVal, err := cnab.WriteParameterToString(name, value)
 		if err != nil {
diff --git a/pkg/porter/parameters.go b/pkg/porter/parameters.go
index 6edc7e11..8fcf5c29 100644
--- a/pkg/porter/parameters.go
+++ b/pkg/porter/parameters.go
@@ -272,7 +272,7 @@ func (p *Porter) ShowParameter(ctx context.Context, opts ParameterShowOptions) e
 
 		// Iterate through all ParameterStrategies and add to rows
 		for _, pset := range paramSet.Parameters {
-			rows = append(rows, []string{pset.Name, pset.Source.Value, pset.Source.Key})
+			rows = append(rows, []string{pset.Name, pset.Source.Hint, pset.Source.Strategy})
 		}
 
 		// Build and configure our tablewriter
@@ -391,7 +391,7 @@ func (p *Porter) loadParameterSets(ctx context.Context, bun cnab.ExtendedBundle,
 				for i, param := range pset.Parameters {
 					if param.Name == paramName {
 						// Pass through value (filepath) directly to resolvedParameters
-						resolvedParameters[param.Name] = param.Source.Value
+						resolvedParameters[param.Name] = param.Source.Hint
 						// Eliminate this param from pset to prevent its resolution by
 						// the cnab-go library, which doesn't support this parameter type
 						pset.Parameters[i] = pset.Parameters[len(pset.Parameters)-1]
diff --git a/pkg/secrets/strategy.go b/pkg/secrets/strategy.go
index 9b85e096..498328a4 100644
--- a/pkg/secrets/strategy.go
+++ b/pkg/secrets/strategy.go
@@ -43,46 +43,51 @@ func (s Set) ToCNAB() valuesource.Set {
 	return valuesource.Set(s)
 }
 
-// Strategy represents a strategy for determining the value of a parameter or credential
-type Strategy struct {
+// SourceMap maps from a parameter or credential name to a source strategy for resolving its value.
+type SourceMap struct {
 	// Name is the name of the parameter or credential.
 	Name string `json:"name" yaml:"name"`
-	// Source is the location of the value.
-	// During resolution, the source will be loaded, and the result temporarily placed
-	// into Value.
+
+	// Source defines a strategy for resolving a value from the specified source.
 	Source Source `json:"source,omitempty" yaml:"source,omitempty"`
-	// Value holds the parameter or credential value.
-	// When a parameter or credential is loaded, it is loaded into this field. In all
+
+	// ResolvedValue holds the resolved parameter or credential value.
+	// When a parameter or credential is resolved, it is loaded into this field. In all
 	// other cases, it is empty. This field is omitted during serialization.
-	Value string `json:"-" yaml:"-"`
+	ResolvedValue string `json:"-" yaml:"-"`
 }
 
-// Source represents a strategy for loading a value from local host.
+// Source specifies how to resolve a parameter or credential from an external
+// source.
 type Source struct {
-	Key   string
-	Value string
+	// Strategy to resolve the source value, e.g. "secret" or "env".
+	Strategy string
+
+	// Hint to the strategy handler on how to resolve the value.
+	// For example the name of the secret in a secret store or name of an environment variable.
+	Hint string
 }
 
 func (s Source) MarshalRaw() interface{} {
-	if s.Key == "" {
+	if s.Strategy == "" {
 		return nil
 	}
-	return map[string]interface{}{s.Key: s.Value}
+	return map[string]interface{}{s.Strategy: s.Hint}
 }
 
 func (s *Source) UnmarshalRaw(raw map[string]interface{}) error {
 	switch len(raw) {
 	case 0:
-		s.Key = ""
-		s.Value = ""
+		s.Strategy = ""
+		s.Hint = ""
 		return nil
 	case 1:
 		for k, v := range raw {
-			s.Key = k
+			s.Strategy = k
 			if value, ok := v.(string); ok {
-				s.Value = value
+				s.Hint = value
 			} else {
-				s.Value = fmt.Sprintf("%v", s.Value)
+				s.Hint = fmt.Sprintf("%v", s.Hint)
 			}
 		}
 		return nil
@@ -125,7 +130,7 @@ func (s Source) MarshalYAML() (interface{}, error) {
 	return s.MarshalRaw(), nil
 }
 
-type StrategyList []Strategy
+type StrategyList []SourceMap
 
 func (l StrategyList) Less(i, j int) bool {
 	return l[i].Name < l[j].Name
diff --git a/pkg/storage/credential_store.go b/pkg/storage/credential_store.go
index 6b9577a1..86e76535 100644
--- a/pkg/storage/credential_store.go
+++ b/pkg/storage/credential_store.go
@@ -62,9 +62,9 @@ func (s CredentialStore) ResolveAll(ctx context.Context, creds CredentialSet) (s
 	var resolveErrors error
 
 	for _, cred := range creds.Credentials {
-		value, err := s.Secrets.Resolve(ctx, cred.Source.Key, cred.Source.Value)
+		value, err := s.Secrets.Resolve(ctx, cred.Source.Strategy, cred.Source.Hint)
 		if err != nil {
-			resolveErrors = multierror.Append(resolveErrors, fmt.Errorf("unable to resolve credential %s.%s from %s %s: %w", creds.Name, cred.Name, cred.Source.Key, cred.Source.Value, err))
+			resolveErrors = multierror.Append(resolveErrors, fmt.Errorf("unable to resolve credential %s.%s from %s %s: %w", creds.Name, cred.Name, cred.Source.Strategy, cred.Source.Hint, err))
 		}
 
 		resolvedCreds[cred.Name] = value
@@ -80,7 +80,7 @@ func (s CredentialStore) Validate(ctx context.Context, creds CredentialSet) erro
 	for _, cs := range creds.Credentials {
 		valid := false
 		for _, validSource := range validSources {
-			if cs.Source.Key == validSource {
+			if cs.Source.Strategy == validSource {
 				valid = true
 				break
 			}
@@ -88,7 +88,7 @@ func (s CredentialStore) Validate(ctx context.Context, creds CredentialSet) erro
 		if !valid {
 			errors = multierror.Append(errors, fmt.Errorf(
 				"%s is not a valid source. Valid sources are: %s",
-				cs.Source.Key,
+				cs.Source.Strategy,
 				strings.Join(validSources, ", "),
 			))
 		}
diff --git a/pkg/storage/credentialset.go b/pkg/storage/credentialset.go
index 6539849d..651fd525 100644
--- a/pkg/storage/credentialset.go
+++ b/pkg/storage/credentialset.go
@@ -63,7 +63,7 @@ type CredentialSetStatus struct {
 }
 
 // NewCredentialSet creates a new CredentialSet with the required fields initialized.
-func NewCredentialSet(namespace string, name string, creds ...secrets.Strategy) CredentialSet {
+func NewCredentialSet(namespace string, name string, creds ...secrets.SourceMap) CredentialSet {
 	now := time.Now()
 	cs := CredentialSet{
 		CredentialSetSpec: CredentialSetSpec{
diff --git a/pkg/storage/installation.go b/pkg/storage/installation.go
index 134262e1..5d327f39 100644
--- a/pkg/storage/installation.go
+++ b/pkg/storage/installation.go
@@ -223,7 +223,7 @@ func (i *Installation) SetLabel(key string, value string) {
 
 // NewInternalParameterSet creates a new ParameterSet that's used to store
 // parameter overrides with the required fields initialized.
-func (i Installation) NewInternalParameterSet(params ...secrets.Strategy) ParameterSet {
+func (i Installation) NewInternalParameterSet(params ...secrets.SourceMap) ParameterSet {
 	return NewInternalParameterSet(i.Namespace, i.ID, params...)
 }
 
diff --git a/pkg/storage/migrations/migration.go b/pkg/storage/migrations/migration.go
index fd5e0a88..adb82aff 100644
--- a/pkg/storage/migrations/migration.go
+++ b/pkg/storage/migrations/migration.go
@@ -310,7 +310,7 @@ func convertClaimToRun(inst storage.Installation, data []byte) (storage.Run, err
 		return storage.Run{}, fmt.Errorf("error parsing claim record: %w", err)
 	}
 
-	params := make([]secrets.Strategy, 0, len(src.Parameters))
+	params := make([]secrets.SourceMap, 0, len(src.Parameters))
 	for k, v := range src.Parameters {
 		stringVal, err := cnab.WriteParameterToString(k, v)
 		if err != nil {
@@ -505,7 +505,7 @@ func convertCredentialSet(namespace string, data []byte) (storage.CredentialSet,
 			SchemaVersion: storage.DefaultCredentialSetSchemaVersion,
 			Namespace:     namespace,
 			Name:          src.Name,
-			Credentials:   make([]secrets.Strategy, len(src.Credentials)),
+			Credentials:   make([]secrets.SourceMap, len(src.Credentials)),
 		},
 		Status: storage.CredentialSetStatus{
 			Created:  src.Created,
@@ -514,11 +514,11 @@ func convertCredentialSet(namespace string, data []byte) (storage.CredentialSet,
 	}
 
 	for i, cred := range src.Credentials {
-		dest.CredentialSetSpec.Credentials[i] = secrets.Strategy{
+		dest.CredentialSetSpec.Credentials[i] = secrets.SourceMap{
 			Name: cred.Name,
 			Source: secrets.Source{
-				Key:   cred.Source.Key,
-				Value: cred.Source.Value,
+				Strategy: cred.Source.Key,
+				Hint:     cred.Source.Value,
 			},
 		}
 	}
@@ -583,7 +583,7 @@ func convertParameterSet(namespace string, data []byte) (storage.ParameterSet, e
 			SchemaVersion: storage.DefaultParameterSetSchemaVersion,
 			Namespace:     namespace,
 			Name:          src.Name,
-			Parameters:    make([]secrets.Strategy, len(src.Parameters)),
+			Parameters:    make([]secrets.SourceMap, len(src.Parameters)),
 		},
 		Status: storage.ParameterSetStatus{
 			Created:  src.Created,
@@ -592,11 +592,11 @@ func convertParameterSet(namespace string, data []byte) (storage.ParameterSet, e
 	}
 
 	for i, cred := range src.Parameters {
-		dest.Parameters[i] = secrets.Strategy{
+		dest.Parameters[i] = secrets.SourceMap{
 			Name: cred.Name,
 			Source: secrets.Source{
-				Key:   cred.Source.Key,
-				Value: cred.Source.Value,
+				Strategy: cred.Source.Key,
+				Hint:     cred.Source.Value,
 			},
 		}
 	}
diff --git a/pkg/storage/parameter_store.go b/pkg/storage/parameter_store.go
index 96bcf9ee..cb72e312 100644
--- a/pkg/storage/parameter_store.go
+++ b/pkg/storage/parameter_store.go
@@ -56,9 +56,9 @@ func (s ParameterStore) ResolveAll(ctx context.Context, params ParameterSet) (se
 	var resolveErrors error
 
 	for _, param := range params.Parameters {
-		value, err := s.Secrets.Resolve(ctx, param.Source.Key, param.Source.Value)
+		value, err := s.Secrets.Resolve(ctx, param.Source.Strategy, param.Source.Hint)
 		if err != nil {
-			resolveErrors = multierror.Append(resolveErrors, fmt.Errorf("unable to resolve parameter %s.%s from %s %s: %w", params.Name, param.Name, param.Source.Key, param.Source.Value, err))
+			resolveErrors = multierror.Append(resolveErrors, fmt.Errorf("unable to resolve parameter %s.%s from %s %s: %w", params.Name, param.Name, param.Source.Strategy, param.Source.Hint, err))
 		}
 
 		resolvedParams[param.Name] = value
@@ -74,7 +74,7 @@ func (s ParameterStore) Validate(ctx context.Context, params ParameterSet) error
 	for _, cs := range params.Parameters {
 		valid := false
 		for _, validSource := range validSources {
-			if cs.Source.Key == validSource {
+			if cs.Source.Strategy == validSource {
 				valid = true
 				break
 			}
@@ -82,7 +82,7 @@ func (s ParameterStore) Validate(ctx context.Context, params ParameterSet) error
 		if !valid {
 			errors = multierror.Append(errors, fmt.Errorf(
 				"%s is not a valid source. Valid sources are: %s",
-				cs.Source.Key,
+				cs.Source.Strategy,
 				strings.Join(validSources, ", "),
 			))
 		}
diff --git a/pkg/storage/parameters.go b/pkg/storage/parameters.go
index e3cbf72b..dc74d946 100644
--- a/pkg/storage/parameters.go
+++ b/pkg/storage/parameters.go
@@ -34,10 +34,10 @@ func ParseVariableAssignments(params []string) (map[string]string, error) {
 }
 
 // ValueStrategy is the strategy used to store non-sensitive parameters
-func ValueStrategy(name string, value string) secrets.Strategy {
-	return secrets.Strategy{
-		Name:   name,
-		Source: secrets.Source{Key: host.SourceValue, Value: value},
-		Value:  value,
+func ValueStrategy(name string, value string) secrets.SourceMap {
+	return secrets.SourceMap{
+		Name:          name,
+		Source:        secrets.Source{Strategy: host.SourceValue, Hint: value},
+		ResolvedValue: value,
 	}
 }
diff --git a/pkg/storage/parameterset.go b/pkg/storage/parameterset.go
index 6f03e563..66f104c8 100644
--- a/pkg/storage/parameterset.go
+++ b/pkg/storage/parameterset.go
@@ -57,7 +57,7 @@ type ParameterSetStatus struct {
 }
 
 // NewParameterSet creates a new ParameterSet with the required fields initialized.
-func NewParameterSet(namespace string, name string, params ...secrets.Strategy) ParameterSet {
+func NewParameterSet(namespace string, name string, params ...secrets.SourceMap) ParameterSet {
 	now := time.Now()
 	ps := ParameterSet{
 		ParameterSetSpec: ParameterSetSpec{
@@ -77,7 +77,7 @@ func NewParameterSet(namespace string, name string, params ...secrets.Strategy)
 }
 
 // NewInternalParameterSet creates a new internal ParameterSet with the required fields initialized.
-func NewInternalParameterSet(namespace string, name string, params ...secrets.Strategy) ParameterSet {
+func NewInternalParameterSet(namespace string, name string, params ...secrets.SourceMap) ParameterSet {
 	return NewParameterSet(namespace, INTERNAL_PARAMETERER_SET+"-"+name, params...)
 }
 
diff --git a/pkg/storage/run.go b/pkg/storage/run.go
index 542359d9..c4aaf13a 100644
--- a/pkg/storage/run.go
+++ b/pkg/storage/run.go
@@ -173,9 +173,9 @@ func (r Run) TypedParameterValues() map[string]interface{} {
 	value := make(map[string]interface{})
 
 	for _, param := range r.Parameters.Parameters {
-		v, err := bun.ConvertParameterValue(param.Name, param.Value)
+		v, err := bun.ConvertParameterValue(param.Name, param.ResolvedValue)
 		if err != nil {
-			value[param.Name] = param.Value
+			value[param.Name] = param.ResolvedValue
 			continue
 		}
 		def, ok := bun.Definitions[param.Name]
diff --git a/pkg/storage/sanitizer.go b/pkg/storage/sanitizer.go
index c58e60a6..45e9c0d5 100644
--- a/pkg/storage/sanitizer.go
+++ b/pkg/storage/sanitizer.go
@@ -29,8 +29,8 @@ func NewSanitizer(parameterstore ParameterSetProvider, secretstore secrets.Store
 // transform the raw value into secret strategies.
 // The id argument is used to associate the reference key with the corresponding
 // run or installation record in porter's database.
-func (s *Sanitizer) CleanRawParameters(ctx context.Context, params map[string]interface{}, bun cnab.ExtendedBundle, id string) ([]secrets.Strategy, error) {
-	strategies := make([]secrets.Strategy, 0, len(params))
+func (s *Sanitizer) CleanRawParameters(ctx context.Context, params map[string]interface{}, bun cnab.ExtendedBundle, id string) ([]secrets.SourceMap, error) {
+	strategies := make([]secrets.SourceMap, 0, len(params))
 	for name, value := range params {
 		stringVal, err := bun.WriteParameterToString(name, value)
 		if err != nil {
@@ -53,13 +53,13 @@ func (s *Sanitizer) CleanRawParameters(ctx context.Context, params map[string]in
 // Sanitized value after saving sensitive data to secrets store.
 // The id argument is used to associate the reference key with the corresponding
 // run or installation record in porter's database.
-func (s *Sanitizer) CleanParameters(ctx context.Context, dirtyParams []secrets.Strategy, bun cnab.ExtendedBundle, id string) ([]secrets.Strategy, error) {
-	cleanedParams := make([]secrets.Strategy, 0, len(dirtyParams))
+func (s *Sanitizer) CleanParameters(ctx context.Context, dirtyParams []secrets.SourceMap, bun cnab.ExtendedBundle, id string) ([]secrets.SourceMap, error) {
+	cleanedParams := make([]secrets.SourceMap, 0, len(dirtyParams))
 	for _, param := range dirtyParams {
 		// Store sensitive hard-coded values in a secret store
-		if param.Source.Key == host.SourceValue && bun.IsSensitiveParameter(param.Name) {
+		if param.Source.Strategy == host.SourceValue && bun.IsSensitiveParameter(param.Name) {
 			cleaned := sanitizedParam(param, id)
-			err := s.secrets.Create(ctx, cleaned.Source.Key, cleaned.Source.Value, cleaned.Value)
+			err := s.secrets.Create(ctx, cleaned.Source.Strategy, cleaned.Source.Hint, cleaned.ResolvedValue)
 			if err != nil {
 				return nil, fmt.Errorf("failed to save sensitive param to secrete store: %w", err)
 			}
@@ -93,9 +93,9 @@ func LinkSensitiveParametersToSecrets(pset ParameterSet, bun cnab.ExtendedBundle
 	return pset
 }
 
-func sanitizedParam(param secrets.Strategy, id string) secrets.Strategy {
-	param.Source.Key = secrets.SourceSecret
-	param.Source.Value = id + "-" + param.Name
+func sanitizedParam(param secrets.SourceMap, id string) secrets.SourceMap {
+	param.Source.Strategy = secrets.SourceSecret
+	param.Source.Hint = id + "-" + param.Name
 	return param
 }
 


Test patch:
diff --git a/pkg/cnab/provider/credentials_test.go b/pkg/cnab/provider/credentials_test.go
index 0ebf12cd..a4f90e2e 100644
--- a/pkg/cnab/provider/credentials_test.go
+++ b/pkg/cnab/provider/credentials_test.go
@@ -23,11 +23,11 @@ func TestRuntime_loadCredentials(t *testing.T) {
 
 	r.TestConfig.TestContext.AddTestFile("testdata/db-creds.json", "/db-creds.json")
 
-	cs1 := storage.NewCredentialSet("", "mycreds", secrets.Strategy{
+	cs1 := storage.NewCredentialSet("", "mycreds", secrets.SourceMap{
 		Name: "password",
 		Source: secrets.Source{
-			Key:   secrets.SourceSecret,
-			Value: "password",
+			Strategy: secrets.SourceSecret,
+			Hint:     "password",
 		},
 	})
 
@@ -135,11 +135,11 @@ func TestRuntime_loadCredentials_WithApplyTo(t *testing.T) {
 
 		r.TestCredentials.AddSecret("password", "mypassword")
 
-		cs1 := storage.NewCredentialSet("", "mycreds", secrets.Strategy{
+		cs1 := storage.NewCredentialSet("", "mycreds", secrets.SourceMap{
 			Name: "password",
 			Source: secrets.Source{
-				Key:   secrets.SourceSecret,
-				Value: "password",
+				Strategy: secrets.SourceSecret,
+				Hint:     "password",
 			},
 		})
 
diff --git a/pkg/generator/generator_test.go b/pkg/generator/generator_test.go
index 42b5ed70..79191b2a 100644
--- a/pkg/generator/generator_test.go
+++ b/pkg/generator/generator_test.go
@@ -8,9 +8,9 @@ import (
 )
 
 func Test_genEmptySet(t *testing.T) {
-	expected := secrets.Strategy{
+	expected := secrets.SourceMap{
 		Name:   "emptyset",
-		Source: secrets.Source{Value: "TODO"},
+		Source: secrets.Source{Hint: "TODO"},
 	}
 
 	got, err := genEmptySet("emptyset", surveyParameters)
@@ -21,5 +21,5 @@ func Test_genEmptySet(t *testing.T) {
 func Test_genSurvey_unsupported(t *testing.T) {
 	got, err := genSurvey("myturtleset", SurveyType("turtles"))
 	require.EqualError(t, err, "unsupported survey type: turtles")
-	require.Equal(t, secrets.Strategy{}, got)
+	require.Equal(t, secrets.SourceMap{}, got)
 }
diff --git a/pkg/porter/credentials_test.go b/pkg/porter/credentials_test.go
index 5fa83a1a..f4c4942a 100644
--- a/pkg/porter/credentials_test.go
+++ b/pkg/porter/credentials_test.go
@@ -566,7 +566,7 @@ func TestPorter_CredentialsApply(t *testing.T) {
 		assert.Equal(t, "kool-kreds", cs.Name, "unexpected credential set name")
 		require.Len(t, cs.Credentials, 4, "expected 4 credentials in the set")
 		assert.Equal(t, "kool-config", cs.Credentials[0].Name, "expected the kool-config credential mapping defined")
-		assert.Equal(t, "path", cs.Credentials[0].Source.Key, "unexpected credential source")
-		assert.Equal(t, "/path/to/kool-config", cs.Credentials[0].Source.Value, "unexpected credential mapping value")
+		assert.Equal(t, "path", cs.Credentials[0].Source.Strategy, "unexpected credential source")
+		assert.Equal(t, "/path/to/kool-config", cs.Credentials[0].Source.Hint, "unexpected credential mapping value")
 	})
 }
diff --git a/pkg/porter/install_test.go b/pkg/porter/install_test.go
index 912d936a..d938c204 100644
--- a/pkg/porter/install_test.go
+++ b/pkg/porter/install_test.go
@@ -78,8 +78,8 @@ func TestPorter_ApplyParametersToInstallation(t *testing.T) {
 		p.TestParameters.InsertParameterSet(ctx, storage.ParameterSet{
 			ParameterSetSpec: storage.ParameterSetSpec{
 				Name: "oldps1",
-				Parameters: []secrets.Strategy{
-					{Name: "logLevel", Source: secrets.Source{Key: "value", Value: "2"}},
+				Parameters: []secrets.SourceMap{
+					{Name: "logLevel", Source: secrets.Source{Strategy: "value", Hint: "2"}},
 				},
 			},
 		})
@@ -87,8 +87,8 @@ func TestPorter_ApplyParametersToInstallation(t *testing.T) {
 		p.TestParameters.InsertParameterSet(ctx, storage.ParameterSet{
 			ParameterSetSpec: storage.ParameterSetSpec{
 				Name: "newps1",
-				Parameters: []secrets.Strategy{
-					{Name: "logLevel", Source: secrets.Source{Key: "value", Value: "11"}},
+				Parameters: []secrets.SourceMap{
+					{Name: "logLevel", Source: secrets.Source{Strategy: "value", Hint: "11"}},
 				},
 			},
 		})
diff --git a/pkg/porter/lifecycle_test.go b/pkg/porter/lifecycle_test.go
index 0380d149..8f0f35d7 100644
--- a/pkg/porter/lifecycle_test.go
+++ b/pkg/porter/lifecycle_test.go
@@ -451,12 +451,12 @@ func TestPorter_applyActionOptionsToInstallation_sanitizesParameters(t *testing.
 	// there should be no sensitive value on installation record
 	for _, param := range i.Parameters.Parameters {
 		if param.Name == sensitiveParamName {
-			require.Equal(t, param.Source.Key, secrets.SourceSecret)
-			require.NotEqual(t, param.Source.Value, sensitiveParamValue)
+			require.Equal(t, param.Source.Strategy, secrets.SourceSecret)
+			require.NotEqual(t, param.Source.Hint, sensitiveParamValue)
 			continue
 		}
-		require.Equal(t, param.Source.Key, host.SourceValue)
-		require.Equal(t, param.Source.Value, nonsensitiveParamValue)
+		require.Equal(t, param.Source.Strategy, host.SourceValue)
+		require.Equal(t, param.Source.Hint, nonsensitiveParamValue)
 	}
 
 	// When no parameter override specified, installation record should be updated
@@ -472,9 +472,9 @@ func TestPorter_applyActionOptionsToInstallation_sanitizesParameters(t *testing.
 	// Check that when no parameter overrides are specified, we use the originally specified parameters from the previous run
 	require.Len(t, i.Parameters.Parameters, 2)
 	require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name)
-	require.Equal(t, "1", i.Parameters.Parameters[0].Source.Value)
+	require.Equal(t, "1", i.Parameters.Parameters[0].Source.Hint)
 	require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name)
-	require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Key)
+	require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Strategy)
 }
 
 // When the installation has been used before with a parameter value
@@ -518,9 +518,9 @@ func TestPorter_applyActionOptionsToInstallation_PreservesExistingParams(t *test
 	// Check that overrides are applied on top of existing parameters
 	require.Len(t, i.Parameters.Parameters, 2)
 	require.Equal(t, "my-first-param", i.Parameters.Parameters[0].Name)
-	require.Equal(t, "value", i.Parameters.Parameters[0].Source.Key, "my-first-param isn't sensitive and can be stored in a hard-coded value")
+	require.Equal(t, "value", i.Parameters.Parameters[0].Source.Strategy, "my-first-param isn't sensitive and can be stored in a hard-coded value")
 	require.Equal(t, "my-second-param", i.Parameters.Parameters[1].Name)
-	require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Key, "my-second-param should be stored on the installation using a secret since it's sensitive")
+	require.Equal(t, "secret", i.Parameters.Parameters[1].Source.Strategy, "my-second-param should be stored on the installation using a secret since it's sensitive")
 
 	// Check the values stored are correct
 	params, err := p.Parameters.ResolveAll(ctx, i.Parameters)
diff --git a/pkg/porter/list_test.go b/pkg/porter/list_test.go
index e43402b0..87fbe385 100644
--- a/pkg/porter/list_test.go
+++ b/pkg/porter/list_test.go
@@ -60,8 +60,8 @@ func TestPorter_ListInstallations(t *testing.T) {
 	defer p.Close()
 
 	i1 := storage.NewInstallation("", "shared-mysql")
-	i1.Parameters.Parameters = []secrets.Strategy{ // Define a parameter that is stored in a secret, list should not retrieve it
-		{Name: "password", Source: secrets.Source{Key: "secret", Value: "mypassword"}},
+	i1.Parameters.Parameters = []secrets.SourceMap{ // Define a parameter that is stored in a secret, list should not retrieve it
+		{Name: "password", Source: secrets.Source{Strategy: "secret", Hint: "mypassword"}},
 	}
 	i1.Status.RunID = "10" // Add a run but don't populate the data for it, list should not retrieve it
 
@@ -140,14 +140,14 @@ func TestDisplayInstallation_ConvertToInstallation(t *testing.T) {
 	require.Equal(t, i.Parameters.String(), convertedInstallation.Parameters.String(), "invalid parameters name")
 	require.Equal(t, len(i.Parameters.Parameters), len(convertedInstallation.Parameters.Parameters))
 
-	parametersMap := make(map[string]secrets.Strategy, len(i.Parameters.Parameters))
+	parametersMap := make(map[string]secrets.SourceMap, len(i.Parameters.Parameters))
 	for _, param := range i.Parameters.Parameters {
 		parametersMap[param.Name] = param
 	}
 
 	for _, param := range convertedInstallation.Parameters.Parameters {
 		expected := parametersMap[param.Name]
-		require.Equal(t, expected.Value, param.Value)
+		require.Equal(t, expected.ResolvedValue, param.ResolvedValue)
 		expectedSource, err := expected.Source.MarshalJSON()
 		require.NoError(t, err)
 		source, err := param.Source.MarshalJSON()
diff --git a/pkg/porter/parameters_test.go b/pkg/porter/parameters_test.go
index e67b84dd..2fe71329 100644
--- a/pkg/porter/parameters_test.go
+++ b/pkg/porter/parameters_test.go
@@ -860,7 +860,7 @@ func TestPorter_ParametersApply(t *testing.T) {
 		assert.Equal(t, "mypset", ps.Name, "unexpected parameter set name")
 		require.Len(t, ps.Parameters, 1, "expected 1 parameter in the set")
 		assert.Equal(t, "foo", ps.Parameters[0].Name, "expected the foo parameter mapping defined")
-		assert.Equal(t, "secret", ps.Parameters[0].Source.Key, "expected the foo parameter mapping to come from a secret")
-		assert.Equal(t, "foo_secret", ps.Parameters[0].Source.Value, "expected the foo parameter mapping to use foo_secret")
+		assert.Equal(t, "secret", ps.Parameters[0].Source.Strategy, "expected the foo parameter mapping to come from a secret")
+		assert.Equal(t, "foo_secret", ps.Parameters[0].Source.Hint, "expected the foo parameter mapping to use foo_secret")
 	})
 }
diff --git a/pkg/porter/reconcile_test.go b/pkg/porter/reconcile_test.go
index d7b7fcb5..42631502 100644
--- a/pkg/porter/reconcile_test.go
+++ b/pkg/porter/reconcile_test.go
@@ -62,7 +62,7 @@ func TestPorter_IsInstallationInSync(t *testing.T) {
 		myps := storage.ParameterSet{
 			ParameterSetSpec: storage.ParameterSetSpec{
 				Name: "myps",
-				Parameters: []secrets.Strategy{
+				Parameters: []secrets.SourceMap{
 					storage.ValueStrategy("my-second-param", "override"),
 				},
 			},
diff --git a/pkg/porter/show_test.go b/pkg/porter/show_test.go
index 383918ed..e6ce69c7 100644
--- a/pkg/porter/show_test.go
+++ b/pkg/porter/show_test.go
@@ -92,9 +92,9 @@ func TestPorter_ShowInstallationWithBundle(t *testing.T) {
 					"io.cnab/app":        "wordpress",
 					"io.cnab/appVersion": "v1.2.3",
 				}
-				params := []secrets.Strategy{
-					{Name: "logLevel", Source: secrets.Source{Value: "3"}, Value: "3"},
-					secrets.Strategy{Name: "secretString", Source: secrets.Source{Key: "secretString", Value: "foo"}, Value: "foo"},
+				params := []secrets.SourceMap{
+					{Name: "logLevel", Source: secrets.Source{Hint: "3"}, ResolvedValue: "3"},
+					secrets.SourceMap{Name: "secretString", Source: secrets.Source{Strategy: "secretString", Hint: "foo"}, ResolvedValue: "foo"},
 				}
 				i.Parameters = i.NewInternalParameterSet(params...)
 
@@ -114,7 +114,7 @@ func TestPorter_ShowInstallationWithBundle(t *testing.T) {
 				)
 
 				r.Parameters = i.NewInternalParameterSet(
-					[]secrets.Strategy{
+					[]secrets.SourceMap{
 						storage.ValueStrategy("logLevel", "3"),
 						storage.ValueStrategy("token", "top-secret"),
 						storage.ValueStrategy("secretString", "foo"),
@@ -205,9 +205,9 @@ func TestPorter_ShowInstallationWithoutRecordedRun(t *testing.T) {
 			"io.cnab/app":        "wordpress",
 			"io.cnab/appVersion": "v1.2.3",
 		}
-		params := []secrets.Strategy{
-			{Name: "logLevel", Source: secrets.Source{Value: "3"}, Value: "3"},
-			secrets.Strategy{Name: "secretString", Source: secrets.Source{Key: "secretString", Value: "foo"}, Value: "foo"},
+		params := []secrets.SourceMap{
+			{Name: "logLevel", Source: secrets.Source{Hint: "3"}, ResolvedValue: "3"},
+			secrets.SourceMap{Name: "secretString", Source: secrets.Source{Strategy: "secretString", Hint: "foo"}, ResolvedValue: "foo"},
 		}
 		i.Parameters = i.NewInternalParameterSet(params...)
 
diff --git a/pkg/storage/credential_store_test.go b/pkg/storage/credential_store_test.go
index 0336ad91..fd1a8dbf 100644
--- a/pkg/storage/credential_store_test.go
+++ b/pkg/storage/credential_store_test.go
@@ -10,10 +10,10 @@ import (
 )
 
 func TestCredentialStorage_CRUD(t *testing.T) {
-	cs := NewCredentialSet("dev", "sekrets", secrets.Strategy{
+	cs := NewCredentialSet("dev", "sekrets", secrets.SourceMap{
 		Name: "password", Source: secrets.Source{
-			Key:   "secret",
-			Value: "dbPassword"}})
+			Strategy: "secret",
+			Hint:     "dbPassword"}})
 
 	cp := NewTestCredentialProvider(t)
 	defer cp.Close()
@@ -34,10 +34,10 @@ func TestCredentialStorage_CRUD(t *testing.T) {
 	require.NoError(t, err)
 	require.Len(t, creds, 1, "expected 1 credential set defined in all namespaces")
 
-	cs.Credentials = append(cs.Credentials, secrets.Strategy{
+	cs.Credentials = append(cs.Credentials, secrets.SourceMap{
 		Name: "token", Source: secrets.Source{
-			Key:   "secret",
-			Value: "github-token",
+			Strategy: "secret",
+			Hint:     "github-token",
 		},
 	})
 	require.NoError(t, cp.UpdateCredentialSet(context.Background(), cs))
@@ -45,10 +45,10 @@ func TestCredentialStorage_CRUD(t *testing.T) {
 	require.NoError(t, err)
 	assert.Len(t, cs.Credentials, 2)
 
-	cs2 := NewCredentialSet("dev", "sekrets-2", secrets.Strategy{
+	cs2 := NewCredentialSet("dev", "sekrets-2", secrets.SourceMap{
 		Name: "password-2", Source: secrets.Source{
-			Key:   "secret-2",
-			Value: "dbPassword-2"}})
+			Strategy: "secret-2",
+			Hint:     "dbPassword-2"}})
 	require.NoError(t, cp.InsertCredentialSet(context.Background(), cs2))
 
 	creds, err = cp.ListCredentialSets(context.Background(), ListOptions{Namespace: "dev", Skip: 1})
@@ -74,16 +74,16 @@ func TestCredentialStorage_CRUD(t *testing.T) {
 func TestCredentialStorage_Validate_GoodSources(t *testing.T) {
 	s := CredentialStore{}
 	testCreds := NewCredentialSet("dev", "mycreds",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Source: secrets.Source{
-				Key:   "env",
-				Value: "SOME_ENV",
+				Strategy: "env",
+				Hint:     "SOME_ENV",
 			},
 		},
-		secrets.Strategy{
+		secrets.SourceMap{
 			Source: secrets.Source{
-				Key:   "value",
-				Value: "somevalue",
+				Strategy: "value",
+				Hint:     "somevalue",
 			},
 		})
 
@@ -94,16 +94,16 @@ func TestCredentialStorage_Validate_GoodSources(t *testing.T) {
 func TestCredentialStorage_Validate_BadSources(t *testing.T) {
 	s := CredentialStore{}
 	testCreds := NewCredentialSet("dev", "mycreds",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Source: secrets.Source{
-				Key:   "wrongthing",
-				Value: "SOME_ENV",
+				Strategy: "wrongthing",
+				Hint:     "SOME_ENV",
 			},
 		},
-		secrets.Strategy{
+		secrets.SourceMap{
 			Source: secrets.Source{
-				Key:   "anotherwrongthing",
-				Value: "somevalue",
+				Strategy: "anotherwrongthing",
+				Hint:     "somevalue",
 			},
 		},
 	)
diff --git a/pkg/storage/credentialset_test.go b/pkg/storage/credentialset_test.go
index 697b3007..76fa008b 100644
--- a/pkg/storage/credentialset_test.go
+++ b/pkg/storage/credentialset_test.go
@@ -17,11 +17,11 @@ import (
 )
 
 func TestNewCredentialSet(t *testing.T) {
-	cs := NewCredentialSet("dev", "mycreds", secrets.Strategy{
+	cs := NewCredentialSet("dev", "mycreds", secrets.SourceMap{
 		Name: "password",
 		Source: secrets.Source{
-			Key:   "env",
-			Value: "MY_PASSWORD",
+			Strategy: "env",
+			Hint:     "MY_PASSWORD",
 		},
 	})
 
@@ -152,12 +152,12 @@ func TestMarshal(t *testing.T) {
 			SchemaVersion: "schemaVersion",
 			Namespace:     "namespace",
 			Name:          "name",
-			Credentials: []secrets.Strategy{
+			Credentials: []secrets.SourceMap{
 				{
 					Name: "cred1",
 					Source: secrets.Source{
-						Key:   "secret",
-						Value: "mysecret",
+						Strategy: "secret",
+						Hint:     "mysecret",
 					},
 				},
 			},
diff --git a/pkg/storage/migrations/migration_test.go b/pkg/storage/migrations/migration_test.go
index 143ce65a..f8671c8d 100644
--- a/pkg/storage/migrations/migration_test.go
+++ b/pkg/storage/migrations/migration_test.go
@@ -49,8 +49,8 @@ func TestConvertClaimToRun(t *testing.T) {
 
 	param := run.Parameters.Parameters[0]
 	assert.Equal(t, param.Name, "porter-debug", "incorrect parameter name")
-	assert.Equal(t, param.Source.Key, "value", "incorrect parameter source key")
-	assert.Equal(t, param.Source.Value, "false", "incorrect parameter source value")
+	assert.Equal(t, param.Source.Strategy, "value", "incorrect parameter source key")
+	assert.Equal(t, param.Source.Hint, "false", "incorrect parameter source value")
 }
 
 func TestConvertResult(t *testing.T) {
@@ -191,8 +191,8 @@ func validateMigratedInstallations(ctx context.Context, t *testing.T, c *config.
 	assert.Len(t, lastRun.Parameters.Parameters, 1, "expected one parameter set on the run")
 	params := lastRun.Parameters.Parameters
 	assert.Equal(t, "porter-debug", params[0].Name, "expected the porter-debug parameter to be set on the run")
-	assert.Equal(t, "value", params[0].Source.Key, "expected the porter-debug parameter to be a hard-coded value")
-	assert.Equal(t, "true", params[0].Source.Value, "expected the porter-debug parameter to be false")
+	assert.Equal(t, "value", params[0].Source.Strategy, "expected the porter-debug parameter to be a hard-coded value")
+	assert.Equal(t, "true", params[0].Source.Hint, "expected the porter-debug parameter to be false")
 
 	runResults := results[lastRun.ID]
 	assert.Len(t, runResults, 2, "expected 2 results for the last run")
@@ -240,8 +240,8 @@ func validateMigratedCredentialSets(ctx context.Context, t *testing.T, destStore
 
 	cred := creds.Credentials[0]
 	assert.Equal(t, "github-token", cred.Name, "incorrect credential name")
-	assert.Equal(t, "env", cred.Source.Key, "incorrect credential source key")
-	assert.Equal(t, "GITHUB_TOKEN", cred.Source.Value, "incorrect credential source value")
+	assert.Equal(t, "env", cred.Source.Strategy, "incorrect credential source key")
+	assert.Equal(t, "GITHUB_TOKEN", cred.Source.Hint, "incorrect credential source value")
 }
 
 func validateMigratedParameterSets(ctx context.Context, t *testing.T, destStore storage.TestStore, opts storage.MigrateOptions) {
@@ -264,6 +264,6 @@ func validateMigratedParameterSets(ctx context.Context, t *testing.T, destStore
 
 	param := ps.Parameters[0]
 	assert.Equal(t, "name", param.Name, "incorrect parameter name")
-	assert.Equal(t, "env", param.Source.Key, "incorrect parameter source key")
-	assert.Equal(t, "USER", param.Source.Value, "incorrect parameter source value")
+	assert.Equal(t, "env", param.Source.Strategy, "incorrect parameter source key")
+	assert.Equal(t, "USER", param.Source.Hint, "incorrect parameter source value")
 }
diff --git a/pkg/storage/parameter_store_test.go b/pkg/storage/parameter_store_test.go
index d91f3908..7fa4be96 100644
--- a/pkg/storage/parameter_store_test.go
+++ b/pkg/storage/parameter_store_test.go
@@ -19,11 +19,11 @@ func TestParameterStore_CRUD(t *testing.T) {
 	require.Empty(t, params, "Find should return no entries")
 
 	myParamSet := NewParameterSet("dev", "myparams",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Name: "myparam",
 			Source: secrets.Source{
-				Key:   "value",
-				Value: "myparamvalue",
+				Strategy: "value",
+				Hint:     "myparamvalue",
 			},
 		})
 	myParamSet.Status.Created = time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
@@ -50,11 +50,11 @@ func TestParameterStore_CRUD(t *testing.T) {
 	require.Equal(t, myParamSet, pset, "Get should return the saved parameter set")
 
 	myParamSet2 := NewParameterSet("dev", "myparams2",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Name: "myparam2",
 			Source: secrets.Source{
-				Key:   "value2",
-				Value: "myparamvalue2",
+				Strategy: "value2",
+				Hint:     "myparamvalue2",
 			},
 		})
 	myParamSet2.Status.Created = time.Date(2020, 1, 1, 12, 0, 0, 0, time.UTC)
@@ -94,18 +94,18 @@ func TestParameterStorage_ResolveAll(t *testing.T) {
 	// The inmemory secret store currently only supports secret sources
 	// So all of these have this same source
 	testParameterSet := NewParameterSet("", "myparamset",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Name: "param1",
 			Source: secrets.Source{
-				Key:   "secret",
-				Value: "param1",
+				Strategy: "secret",
+				Hint:     "param1",
 			},
 		},
-		secrets.Strategy{
+		secrets.SourceMap{
 			Name: "param2",
 			Source: secrets.Source{
-				Key:   "secret",
-				Value: "param2",
+				Strategy: "secret",
+				Hint:     "param2",
 			},
 		})
 
@@ -149,34 +149,34 @@ func TestParameterStorage_Validate(t *testing.T) {
 		s := ParameterStore{}
 
 		testParameterSet := NewParameterSet("", "myparams",
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "env",
-					Value: "SOME_ENV",
+					Strategy: "env",
+					Hint:     "SOME_ENV",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "value",
-					Value: "somevalue",
+					Strategy: "value",
+					Hint:     "somevalue",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "path",
-					Value: "/some/path",
+					Strategy: "path",
+					Hint:     "/some/path",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "command",
-					Value: "some command",
+					Strategy: "command",
+					Hint:     "some command",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "secret",
-					Value: "secret",
+					Strategy: "secret",
+					Hint:     "secret",
 				},
 			})
 
@@ -187,16 +187,16 @@ func TestParameterStorage_Validate(t *testing.T) {
 	t.Run("invalid sources", func(t *testing.T) {
 		s := ParameterStore{}
 		testParameterSet := NewParameterSet("", "myparams",
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "wrongthing",
-					Value: "SOME_ENV",
+					Strategy: "wrongthing",
+					Hint:     "SOME_ENV",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Source: secrets.Source{
-					Key:   "anotherwrongthing",
-					Value: "somevalue",
+					Strategy: "anotherwrongthing",
+					Hint:     "somevalue",
 				},
 			})
 
diff --git a/pkg/storage/parameters_test.go b/pkg/storage/parameters_test.go
index 56de1796..2d6e0ee5 100644
--- a/pkg/storage/parameters_test.go
+++ b/pkg/storage/parameters_test.go
@@ -66,39 +66,39 @@ func TestTestParameterProvider_Load(t *testing.T) {
 
 	t.Run("successful load, successful unmarshal", func(t *testing.T) {
 		expected := NewParameterSet("", "mybun",
-			secrets.Strategy{
+			secrets.SourceMap{
 				Name: "param_env",
 				Source: secrets.Source{
-					Key:   "env",
-					Value: "PARAM_ENV",
+					Strategy: "env",
+					Hint:     "PARAM_ENV",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Name: "param_value",
 				Source: secrets.Source{
-					Key:   "value",
-					Value: "param_value",
+					Strategy: "value",
+					Hint:     "param_value",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Name: "param_command",
 				Source: secrets.Source{
-					Key:   "command",
-					Value: "echo hello world",
+					Strategy: "command",
+					Hint:     "echo hello world",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Name: "param_path",
 				Source: secrets.Source{
-					Key:   "path",
-					Value: "/path/to/param",
+					Strategy: "path",
+					Hint:     "/path/to/param",
 				},
 			},
-			secrets.Strategy{
+			secrets.SourceMap{
 				Name: "param_secret",
 				Source: secrets.Source{
-					Key:   "secret",
-					Value: "param_secret",
+					Strategy: "secret",
+					Hint:     "param_secret",
 				},
 			})
 		expected.SchemaVersion = "1.0.1" // It's an older code but it checks out
diff --git a/pkg/storage/parameterset_test.go b/pkg/storage/parameterset_test.go
index fdcb1e7c..fa776ced 100644
--- a/pkg/storage/parameterset_test.go
+++ b/pkg/storage/parameterset_test.go
@@ -15,11 +15,11 @@ import (
 
 func TestNewParameterSet(t *testing.T) {
 	ps := NewParameterSet("dev", "myparams",
-		secrets.Strategy{
+		secrets.SourceMap{
 			Name: "password",
 			Source: secrets.Source{
-				Key:   "env",
-				Value: "DB_PASSWORD",
+				Strategy: "env",
+				Hint:     "DB_PASSWORD",
 			},
 		})
 
diff --git a/pkg/storage/run_test.go b/pkg/storage/run_test.go
index 358bac48..063bad9c 100644
--- a/pkg/storage/run_test.go
+++ b/pkg/storage/run_test.go
@@ -172,11 +172,11 @@ func TestRun_TypedParameterValues(t *testing.T) {
 	run := NewRun("dev", "mybuns")
 	run.Bundle = bun
 	run.Parameters = NewParameterSet(run.Namespace, run.Bundle.Name)
-	params := []secrets.Strategy{
+	params := []secrets.SourceMap{
 		ValueStrategy("baz", "baz-test"),
 		ValueStrategy("name", "porter-test"),
 		ValueStrategy("porter-state", ""),
-		{Name: "foo", Source: secrets.Source{Key: secrets.SourceSecret, Value: "runID"}, Value: "5"},
+		{Name: "foo", Source: secrets.Source{Strategy: secrets.SourceSecret, Hint: "runID"}, ResolvedValue: "5"},
 	}
 
 	expected := map[string]interface{}{
diff --git a/pkg/storage/sanitizer_test.go b/pkg/storage/sanitizer_test.go
index 50147ed5..135c9b87 100644
--- a/pkg/storage/sanitizer_test.go
+++ b/pkg/storage/sanitizer_test.go
@@ -28,9 +28,9 @@ func TestSanitizer_Parameters(t *testing.T) {
 	recordID := "01FZVC5AVP8Z7A78CSCP1EJ604"
 	sensitiveParamName := "my-second-param"
 	sensitiveParamKey := recordID + "-" + sensitiveParamName
-	expected := []secrets.Strategy{
-		{Name: "my-first-param", Source: secrets.Source{Key: host.SourceValue, Value: "1"}, Value: "1"},
-		{Name: sensitiveParamName, Source: secrets.Source{Key: secrets.SourceSecret, Value: sensitiveParamKey}, Value: "2"},
+	expected := []secrets.SourceMap{
+		{Name: "my-first-param", Source: secrets.Source{Strategy: host.SourceValue, Hint: "1"}, ResolvedValue: "1"},
+		{Name: sensitiveParamName, Source: secrets.Source{Strategy: secrets.SourceSecret, Hint: sensitiveParamKey}, ResolvedValue: "2"},
 	}
 	sort.SliceStable(expected, func(i, j int) bool {
 		return expected[i].Name < expected[j].Name
@@ -71,25 +71,25 @@ func TestSanitizer_CleanParameters(t *testing.T) {
 			name:       "hardcoded sensitive value",
 			paramName:  "my-second-param",
 			sourceKey:  host.SourceValue,
-			wantSource: secrets.Source{Key: secrets.SourceSecret, Value: "INSTALLATION_ID-my-second-param"},
+			wantSource: secrets.Source{Strategy: secrets.SourceSecret, Hint: "INSTALLATION_ID-my-second-param"},
 		},
 		{ // Should be left alone
 			name:       "hardcoded insensitive value",
 			paramName:  "my-first-param",
 			sourceKey:  host.SourceValue,
-			wantSource: secrets.Source{Key: host.SourceValue, Value: "myvalue"},
+			wantSource: secrets.Source{Strategy: host.SourceValue, Hint: "myvalue"},
 		},
 		{ // Should be left alone
 			name:       "secret",
 			paramName:  "my-first-param",
 			sourceKey:  secrets.SourceSecret,
-			wantSource: secrets.Source{Key: secrets.SourceSecret, Value: "myvalue"},
+			wantSource: secrets.Source{Strategy: secrets.SourceSecret, Hint: "myvalue"},
 		},
 		{ // Should be left alone
 			name:       "env var",
 			paramName:  "my-second-param",
 			sourceKey:  host.SourceEnv,
-			wantSource: secrets.Source{Key: host.SourceEnv, Value: "myvalue"},
+			wantSource: secrets.Source{Strategy: host.SourceEnv, Hint: "myvalue"},
 		},
 	}
 
@@ -107,13 +107,13 @@ func TestSanitizer_CleanParameters(t *testing.T) {
 
 			inst := storage.NewInstallation("", "mybuns")
 			inst.ID = "INSTALLATION_ID" // Standardize for easy comparisons later
-			inst.Parameters.Parameters = []secrets.Strategy{
-				{Name: tc.paramName, Source: secrets.Source{Key: tc.sourceKey, Value: "myvalue"}},
+			inst.Parameters.Parameters = []secrets.SourceMap{
+				{Name: tc.paramName, Source: secrets.Source{Strategy: tc.sourceKey, Hint: "myvalue"}},
 			}
 			gotParams, err := r.Sanitizer.CleanParameters(ctx, inst.Parameters.Parameters, bun, inst.ID)
 			require.NoError(t, err, "CleanParameters failed")
 
-			wantParms := []secrets.Strategy{{Name: tc.paramName, Source: tc.wantSource}}
+			wantParms := []secrets.SourceMap{{Name: tc.paramName, Source: tc.wantSource}}
 			require.Equal(t, wantParms, gotParams, "unexpected value returned from CleanParameters")
 		})
 	}
diff --git a/tests/integration/dependencies_test.go b/tests/integration/dependencies_test.go
index e3b816dc..d5065fa6 100644
--- a/tests/integration/dependencies_test.go
+++ b/tests/integration/dependencies_test.go
@@ -74,11 +74,11 @@ func installWordpressBundle(ctx context.Context, p *porter.TestPorter) (namespac
 
 	// Add a supplemental parameter set to vet dep param resolution
 	installOpts.ParameterSets = []string{"myparam"}
-	testParamSets := storage.NewParameterSet(namespace, "myparam", secrets.Strategy{
+	testParamSets := storage.NewParameterSet(namespace, "myparam", secrets.SourceMap{
 		Name: "mysql#probe-timeout",
 		Source: secrets.Source{
-			Key:   host.SourceValue,
-			Value: "2",
+			Strategy: host.SourceValue,
+			Hint:     "2",
 		},
 	})
 
diff --git a/tests/integration/install_test.go b/tests/integration/install_test.go
index ab05e9ef..60d4bb66 100644
--- a/tests/integration/install_test.go
+++ b/tests/integration/install_test.go
@@ -53,11 +53,11 @@ func TestInstall_fileParam(t *testing.T) {
 	installOpts := porter.NewInstallOptions()
 	installOpts.Params = []string{"myfile=./myfile"}
 	installOpts.ParameterSets = []string{"myparam"}
-	testParamSets := storage.NewParameterSet("", "myparam", secrets.Strategy{
+	testParamSets := storage.NewParameterSet("", "myparam", secrets.SourceMap{
 		Name: "myotherfile",
 		Source: secrets.Source{
-			Key:   host.SourcePath,
-			Value: "./myotherfile",
+			Strategy: host.SourcePath,
+			Hint:     "./myotherfile",
 		},
 	})
 
diff --git a/tests/integration/sensitive_data_test.go b/tests/integration/sensitive_data_test.go
index d6b10749..183511e4 100644
--- a/tests/integration/sensitive_data_test.go
+++ b/tests/integration/sensitive_data_test.go
@@ -38,18 +38,18 @@ func TestSensitiveData(t *testing.T) {
 
 	for _, param := range i.Parameters.Parameters {
 		if param.Name == sensitiveParamName {
-			assert.NotContains(t, param.Source.Value, sensitiveParamValue)
+			assert.NotContains(t, param.Source.Hint, sensitiveParamValue)
 		}
 	}
 
 	for _, param := range run.ParameterOverrides.Parameters {
 		if param.Name == sensitiveParamName {
-			assert.NotContains(t, param.Source.Value, sensitiveParamValue)
+			assert.NotContains(t, param.Source.Hint, sensitiveParamValue)
 		}
 	}
 	for _, param := range run.Parameters.Parameters {
 		if param.Name == sensitiveParamName {
-			assert.NotContains(t, param.Source.Value, sensitiveParamValue)
+			assert.NotContains(t, param.Source.Hint, sensitiveParamValue)
 		}
 	}