11// Copyright (c) Microsoft Corporation.
22// Licensed under the MIT License.
33
4- use crate :: { configure:: { config_doc:: { Configuration , ExecutionKind , Resource } , Configurator , context:: ProcessMode } , dscresources:: resource_manifest:: Kind } ;
4+ use crate :: { configure:: { Configurator , config_doc:: { Configuration , ExecutionKind , Resource } , context:: ProcessMode , parameters :: is_secure_value } , dscresources:: resource_manifest:: Kind } ;
55use crate :: dscresources:: invoke_result:: { ResourceGetResponse , ResourceSetResponse } ;
66use dscerror:: DscError ;
77use jsonschema:: Validator ;
@@ -311,7 +311,7 @@ impl Invoke for DscResource {
311311 let TestResult :: Resource ( ref resource_result) = result. results [ 0 ] . result else {
312312 return Err ( DscError :: Operation ( t ! ( "dscresources.dscresource.invokeReturnedWrongResult" , operation = "test" , resource = self . type_name) . to_string ( ) ) ) ;
313313 } ;
314- let desired_state = resource_result. desired_state
314+ let mut desired_state = resource_result. desired_state
315315 . as_object ( ) . ok_or ( DscError :: Operation ( t ! ( "dscresources.dscresource.propertyIncorrectType" , property = "desiredState" , property_type = "object" ) . to_string ( ) ) ) ?
316316 . get ( "resources" ) . ok_or ( DscError :: Operation ( t ! ( "dscresources.dscresource.propertyNotFound" , property = "resources" ) . to_string ( ) ) ) ?
317317 . as_array ( ) . ok_or ( DscError :: Operation ( t ! ( "dscresources.dscresource.propertyIncorrectType" , property = "resources" , property_type = "array" ) . to_string ( ) ) ) ?[ 0 ]
@@ -324,6 +324,7 @@ impl Invoke for DscResource {
324324 . as_object ( ) . ok_or ( DscError :: Operation ( t ! ( "dscresources.dscresource.propertyIncorrectType" , property = "result" , property_type = "object" ) . to_string ( ) ) ) ?
325325 . get ( "properties" ) . ok_or ( DscError :: Operation ( t ! ( "dscresources.dscresource.propertyNotFound" , property = "properties" ) . to_string ( ) ) ) ?. clone ( ) ;
326326 let diff_properties = get_diff ( & desired_state, & actual_state) ;
327+ desired_state = redact ( & desired_state) ;
327328 let test_result = TestResult :: Resource ( ResourceTestResponse {
328329 desired_state,
329330 actual_state,
@@ -346,7 +347,7 @@ impl Invoke for DscResource {
346347 let resource_manifest = import_manifest ( manifest. clone ( ) ) ?;
347348 if resource_manifest. test . is_none ( ) {
348349 let get_result = self . get ( expected) ?;
349- let desired_state = serde_json:: from_str ( expected) ?;
350+ let mut desired_state = serde_json:: from_str ( expected) ?;
350351 let actual_state = match get_result {
351352 GetResult :: Group ( results) => {
352353 let mut result_array: Vec < Value > = Vec :: new ( ) ;
@@ -360,6 +361,7 @@ impl Invoke for DscResource {
360361 }
361362 } ;
362363 let diff_properties = get_diff ( & desired_state, & actual_state) ;
364+ desired_state = redact ( & desired_state) ;
363365 let test_result = TestResult :: Resource ( ResourceTestResponse {
364366 desired_state,
365367 actual_state,
@@ -491,6 +493,37 @@ pub fn get_well_known_properties() -> HashMap<String, Value> {
491493 ] )
492494}
493495
496+ /// Checks if the JSON value is sensitive and should be redacted
497+ ///
498+ /// # Arguments
499+ ///
500+ /// * `value` - The JSON value to check
501+ ///
502+ /// # Returns
503+ ///
504+ /// Original value if not sensitive, otherwise a redacted value
505+ pub fn redact ( value : & Value ) -> Value {
506+ trace ! ( "Redacting value: {value}" ) ;
507+ if is_secure_value ( value) {
508+ return Value :: String ( "<secureValue>" . to_string ( ) ) ;
509+ }
510+
511+ if let Some ( map) = value. as_object ( ) {
512+ let mut new_map = Map :: new ( ) ;
513+ for ( key, val) in map {
514+ new_map. insert ( key. clone ( ) , redact ( val) ) ;
515+ }
516+ return Value :: Object ( new_map) ;
517+ }
518+
519+ if let Some ( array) = value. as_array ( ) {
520+ let new_array: Vec < Value > = array. iter ( ) . map ( |val| redact ( val) ) . collect ( ) ;
521+ return Value :: Array ( new_array) ;
522+ }
523+
524+ value. clone ( )
525+ }
526+
494527#[ must_use]
495528/// Performs a comparison of two JSON Values if the expected is a strict subset of the actual
496529///
@@ -524,6 +557,11 @@ pub fn get_diff(expected: &Value, actual: &Value) -> Vec<String> {
524557 }
525558
526559 for ( key, value) in & * map {
560+ if is_secure_value ( & value) {
561+ // skip secure values as they are not comparable
562+ continue ;
563+ }
564+
527565 if value. is_object ( ) {
528566 let sub_diff = get_diff ( value, & actual[ key] ) ;
529567 if !sub_diff. is_empty ( ) {
0 commit comments