Skip to content

Commit 91c6c1c

Browse files
committed
fix handling of arrays
1 parent be4abd4 commit 91c6c1c

File tree

9 files changed

+95
-21
lines changed

9 files changed

+95
-21
lines changed

dsc/examples/secure_parameters.dsc.yaml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,23 @@ parameters:
88
type: bool
99
defaultValue: false
1010
resources:
11-
- name: Echo 1
11+
- name: SecureString
1212
type: Microsoft.DSC.Debug/Echo
1313
properties:
1414
output: "[parameters('myString')]"
1515
showSecrets: "[parameters('showSecrets')]"
16-
- name: Echo 2
16+
- name: SecureObject
1717
type: Microsoft.DSC.Debug/Echo
1818
properties:
1919
output: "[parameters('myObject').myProperty]"
2020
showSecrets: "[parameters('showSecrets')]"
21+
- name: SecureArray
22+
type: Microsoft.DSC.Debug/Echo
23+
properties:
24+
output: "[parameters('myObject').myArray]"
25+
showSecrets: "[parameters('showSecrets')]"
26+
- name: SecureArrayIndexed
27+
type: Microsoft.DSC.Debug/Echo
28+
properties:
29+
output: "[parameters('myObject').myArray[1]]"
30+
showSecrets: "[parameters('showSecrets')]"

dsc/examples/secure_parameters.parameters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ parameters:
22
myString: mySecret
33
myObject:
44
myProperty: mySecretProperty
5+
myArray:
6+
- item1
7+
- item2

dsc/examples/secure_parameters_shown.parameters.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ parameters:
22
myString: mySecret
33
myObject:
44
myProperty: mySecretProperty
5+
myArray:
6+
- item1
7+
- item2
58
showSecrets: true

dsc/tests/dsc_parameters.tests.ps1

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,17 +275,25 @@ Describe 'Parameters tests' {
275275
}
276276

277277
It 'secure types can be passed as objects to resources but redacted in output' {
278-
$out = dsc config -f $PSScriptRoot/../examples/secure_parameters.parameters.yaml get -f $PSScriptRoot/../examples/secure_parameters.dsc.yaml | ConvertFrom-Json
278+
$out = dsc -l trace config -f $PSScriptRoot/../examples/secure_parameters.parameters.yaml get -f $PSScriptRoot/../examples/secure_parameters.dsc.yaml 2> $TestDrive/error.log | ConvertFrom-Json
279279
$LASTEXITCODE | Should -Be 0
280+
$out.results.Count | Should -Be 4
280281
$out.results[0].result.actualState.output | Should -BeExactly '<secureValue>'
281282
$out.results[1].result.actualState.output | Should -BeExactly '<secureValue>'
283+
$out.results[2].result.actualState.output[0] | Should -BeExactly '<secureValue>'
284+
$out.results[2].result.actualState.output[1] | Should -BeExactly '<secureValue>'
285+
$out.results[3].result.actualState.output | Should -BeExactly '<secureValue>'
282286
}
283287

284288
It 'secure types can be passed as objects to resources' {
285289
$out = dsc config -f $PSScriptRoot/../examples/secure_parameters_shown.parameters.yaml get -f $PSScriptRoot/../examples/secure_parameters.dsc.yaml | ConvertFrom-Json
286290
$LASTEXITCODE | Should -Be 0
291+
$out.results.Count | Should -Be 4
287292
$out.results[0].result.actualState.output.secureString | Should -BeExactly 'mySecret'
288293
$out.results[1].result.actualState.output.secureString | Should -BeExactly 'mySecretProperty'
294+
$out.results[2].result.actualState.output[0].secureString | Should -BeExactly 'item1'
295+
$out.results[2].result.actualState.output[1].secureString | Should -BeExactly 'item2'
296+
$out.results[3].result.actualState.output.secureObject.secureString | Should -BeExactly 'item2'
289297
}
290298

