get.porter.sh/porter@v1.3.0/pkg/storage/sanitizer_test.go (about) 1 package storage_test 2 3 import ( 4 "context" 5 "path/filepath" 6 "reflect" 7 "sort" 8 "testing" 9 10 "get.porter.sh/porter/pkg/cnab" 11 "get.porter.sh/porter/pkg/porter" 12 "get.porter.sh/porter/pkg/portercontext" 13 "get.porter.sh/porter/pkg/secrets" 14 "get.porter.sh/porter/pkg/storage" 15 "github.com/cnabio/cnab-go/secrets/host" 16 "github.com/stretchr/testify/require" 17 ) 18 19 func TestSanitizer_Parameters(t *testing.T) { 20 c := portercontext.New() 21 bun, err := cnab.LoadBundle(c, filepath.Join("../porter/testdata/bundle.json")) 22 require.NoError(t, err) 23 24 ctx := context.Background() 25 r := porter.NewTestPorter(t) 26 defer r.Close() 27 28 recordID := "01FZVC5AVP8Z7A78CSCP1EJ604" 29 sensitiveParamName := "my-second-param" 30 sensitiveParamKey := recordID + "-" + sensitiveParamName 31 expected := []secrets.SourceMap{ 32 {Name: "my-first-param", Source: secrets.Source{Strategy: host.SourceValue, Hint: "1"}, ResolvedValue: "1"}, 33 {Name: sensitiveParamName, Source: secrets.Source{Strategy: secrets.SourceSecret, Hint: sensitiveParamKey}, ResolvedValue: "2"}, 34 } 35 sort.SliceStable(expected, func(i, j int) bool { 36 return expected[i].Name < expected[j].Name 37 }) 38 39 // parameters that are hard coded values should be sanitized, while those mapped from secrets or env vars should be left alone by the sanitizer 40 rawParams := map[string]interface{}{ 41 "my-first-param": 1, 42 sensitiveParamName: "2", 43 } 44 result, err := r.TestSanitizer.CleanRawParameters(ctx, rawParams, bun, recordID) 45 require.NoError(t, err) 46 require.Equal(t, len(expected), len(result)) 47 sort.SliceStable(result, func(i, j int) bool { 48 return result[i].Name < result[j].Name 49 }) 50 51 require.Truef(t, reflect.DeepEqual(result, expected), "expected: %v, got: %v", expected, result) 52 53 pset := storage.NewParameterSet("", "dev", result...) 54 resolved, err := r.TestSanitizer.RestoreParameterSet(ctx, pset, bun) 55 require.NoError(t, err) 56 57 require.Equal(t, len(rawParams), len(resolved)) 58 for name, value := range resolved { 59 require.Equal(t, rawParams[name], value) 60 } 61 } 62 63 func TestSanitizer_CleanParameters(t *testing.T) { 64 testcases := []struct { 65 name string 66 paramName string 67 sourceKey string 68 wantSource secrets.Source 69 }{ 70 { // Should be switched to a secret 71 name: "hardcoded sensitive value", 72 paramName: "my-second-param", 73 sourceKey: host.SourceValue, 74 wantSource: secrets.Source{Strategy: secrets.SourceSecret, Hint: "INSTALLATION_ID-my-second-param"}, 75 }, 76 { // Should be left alone 77 name: "hardcoded insensitive value", 78 paramName: "my-first-param", 79 sourceKey: host.SourceValue, 80 wantSource: secrets.Source{Strategy: host.SourceValue, Hint: "myvalue"}, 81 }, 82 { // Should be left alone 83 name: "secret", 84 paramName: "my-first-param", 85 sourceKey: secrets.SourceSecret, 86 wantSource: secrets.Source{Strategy: secrets.SourceSecret, Hint: "myvalue"}, 87 }, 88 { // Should be left alone 89 name: "env var", 90 paramName: "my-second-param", 91 sourceKey: host.SourceEnv, 92 wantSource: secrets.Source{Strategy: host.SourceEnv, Hint: "myvalue"}, 93 }, 94 } 95 96 for _, tc := range testcases { 97 tc := tc 98 t.Run(tc.name, func(t *testing.T) { 99 100 c := portercontext.New() 101 bun, err := cnab.LoadBundle(c, filepath.Join("../porter/testdata/bundle.json")) 102 require.NoError(t, err) 103 104 ctx := context.Background() 105 r := porter.NewTestPorter(t) 106 defer r.Close() 107 108 inst := storage.NewInstallation("", "mybuns") 109 inst.ID = "INSTALLATION_ID" // Standardize for easy comparisons later 110 inst.Parameters.Parameters = []secrets.SourceMap{ 111 {Name: tc.paramName, Source: secrets.Source{Strategy: tc.sourceKey, Hint: "myvalue"}}, 112 } 113 gotParams, err := r.Sanitizer.CleanParameters(ctx, inst.Parameters.Parameters, bun, inst.ID) 114 require.NoError(t, err, "CleanParameters failed") 115 116 wantParms := []secrets.SourceMap{{Name: tc.paramName, Source: tc.wantSource}} 117 require.Equal(t, wantParms, gotParams, "unexpected value returned from CleanParameters") 118 }) 119 } 120 } 121 122 func TestSanitizer_Output(t *testing.T) { 123 c := portercontext.New() 124 bun, err := cnab.LoadBundle(c, filepath.Join("../porter/testdata/bundle.json")) 125 require.NoError(t, err) 126 127 ctx := context.Background() 128 r := porter.NewTestPorter(t) 129 defer r.Close() 130 131 recordID := "01FZVC5AVP8Z7A78CSCP1EJ604" 132 sensitiveOutputName := "my-first-output" 133 sensitiveOutput := storage.Output{ 134 Name: sensitiveOutputName, 135 Key: "", 136 Value: []byte("this is secret output"), 137 RunID: recordID, 138 } 139 140 expectedSensitiveOutput := storage.Output{ 141 Name: sensitiveOutputName, 142 Key: recordID + "-" + sensitiveOutputName, 143 Value: nil, 144 RunID: recordID, 145 } 146 147 plainOutput := storage.Output{ 148 Name: "my-second-output", 149 Key: "", 150 Value: []byte("true"), 151 RunID: recordID, 152 } 153 154 plainResult, err := r.TestSanitizer.CleanOutput(ctx, plainOutput, bun) 155 require.NoError(t, err) 156 require.Equal(t, plainOutput, plainResult) 157 158 sensitiveResult, err := r.TestSanitizer.CleanOutput(ctx, sensitiveOutput, bun) 159 require.NoError(t, err) 160 require.Equal(t, expectedSensitiveOutput, sensitiveResult) 161 162 expectedOutputs := storage.NewOutputs([]storage.Output{ 163 plainOutput, 164 {Name: sensitiveOutputName, Key: expectedSensitiveOutput.Key, Value: sensitiveOutput.Value, RunID: recordID}, 165 }) 166 resolved, err := r.TestSanitizer.RestoreOutputs(ctx, storage.NewOutputs([]storage.Output{sensitiveResult, plainOutput})) 167 require.NoError(t, err) 168 sort.Sort(resolved) 169 sort.Sort(expectedOutputs) 170 require.Truef(t, reflect.DeepEqual(expectedOutputs, resolved), "expected outputs: %v, got outputs: %v", expectedOutputs, resolved) 171 172 }