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