291299
It 'parameter types are validated for <type>' -TestCases @(

dsc_lib/src/configure/parameters.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub struct Input {
1111
pub parameters: HashMap<String, Value>,
1212
}
1313

14+
pub const SECURE_VALUE_REDACTED: &str = "<secureValue>";
15+
1416
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)]
1517
pub struct SecureString {
1618
#[serde(rename = "secureString")]
@@ -19,7 +21,7 @@ pub struct SecureString {
1921

2022
impl Display for SecureString {
2123
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22-
write!(f, "<secureValue>")
24+
write!(f, "{SECURE_VALUE_REDACTED}")
2325
}
2426
}
2527

@@ -31,7 +33,7 @@ pub struct SecureObject {
3133

3234
impl Display for SecureObject {
3335
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34-
write!(f, "<secureValue>")
36+
write!(f, "{SECURE_VALUE_REDACTED}")
3537
}
3638
}
3739

dsc_lib/src/dscresources/dscresource.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
use crate::{configure::{Configurator, config_doc::{Configuration, ExecutionKind, Resource}, context::ProcessMode, parameters::is_secure_value}, dscresources::resource_manifest::Kind};
4+
use crate::{configure::{Configurator, config_doc::{Configuration, ExecutionKind, Resource}, context::ProcessMode, parameters::{SECURE_VALUE_REDACTED, is_secure_value}}, dscresources::resource_manifest::Kind};
55
use crate::dscresources::invoke_result::{ResourceGetResponse, ResourceSetResponse};
66
use dscerror::DscError;
77
use jsonschema::Validator;
@@ -503,9 +503,8 @@ pub fn get_well_known_properties() -> HashMap<String, Value> {
503503
///
504504
/// Original value if not sensitive, otherwise a redacted value
505505
pub fn redact(value: &Value) -> Value {
506-
trace!("Redacting value: {value}");
507506
if is_secure_value(value) {
508-
return Value::String("<secureValue>".to_string());
507+
return Value::String(SECURE_VALUE_REDACTED.to_string());
509508
}
510509

511510
if let Some(map) = value.as_object() {

dsc_lib/src/parser/expressions.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ impl Expression {
196196
}
197197
}
198198

199+
/// Convert a JSON value to a secure value if it is a string or an array of strings.
200+
///
201+
/// Arguments
202+
///
203+
/// * `value` - The JSON value to convert.
204+
///
205+
/// Returns
206+
///
207+
/// The converted JSON value.
199208
fn convert_to_secure(value: &Value) -> Value {
200209
if let Some(string) = value.as_str() {
201210
let secure_string = crate::configure::parameters::SecureString {
@@ -205,12 +214,10 @@ fn convert_to_secure(value: &Value) -> Value {
205214
}
206215

207216
if let Some(obj) = value.as_object() {
208-
if obj.len() == 1 && obj.contains_key("secureObject") {
209-
let secure_object = crate::configure::parameters::SecureObject {
210-
secure_object: obj["secureObject"].clone(),
211-
};
212-
return serde_json::to_value(secure_object).unwrap_or(value.clone());
213-
}
217+
let secure_object = crate::configure::parameters::SecureObject {
218+
secure_object: serde_json::Value::Object(obj.clone()),
219+
};
220+
return serde_json::to_value(secure_object).unwrap_or(value.clone());
214221
}
215222

216223
if let Some(array) = value.as_array() {

dscecho/locales/en-us.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,3 @@ _version = 1
22

33
[main]
44
invalidJson = "Error JSON does not match schema"
5-
noInput = "No input provided."

dscecho/src/main.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ use args::Args;
88
use clap::Parser;
99
use rust_i18n::{i18n, t};
1010
use schemars::schema_for;
11+
use serde_json::{Map, Value};
1112
use crate::echo::{Echo, Output};
1213

1314
i18n!("locales", fallback = "en-us");
1415

16+
const SECURE_VALUE_REDACTED: &str = "<secureValue>";
17+
1518
fn main() {
1619
let args = Args::parse();
1720
match args.input {
@@ -24,9 +27,21 @@ fn main() {
2427
}
2528
};
2629
if echo.show_secrets != Some(true) {
27-
match &echo.output {
30+
match echo.output {
2831
Output::SecureString(_) | Output::SecureObject(_) => {
29-
echo.output = Output::String("<secureValue>".to_string());
32+
echo.output = Output::String(SECURE_VALUE_REDACTED.to_string());
33+
},
34+
Output::Array(ref mut arr) => {
35+
for item in arr.iter_mut() {
36+
if is_secure_value(item) {
37+
*item = Value::String(SECURE_VALUE_REDACTED.to_string());
38+
} else {
39+
*item = redact(item);
40+
}
41+
}
42+
},
43+
Output::Object(ref mut obj) => {
44+
*obj = redact(obj);
3045
},
3146
_ => {}
3247
}
@@ -36,11 +51,39 @@ fn main() {
3651
return;
3752
},
3853
None => {
39-
eprintln!("{}", t!("main.noInput"));
54+
let schema = schema_for!(Echo);
55+
let json = serde_json::to_string_pretty(&schema).unwrap();
56+
println!("{json}");
57+
}
58+
}
59+
}
60+
61+
fn is_secure_value(value: &Value) -> bool {
62+
if let Some(obj) = value.as_object() {
63+
if obj.len() == 1 && (obj.contains_key("secureString") || obj.contains_key("secureObject")) {
64+
return true;
4065
}
4166
}
67+
false
68+
}
69+
70+
pub fn redact(value: &Value) -> Value {
71+
if is_secure_value(value) {
72+
return Value::String(SECURE_VALUE_REDACTED.to_string());
73+
}
74+
75+
if let Some(map) = value.as_object() {
76+
let mut new_map = Map::new();
77+
for (key, val) in map {
78+
new_map.insert(key.clone(), redact(val));
79+
}
80+
return Value::Object(new_map);
81+
}
82+
83+
if let Some(array) = value.as_array() {
84+
let new_array: Vec<Value> = array.iter().map(redact).collect();
85+
return Value::Array(new_array);
86+
}
4287

43-
let schema = schema_for!(Echo);
44-
let json = serde_json::to_string_pretty(&schema).unwrap();
45-
println!("{json}");
88+
value.clone()
4689
}

0 commit comments

Comments
 (0)