1
+ // Copyright (c) .NET Foundation. All rights reserved.
2
+ // Licensed under the MIT License. See License.txt in the project root for license information.
3
+
4
+ using System ;
5
+ using System . Collections . Immutable ;
6
+ using Newtonsoft . Json . Linq ;
7
+ using Xunit ;
8
+
9
+ namespace Microsoft . Azure . WebJobs . Script . Tests
10
+ {
11
+ public sealed class MetadataJsonHelperTests
12
+ {
13
+ [ Fact ]
14
+ public void CreateJObjectWithSanitizedPropertyValue_NullJsonObject_ThrowsArgumentNullException ( )
15
+ {
16
+ JObject jsonObject = null ;
17
+ ImmutableHashSet < string > propertyNames = [ "sensitiveProperty" ] ;
18
+
19
+ Assert . Throws < ArgumentNullException > ( ( ) => MetadataJsonHelper . SanitizeProperties ( jsonObject , propertyNames ) ) ;
20
+ }
21
+
22
+ [ Fact ]
23
+ public void CreateJObjectWithSanitizedPropertyValue_NullPropertyNames_ThrowsArgumentNullException ( )
24
+ {
25
+ var jsonObject = new JObject ( ) ;
26
+ ImmutableHashSet < string > propertyNames = null ;
27
+
28
+ Assert . Throws < ArgumentNullException > ( ( ) => MetadataJsonHelper . SanitizeProperties ( jsonObject , propertyNames ) ) ;
29
+ }
30
+
31
+ [ Fact ]
32
+ public void CreateJObjectWithSanitizedPropertyValue_ValidInput_SanitizesMatchingProperties ( )
33
+ {
34
+ var jsonObject = new JObject
35
+ {
36
+ { "sensitiveProperty1" , "AccountKey=foo" } ,
37
+ { "sensitiveProperty2" , "MyConnection" } ,
38
+ { "SENSITIVEPROPERTY3" , "AccountKey=bar" } ,
39
+ { "otherProperty" , "value2" }
40
+ } ;
41
+ var sensitiveBindingPropertyNames = ImmutableHashSet . Create ( "sensitiveProperty1" , "sensitiveproperty2" , "sensitiveproperty3" ) ;
42
+
43
+ var result = MetadataJsonHelper . SanitizeProperties ( jsonObject , sensitiveBindingPropertyNames ) ;
44
+
45
+ Assert . Equal ( "[Hidden Credential]" , result [ "sensitiveProperty1" ] . ToString ( ) ) ;
46
+ Assert . Equal ( "MyConnection" , result [ "sensitiveProperty2" ] . ToString ( ) ) ;
47
+ Assert . Equal ( "[Hidden Credential]" , result [ "SENSITIVEPROPERTY3" ] . ToString ( ) ) ;
48
+ Assert . Equal ( "value2" , result [ "otherProperty" ] . ToString ( ) ) ;
49
+ }
50
+
51
+ [ Fact ]
52
+ public void CreateJObjectWithSanitizedPropertyValue_NoMatchingProperties_DoesNotSanitize ( )
53
+ {
54
+ var jsonObject = new JObject
55
+ {
56
+ { "otherProperty1" , "value1" } ,
57
+ { "otherProperty2" , "value2" } ,
58
+ { "otherProperty3" , "AccountKey=foo" }
59
+ } ;
60
+ var sensitiveBindingPropertyNames = ImmutableHashSet . Create ( "sensitiveProperty" ) ;
61
+
62
+ var result = MetadataJsonHelper . SanitizeProperties ( jsonObject , sensitiveBindingPropertyNames ) ;
63
+
64
+ Assert . Equal ( "value1" , result [ "otherProperty1" ] . ToString ( ) ) ;
65
+ Assert . Equal ( "value2" , result [ "otherProperty2" ] . ToString ( ) ) ;
66
+ Assert . Equal ( "AccountKey=foo" , result [ "otherProperty3" ] . ToString ( ) ) ;
67
+ }
68
+
69
+ [ Fact ]
70
+ public void CreateJObjectWithSanitizedPropertyValue_StringInput_NullOrEmptyJson_ThrowsArgumentException ( )
71
+ {
72
+ string json = null ;
73
+ var propertyNames = ImmutableHashSet . Create ( "sensitiveProperty" ) ;
74
+
75
+ Assert . Throws < ArgumentException > ( ( ) => MetadataJsonHelper . CreateJObjectWithSanitizedPropertyValue ( json , propertyNames ) ) ;
76
+ }
77
+
78
+ [ Fact ]
79
+ public void CreateJObjectWithSanitizedPropertyValue_StringInput_InvalidJson_ThrowsJsonReaderException ( )
80
+ {
81
+ var json = "invalid json" ;
82
+ var propertyNames = ImmutableHashSet . Create ( "sensitiveProperty" ) ;
83
+
84
+ Assert . Throws < Newtonsoft . Json . JsonReaderException > ( ( ) => MetadataJsonHelper . CreateJObjectWithSanitizedPropertyValue ( json , propertyNames ) ) ;
85
+ }
86
+
87
+ [ Fact ]
88
+ public void CreateJObjectWithSanitizedPropertyValue_StringInput_ValidJson_SanitizesMatchingProperties ( )
89
+ {
90
+ var json = """{ "SensitiveProperty": "pwd=12345", "otherProperty": "value2" }""" ;
91
+ var propertyNames = ImmutableHashSet . Create ( "sensitiveproperty" ) ;
92
+
93
+ var result = MetadataJsonHelper . CreateJObjectWithSanitizedPropertyValue ( json , propertyNames ) ;
94
+
95
+ Assert . Equal ( "[Hidden Credential]" , result [ "SensitiveProperty" ] . ToString ( ) ) ;
96
+ Assert . Equal ( "value2" , result [ "otherProperty" ] . ToString ( ) ) ;
97
+ }
98
+
99
+ [ Fact ]
100
+ public void CreateJObjectWithSanitizedPropertyValue_NullSensitiveProperty_DoesNotThrow ( )
101
+ {
102
+ var jsonObject = new JObject
103
+ {
104
+ { "connection" , null } ,
105
+ { "otherProperty1" , "value1" } ,
106
+ { "otherProperty2" , string . Empty }
107
+ } ;
108
+ var propertyNames = ImmutableHashSet . Create ( "connection" , "otherProperty2" ) ;
109
+
110
+ var result = MetadataJsonHelper . SanitizeProperties ( jsonObject , propertyNames ) ;
111
+
112
+ Assert . Equal ( JTokenType . Null , result [ "connection" ] . Type ) ; // Ensure null remains null
113
+ Assert . Equal ( "value1" , result [ "otherProperty1" ] . ToString ( ) ) ;
114
+ Assert . Equal ( string . Empty , result [ "otherProperty2" ] . ToString ( ) ) ; // Ensure empty string remains empty
115
+ }
116
+
117
+ [ Fact ]
118
+ public void CreateJObjectWithSanitizedPropertyValue_StringInput_DateTimeWithTimezoneOffset_RemainsUnchanged ( )
119
+ {
120
+ var json = """{ "timestamp": "2025-07-03T12:30:45+02:00", "otherProperty": "value2" }""" ;
121
+ var propertyNames = ImmutableHashSet . Create ( "sensitiveProperty" ) ;
122
+
123
+ var result = MetadataJsonHelper . CreateJObjectWithSanitizedPropertyValue ( json , propertyNames ) ;
124
+
125
+ Assert . Equal ( "2025-07-03T12:30:45+02:00" , result [ "timestamp" ] . ToObject < string > ( ) ) ; // ensure the value remains unchanged(not parsed as DateTime)
126
+ Assert . Equal ( "value2" , result [ "otherProperty" ] . ToString ( ) ) ;
127
+ }
128
+ }
129
+ }
0 commit comments