@@ -195,6 +195,133 @@ func TestGenericReplacement_specificPathWithValidation(t *testing.T) {
195195 })
196196}
197197
198+ func TestGenericReplacement_specificPathUrlEncoded (t * testing.T ) {
199+ // Test that the specific-path placeholder syntax is used to find/replace placeholders that were url-encoded
200+ // along with the generic syntax, since the generic Vault path is defined
201+ mv := helpers.MockVault {}
202+ mv .LoadData (map [string ]interface {}{
203+ "namespace" : "default ns" ,
204+ })
205+
206+ dummyResource := Resource {
207+ TemplateData : map [string ]interface {}{
208+ "namespace" : "%3Cpath%3Ablah%2Fblah%23namespace%3E" ,
209+ "name" : "<name>" ,
210+ },
211+ Data : map [string ]interface {}{
212+ "namespace" : "something-else" ,
213+ "name" : "foo" ,
214+ },
215+ Backend : & mv ,
216+ Annotations : map [string ]string {
217+ (types .AVPPathAnnotation ): "" ,
218+ },
219+ }
220+
221+ replaceInner (& dummyResource , & dummyResource .TemplateData , genericReplacement )
222+
223+ if ! mv .GetIndividualSecretCalled {
224+ t .Fatalf ("expected GetSecrets to be called since placeholder contains explicit path so Vault lookup is neeed" )
225+ }
226+
227+ expected := Resource {
228+ TemplateData : map [string ]interface {}{
229+ "namespace" : "default+ns" ,
230+ "name" : "foo" ,
231+ },
232+ Data : map [string ]interface {}{
233+ "namespace" : "something-else" ,
234+ "name" : "foo" ,
235+ },
236+ replacementErrors : []error {},
237+ }
238+
239+ assertSuccessfulReplacement (& dummyResource , & expected , t )
240+ }
241+
242+ func TestGenericReplacement_specificPathUrlEncodedWithValidation (t * testing.T ) {
243+ // Test that the specific-path placeholder syntax is used to find/replace placeholders
244+ // along with the generic syntax, since the generic Vault path is defined
245+ mv := helpers.MockVault {}
246+ mv .LoadData (map [string ]interface {}{
247+ "namespace" : "default ns" ,
248+ })
249+
250+ t .Run ("valid path" , func (t * testing.T ) {
251+ dummyResource := Resource {
252+ TemplateData : map [string ]interface {}{
253+ "namespace" : "%3Cpath%3Ablah%2Fblah%23namespace%3E" ,
254+ "name" : "<name>" ,
255+ },
256+ Data : map [string ]interface {}{
257+ "namespace" : "something-else" ,
258+ "name" : "foo" ,
259+ },
260+ Backend : & mv ,
261+ Annotations : map [string ]string {
262+ (types .AVPPathAnnotation ): "" ,
263+ },
264+ PathValidation : regexp .MustCompile (`^([A-Za-z/]*)$` ),
265+ }
266+
267+ replaceInner (& dummyResource , & dummyResource .TemplateData , genericReplacement )
268+
269+ if ! mv .GetIndividualSecretCalled {
270+ t .Fatalf ("expected GetSecrets to be called since placeholder contains explicit path so Vault lookup is neeed" )
271+ }
272+
273+ expected := Resource {
274+ TemplateData : map [string ]interface {}{
275+ "namespace" : "default+ns" ,
276+ "name" : "foo" ,
277+ },
278+ Data : map [string ]interface {}{
279+ "namespace" : "something-else" ,
280+ "name" : "foo" ,
281+ },
282+ replacementErrors : []error {},
283+ }
284+
285+ assertSuccessfulReplacement (& dummyResource , & expected , t )
286+ })
287+
288+ t .Run ("invalid path" , func (t * testing.T ) {
289+ dummyResource := Resource {
290+ TemplateData : map [string ]interface {}{
291+ "namespace" : "%3Cpath%3A..%2Fblah%2Fblah%23namespace%3E" ,
292+ },
293+ Data : map [string ]interface {}{
294+ "namespace" : "something-else" ,
295+ },
296+ Backend : & mv ,
297+ Annotations : map [string ]string {
298+ (types .AVPPathAnnotation ): "" ,
299+ },
300+ PathValidation : regexp .MustCompile (`^([A-Za-z/]*)$` ),
301+ }
302+
303+ replaceInner (& dummyResource , & dummyResource .TemplateData , genericReplacement )
304+
305+ if ! mv .GetIndividualSecretCalled {
306+ t .Fatalf ("expected GetSecrets to be called since placeholder contains explicit path so Vault lookup is neeed" )
307+ }
308+
309+ expected := Resource {
310+ TemplateData : map [string ]interface {}{
311+ "namespace" : "%3Cpath%3A..%2Fblah%2Fblah%23namespace%3E" ,
312+ },
313+ Data : map [string ]interface {}{
314+ "namespace" : "something-else" ,
315+ },
316+ replacementErrors : []error {
317+ fmt .Errorf ("the path ../blah/blah is disallowed by AVP_PATH_VALIDATION restriction" ),
318+ },
319+ }
320+
321+ assertFailedReplacement (& dummyResource , & expected , t )
322+ })
323+ }
324+
198325func TestGenericReplacement_specificPathVersioned (t * testing.T ) {
199326 // Test that the specific-path placeholder syntax with versioning is used to find/replace placeholders
200327 mv := helpers.MockVault {}
@@ -316,6 +443,47 @@ func TestGenericReplacement_multiString(t *testing.T) {
316443 assertSuccessfulReplacement (& dummyResource , & expected , t )
317444}
318445
446+ func TestGenericReplacement_multiStringSpecificPathUrlEncoded (t * testing.T ) {
447+ mv := helpers.MockVault {}
448+ mv .LoadData (map [string ]interface {}{
449+ "name" : "my app" ,
450+ "tag" : "v1" ,
451+ })
452+
453+ dummyResource := Resource {
454+ TemplateData : map [string ]interface {}{
455+ "namespace" : "<namespace>" ,
456+ "image" : "foo.io/%3Cpath%3Ablah%2Fblah%23name%3E:%3Cpath%3Ablah%2Fblah%23tag%3E" ,
457+ },
458+ Data : map [string ]interface {}{
459+ "namespace" : "default" ,
460+ "name" : "app" ,
461+ "tag" : "latest" ,
462+ },
463+ Backend : & mv ,
464+ Annotations : map [string ]string {
465+ (types .AVPPathAnnotation ): "" ,
466+ },
467+ }
468+
469+ replaceInner (& dummyResource , & dummyResource .TemplateData , genericReplacement )
470+
471+ expected := Resource {
472+ TemplateData : map [string ]interface {}{
473+ "namespace" : "default" ,
474+ "image" : "foo.io/my+app:v1" ,
475+ },
476+ Data : map [string ]interface {}{
477+ "namespace" : "default" ,
478+ "name" : "app" ,
479+ "tag" : "latest" ,
480+ },
481+ replacementErrors : []error {},
482+ }
483+
484+ assertSuccessfulReplacement (& dummyResource , & expected , t )
485+ }
486+
319487func TestGenericReplacement_Base64 (t * testing.T ) {
320488 dummyResource := Resource {
321489 TemplateData : map [string ]interface {}{
0 commit comments