DSC icon indicating copy to clipboard operation
DSC copied to clipboard

Parameter `secureString` transforms input incorrectly on adapter

Open Gijsreyn opened this issue 2 months ago • 2 comments

Prerequisites

  • [x] Write a descriptive title.
  • [x] Make sure you are able to repro it on the latest version
  • [x] Search the existing issues.

Summary

Whilst working on #1208, another issue popped up. I have the following configuration document:

$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
parameters:
  myString:
    type: secureString
    defaultValue: "MySecret"
resources:
- name: Class-resource Info
  type: TestClassResource/TestClassResource
  properties:
    Name: 'TestClassResource'
    SecureStringProp: "[parameters('myString')]"

Instead of parsing the input through the adapter as such (seen in the logging):

{"resources":[{"name":"TestClassResource/TestClassResource","type":"TestClassResource/TestClassResource","properties":{"Name":"TestClassResource","SecureStringProp":"MySecret"}}],"metadata":{"Microsoft.DSC":{"context":"configuration"}}}

It does it like:

jsonInput={"resources":[{"name":"TestClassResource/TestClassResource","type":"TestClassResource/TestClassResource","properties":{"Name":"TestClassResource","SecureStringProp":{"secureString":"MySecret"}}}],"metadata":{"Microsoft.DSC":{"context":"configuration"}}}

Which results in the following error: Exception setting "SecureStringProp": "Cannot create object of type "System.Security.SecureString". The property 'secureString' was not found for the 'System.Security.SecureString' object. There is no settable property available."

Steps to reproduce

See steps above.

Expected behavior

The secure string is parsed as string

Actual behavior

The secure string is parsed as object

Error details


Environment data

Name                           Value
----                           -----
PSVersion                      7.5.3
PSEdition                      Core
GitCommitId                    7.5.3
OS                             Microsoft Windows 10.0.26100
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Version

dsc 3.2.0-preview.6

Visuals

No response

Gijsreyn avatar Oct 24 '25 08:10 Gijsreyn

@SteveL-MSFT - I tried debugging this myself and look back to the history what has happened here.

Basically, I just removed the object type (seen in the history) for string to something like:

se crate::configure::config_doc::DataType;
use crate::configure::parameters::{SecureObject};
use crate::DscError;
use crate::configure::context::Context;
use crate::functions::{FunctionArgKind, Function, FunctionCategory, FunctionMetadata};
use rust_i18n::t;
use serde_json::Value;
use tracing::{debug, trace};

#[derive(Debug, Default)]
pub struct Parameters {}

impl Function for Parameters {
    fn get_metadata(&self) -> FunctionMetadata {
        FunctionMetadata {
            name: "parameters".to_string(),
            description: t!("functions.parameters.description").to_string(),
            category: vec![FunctionCategory::Deployment],
            min_args: 1,
            max_args: 1,
            accepted_arg_ordered_types: vec![vec![FunctionArgKind::String]],
            remaining_arg_accepted_types: None,
            return_types: vec![FunctionArgKind::String, FunctionArgKind::Number, FunctionArgKind::Boolean, FunctionArgKind::Object, FunctionArgKind::Array, FunctionArgKind::Null],
        }
    }

    fn invoke(&self, args: &[Value], context: &Context) -> Result<Value, DscError> {
        debug!("{}", t!("functions.parameters.invoked"));
        if let Some(key) = args[0].as_str() {
            trace!("{}", t!("functions.parameters.traceKey", key = key));
            if context.parameters.contains_key(key) {
                let (value, data_type) = &context.parameters[key];

                match data_type {
                    DataType::SecureString => {
                        let Some(_value) = value.as_str() else {
                            return Err(DscError::Parser(t!("functions.parameters.keyNotString", key = key).to_string()));
                        };
                    },
// truncated

Now I'm not certain, nor did I gave feedback during that PR, what the design choice was to transform the secure string to an object. As mentioned in the PR, I can see that resources should handle this, but is this also the case for adapters? If so, a second option would be to read it in the adapter, and simply strip away the object type.

Another option would be (which I haven't checked out) to let the adapter code handle it 🤔. Any thoughts are welcome.

Gijsreyn avatar Oct 24 '25 09:10 Gijsreyn

@Gijsreyn the intent for that original PR was the secureString and secureObject needed to maintain their "object-ness" and rely on resources to handle them appropriately. This is also true for adapters. In this case, the psadapter needs to see if the property value is of one of these types and convert it to the correct PowerShell/.NET type.

SteveL-MSFT avatar Oct 27 '25 22:10 SteveL-MSFT