From 8ae3bd64fe6bd0fb7e1a86cba81d7c93d97d61b9 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 9 Jun 2026 21:24:51 -0700 Subject: [PATCH 1/6] Enable `export` operation to have own schema --- Cargo.lock | 1 + dsc/tests/dsc_resource_export.tests.ps1 | 20 ++++ lib/dsc-lib-jsonschema/.versions.json | 4 +- lib/dsc-lib/locales/en-us.toml | 1 + .../src/dscresources/command_resource.rs | 49 ++++++++- .../src/dscresources/resource_manifest.rs | 13 +++ tools/dsctest/Cargo.toml | 1 + tools/dsctest/dsctest.dsc.manifests.json | 104 ++++++++++++++++++ tools/dsctest/src/args.rs | 8 ++ tools/dsctest/src/export_schema.rs | 86 +++++++++++++++ tools/dsctest/src/main.rs | 11 ++ 11 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 dsc/tests/dsc_resource_export.tests.ps1 create mode 100644 tools/dsctest/src/export_schema.rs diff --git a/Cargo.lock b/Cargo.lock index fdd7f377c..25495a3f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -979,6 +979,7 @@ name = "dsctest" version = "0.1.0" dependencies = [ "clap", + "regex", "registry", "schemars", "serde", diff --git a/dsc/tests/dsc_resource_export.tests.ps1 b/dsc/tests/dsc_resource_export.tests.ps1 new file mode 100644 index 000000000..f780f87f6 --- /dev/null +++ b/dsc/tests/dsc_resource_export.tests.ps1 @@ -0,0 +1,20 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +Describe 'Resource export tests' { + It "Export with accepts input '' and returns filtered results" -TestCases @( + @{ resource = 'Test/ExportSchemaCommand'; json = '{ "name": "Gijs" }'; expected = @('Gijs') }, + @{ resource = 'Test/ExportSchemaCommand'; json = '{ "name": "*e*" }'; expected = @('Steve', 'Tess') }, + @{ resource = 'Test/ExportSchemaEmbedded'; json = '{ "name": "Gijs" }'; expected = @('Gijs') }, + @{ resource = 'Test/ExportSchemaEmbedded'; json = '{ "name": "*e*" }'; expected = @('Steve', 'Tess') }, + @{ resource = 'Test/ExportSchemaNoFiltering'; json = '{ "name": "Gijs" }'; expected = @('Steve', 'Tess', 'Gijs') } + ){ + param($resource, $json, $expected) + + $output = dsc resource export -r $resource -i $json 2>$TESTDRIVE/error.log | ConvertFrom-Json + $errorlog = Get-Content "$TESTDRIVE/error.log" -Raw + $LASTEXITCODE | Should -Be 0 -Because $errorlog + $output.resources.count | Should -Be $expected.Count -Because ($output | ConvertTo-Json -Depth 4) + $output.resources.properties.name | Should -Be $expected -Because ($output | ConvertTo-Json -Depth 4) + } +} diff --git a/lib/dsc-lib-jsonschema/.versions.json b/lib/dsc-lib-jsonschema/.versions.json index 6ffb355c8..15f6ca427 100644 --- a/lib/dsc-lib-jsonschema/.versions.json +++ b/lib/dsc-lib-jsonschema/.versions.json @@ -1,10 +1,12 @@ { "latestMajor": "V3", "latestMinor": "V3_2", - "latestPatch": "V3_2_0", + "latestPatch": "V3_2_2", "all": [ "V3", "V3_2", + "V3_2_2", + "V3_2_1", "V3_2_0", "V3_1", "V3_1_3", diff --git a/lib/dsc-lib/locales/en-us.toml b/lib/dsc-lib/locales/en-us.toml index 83316a729..6603fe6fb 100644 --- a/lib/dsc-lib/locales/en-us.toml +++ b/lib/dsc-lib/locales/en-us.toml @@ -193,6 +193,7 @@ exportNotSupportedUsingGet = "Export is not supported by resource '%{resource}' runProcessError = "Failed to run process '%{executable}': %{error}" whatIfWarning = "Resource '%{resource}' uses deprecated 'whatIf' operation. See https://github.com/PowerShell/DSC/issues/1361 for migration information." securityContextRequired = "Operation '%{operation}' for resource '%{resource}' requires security context '%{context}'" +exportNoFilteringWithInput = "Resource '%{resource}' does not support filtering export results and input was provided" [dscresources.dscresource] invokeGet = "Invoking get for '%{resource}'" diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index c03525ab6..cf3568e84 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -8,7 +8,7 @@ use rust_i18n::t; use serde::Deserialize; use serde_json::{Map, Value}; use std::{collections::HashMap, env, path::{Path, PathBuf}, process::Stdio}; -use crate::{configure::{config_doc::{ExecutionKind, SecurityContextKind}, config_result::{ResourceGetResult, ResourceTestResult}}, dscresources::resource_manifest::SchemaArgKind, types::{ExitCodesMap, FullyQualifiedTypeName}, util::canonicalize_which}; +use crate::{configure::{config_doc::{ExecutionKind, SecurityContextKind}, config_result::{ResourceGetResult, ResourceTestResult}}, dscresources::resource_manifest::{ExportSchemaKind, SchemaArgKind}, types::{ExitCodesMap, FullyQualifiedTypeName}, util::canonicalize_which}; use crate::dscerror::DscError; use super::{ dscresource::{get_diff, redact, DscResource}, @@ -616,6 +616,34 @@ pub fn get_schema(resource: &DscResource, target_resource: Option<&DscResource>) } } +pub fn get_export_schema(resource: &DscResource, target_resource: Option<&DscResource>) -> Result { + let Some(manifest) = &resource.manifest else { + return Err(DscError::MissingManifest(resource.type_name.to_string())); + }; + let Some(export) = manifest.export.as_ref() else { + return Err(DscError::SchemaNotAvailable(resource.type_name.to_string())); + }; + + match export.schema { + Some(ExportSchemaKind::Command(ref command)) => { + let resource_type = match target_resource { + Some(r) => r.type_name.clone(), + None => resource.type_name.clone(), + }; + let args = process_schema_args(command.args.as_ref(), &CommandResourceInfo { type_name: resource_type, path: None }); + let (_exit_code, stdout, _stderr) = invoke_command(&command.executable, args, None, Some(&resource.directory), None, manifest.exit_codes.as_ref())?; + Ok(stdout) + }, + Some(ExportSchemaKind::Embedded(ref schema)) => { + let json = serde_json::to_string(schema)?; + Ok(json) + }, + _ => { + get_schema(resource, target_resource) + } + } +} + /// Invoke the export operation on a resource /// /// # Arguments @@ -671,9 +699,26 @@ pub fn invoke_export(resource: &DscResource, input: Option<&str>, target_resourc type_name: resource_type.clone(), path, }; + if let Some(input) = input { + let input = if export.schema == Some(ExportSchemaKind::NoFiltering) { + "" + } else { + input + }; if !input.is_empty() { - verify_json_from_manifest(resource, input, target_resource)?; + let schema = serde_json::from_str(&get_export_schema(resource, target_resource)?)?; + let compiled_schema = match Validator::new(&schema) { + Ok(schema) => schema, + Err(e) => { + return Err(DscError::Schema(e.to_string())); + }, + }; + let json: Value = serde_json::from_str(input)?; + if let Err(err) = compiled_schema.validate(&json) { + return Err(DscError::Schema(err.to_string())); + } + command_input = get_command_input(export.input.as_ref(), input)?; } diff --git a/lib/dsc-lib/src/dscresources/resource_manifest.rs b/lib/dsc-lib/src/dscresources/resource_manifest.rs index 568e44f9b..16947b0ff 100644 --- a/lib/dsc-lib/src/dscresources/resource_manifest.rs +++ b/lib/dsc-lib/src/dscresources/resource_manifest.rs @@ -198,6 +198,18 @@ pub enum SchemaKind { Embedded(Value), } +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] +#[dsc_repo_schema(base_name = "manifest.exportSchema", folder_path = "definitions")] +#[serde(rename_all = "camelCase")] +pub enum ExportSchemaKind { + /// The export schema is returned by running a command. + Command(SchemaCommand), + /// The export schema is embedded in the manifest. + Embedded(Value), + /// The export operation does not support filtering. + NoFiltering, +} + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] pub struct SchemaCommand { /// The command to run to get the schema. @@ -313,6 +325,7 @@ pub struct ExportMethod { /// The security context required to run the Export method. Default if not specified is `current`. #[serde(rename = "requireSecurityContext", skip_serializing_if = "Option::is_none")] pub require_security_context: Option, + pub schema: Option, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema, DscRepoSchema)] diff --git a/tools/dsctest/Cargo.toml b/tools/dsctest/Cargo.toml index b339babbb..f502c610e 100644 --- a/tools/dsctest/Cargo.toml +++ b/tools/dsctest/Cargo.toml @@ -7,6 +7,7 @@ edition = "2024" [dependencies] clap = { workspace = true } +regex = { workspace = true } schemars = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/tools/dsctest/dsctest.dsc.manifests.json b/tools/dsctest/dsctest.dsc.manifests.json index 681dbbf4d..8c2346003 100644 --- a/tools/dsctest/dsctest.dsc.manifests.json +++ b/tools/dsctest/dsctest.dsc.manifests.json @@ -1405,6 +1405,110 @@ ] } } + }, + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/ExportSchemaCommand", + "version": "0.1.0", + "description": "Test resource for export specific schema", + "export": { + "executable": "dsctest", + "args": [ + "export-schema", + { + "jsonInputArg": "--input", + "mandatory": true + } + ], + "schema": { + "command":{ + "executable": "dsctest", + "args": [ + "schema", + "-s", + "export-schema" + ] + } + } + }, + "schema": { + "command": { + "executable": "dsctest", + "args": [ + "schema", + "-s", + "export-get-schema" + ] + } + } + }, + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/ExportSchemaEmbedded", + "version": "0.1.0", + "description": "Test resource for export specific schema", + "export": { + "executable": "dsctest", + "args": [ + "export-schema", + { + "jsonInputArg": "--input", + "mandatory": true + } + ], + "schema": { + "embedded": { + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://example.com/export-schema", + "title": "Export Schema", + "type": "object", + "properties": { + "name": { + "type": "string", + "title": "Export Property", + "description": "Can contain wildcards for export filtering." + } + } + } + } + }, + "schema": { + "command": { + "executable": "dsctest", + "args": [ + "schema", + "-s", + "export-get-schema" + ] + } + } + }, + { + "$schema": "https://aka.ms/dsc/schemas/v3/bundled/resource/manifest.json", + "type": "Test/ExportSchemaNoFiltering", + "version": "0.1.0", + "description": "Test resource for export specific schema", + "export": { + "executable": "dsctest", + "args": [ + "export-schema", + { + "jsonInputArg": "--input", + "mandatory": true + } + ], + "schema": "noFiltering" + }, + "schema": { + "command": { + "executable": "dsctest", + "args": [ + "schema", + "-s", + "export-get-schema" + ] + } + } } ] } diff --git a/tools/dsctest/src/args.rs b/tools/dsctest/src/args.rs index 0e681e27e..a0b28ec59 100644 --- a/tools/dsctest/src/args.rs +++ b/tools/dsctest/src/args.rs @@ -11,6 +11,8 @@ pub enum Schemas { Exist, ExitCode, Export, + ExportGetSchema, + ExportSchema, Exporter, Get, InDesiredState, @@ -95,6 +97,12 @@ pub enum SubCommand { input: String, }, + #[clap(name = "export-schema", about = "Test export specific schema")] + ExportSchema { + #[clap(name = "input", short, long, help = "The input to the export schema command as JSON")] + input: String, + }, + #[clap(name = "exporter", about = "Exports different types of resources")] Exporter { #[clap(name = "input", short, long, help = "The input to the exporter command as JSON")] diff --git a/tools/dsctest/src/export_schema.rs b/tools/dsctest/src/export_schema.rs new file mode 100644 index 000000000..3318dbf07 --- /dev/null +++ b/tools/dsctest/src/export_schema.rs @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use std::fmt::Display; + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +pub enum Names { + Gijs, + Steve, + Tess, +} + +impl Display for Names { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Names::Gijs => write!(f, "Gijs"), + Names::Steve => write!(f, "Steve"), + Names::Tess => write!(f, "Tess"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct Schema { + pub name: Names, +} + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct ExportSchema { + pub name: String, +} + +pub fn invoke_export_schema(input: &str) -> String { + let instances = vec![ + Schema { + name: Names::Steve, + }, + Schema { + name: Names::Tess, + }, + Schema { + name: Names::Gijs, + }, + ]; + let filter: ExportSchema = if !input.is_empty() { + match serde_json::from_str(input) { + Ok(filter) => filter, + Err(err) => { + eprintln!("Error JSON does not match schema: {err}"); + std::process::exit(1); + } + } + } else { + ExportSchema { + name: "*".to_string(), + } + }; + let filtered_instances: Vec = if filter.name.contains("*") { + // convert the wildcard to a regex + let regex = filter.name.replace("*", ".*"); + let regex = regex::Regex::new(®ex).unwrap(); + instances + .into_iter() + .filter(|instance| regex.is_match(&instance.name.to_string())) + .collect() + } else { + instances + .into_iter() + .filter(|instance| instance.name.to_string() == filter.name) + .collect() + }; + let mut output = String::new(); + let mut count = filtered_instances.len(); + for instance in &filtered_instances { + output.push_str(serde_json::to_string(instance).unwrap().as_str()); + if count > 1 { + output.push('\n'); + } + count -= 1; + } + output +} diff --git a/tools/dsctest/src/main.rs b/tools/dsctest/src/main.rs index 060d07969..39decf60e 100644 --- a/tools/dsctest/src/main.rs +++ b/tools/dsctest/src/main.rs @@ -7,6 +7,7 @@ mod delete; mod exist; mod exit_code; mod export; +mod export_schema; mod exporter; mod get; mod in_desired_state; @@ -31,6 +32,7 @@ use crate::delete::Delete; use crate::exist::{Exist, State}; use crate::exit_code::ExitCode; use crate::export::Export; +use crate::export_schema::{ExportSchema, invoke_export_schema}; use crate::exporter::{Exporter, Resource}; use crate::get::Get; use crate::in_desired_state::InDesiredState; @@ -132,6 +134,9 @@ fn main() { } String::new() }, + SubCommand::ExportSchema { input } => { + invoke_export_schema(&input) + }, SubCommand::Exporter { input } => { let exporter = match serde_json::from_str::(&input) { Ok(exporter) => exporter, @@ -300,6 +305,12 @@ fn main() { Schemas::Export => { schema_for!(Export) }, + Schemas::ExportGetSchema => { + schema_for!(export_schema::Schema) + }, + Schemas::ExportSchema => { + schema_for!(ExportSchema) + }, Schemas::Exporter => { schema_for!(Exporter) }, From 653fe93e2b311523453e55b35af93e005594ef62 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 9 Jun 2026 21:28:41 -0700 Subject: [PATCH 2/6] remove unused text --- lib/dsc-lib/locales/en-us.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/dsc-lib/locales/en-us.toml b/lib/dsc-lib/locales/en-us.toml index 6603fe6fb..83316a729 100644 --- a/lib/dsc-lib/locales/en-us.toml +++ b/lib/dsc-lib/locales/en-us.toml @@ -193,7 +193,6 @@ exportNotSupportedUsingGet = "Export is not supported by resource '%{resource}' runProcessError = "Failed to run process '%{executable}': %{error}" whatIfWarning = "Resource '%{resource}' uses deprecated 'whatIf' operation. See https://github.com/PowerShell/DSC/issues/1361 for migration information." securityContextRequired = "Operation '%{operation}' for resource '%{resource}' requires security context '%{context}'" -exportNoFilteringWithInput = "Resource '%{resource}' does not support filtering export results and input was provided" [dscresources.dscresource] invokeGet = "Invoking get for '%{resource}'" From 0d871881cc007a5afda8f2aa33f1c698e0a04b91 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Tue, 9 Jun 2026 21:29:32 -0700 Subject: [PATCH 3/6] no need for helper to be public --- lib/dsc-lib/src/dscresources/command_resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index cf3568e84..d2c43775d 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -616,7 +616,7 @@ pub fn get_schema(resource: &DscResource, target_resource: Option<&DscResource>) } } -pub fn get_export_schema(resource: &DscResource, target_resource: Option<&DscResource>) -> Result { +fn get_export_schema(resource: &DscResource, target_resource: Option<&DscResource>) -> Result { let Some(manifest) = &resource.manifest else { return Err(DscError::MissingManifest(resource.type_name.to_string())); }; From 9976977cb264a05d42fabb45ec7df4866626c96a Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 10 Jun 2026 10:07:38 -0700 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tools/dsctest/dsctest.dsc.manifests.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/dsctest/dsctest.dsc.manifests.json b/tools/dsctest/dsctest.dsc.manifests.json index 8c2346003..446c28655 100644 --- a/tools/dsctest/dsctest.dsc.manifests.json +++ b/tools/dsctest/dsctest.dsc.manifests.json @@ -1462,13 +1462,17 @@ "$id": "http://example.com/export-schema", "title": "Export Schema", "type": "object", + "additionalProperties": false, "properties": { "name": { "type": "string", "title": "Export Property", "description": "Can contain wildcards for export filtering." } - } + }, + "required": [ + "name" + ] } } }, From e00cba3e7703210b0fecde993db4450833d35f64 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 10 Jun 2026 14:17:27 -0700 Subject: [PATCH 5/6] fix use of `validate` for export --- .../src/dscresources/command_resource.rs | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index d2c43775d..740e0984c 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -616,15 +616,30 @@ pub fn get_schema(resource: &DscResource, target_resource: Option<&DscResource>) } } -fn get_export_schema(resource: &DscResource, target_resource: Option<&DscResource>) -> Result { +fn verify_with_export_schema(input: &str, resource: &DscResource, target_resource: Option<&DscResource>) -> Result<(), DscError> { let Some(manifest) = &resource.manifest else { return Err(DscError::MissingManifest(resource.type_name.to_string())); }; + + if manifest.validate.is_some() { + let result = invoke_validate(resource, input, target_resource)?; + if result.valid { + return Ok(()); + } + + let reason = result + .reason + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| t!("dscresources.commandResource.resourceInvalidJson").to_string()); + return Err(DscError::Validation(reason)); + } + let Some(export) = manifest.export.as_ref() else { return Err(DscError::SchemaNotAvailable(resource.type_name.to_string())); }; - match export.schema { + let schema = match export.schema { Some(ExportSchemaKind::Command(ref command)) => { let resource_type = match target_resource { Some(r) => r.type_name.clone(), @@ -632,16 +647,27 @@ fn get_export_schema(resource: &DscResource, target_resource: Option<&DscResourc }; let args = process_schema_args(command.args.as_ref(), &CommandResourceInfo { type_name: resource_type, path: None }); let (_exit_code, stdout, _stderr) = invoke_command(&command.executable, args, None, Some(&resource.directory), None, manifest.exit_codes.as_ref())?; - Ok(stdout) + stdout }, Some(ExportSchemaKind::Embedded(ref schema)) => { - let json = serde_json::to_string(schema)?; - Ok(json) + serde_json::to_string(schema)? }, _ => { - get_schema(resource, target_resource) + get_schema(resource, target_resource)? } + }; + let schema = serde_json::from_str(&schema)?; + let compiled_schema = match Validator::new(&schema) { + Ok(schema) => schema, + Err(e) => { + return Err(DscError::Schema(e.to_string())); + }, + }; + let json: Value = serde_json::from_str(input)?; + if let Err(err) = compiled_schema.validate(&json) { + return Err(DscError::Schema(err.to_string())); } + Ok(()) } /// Invoke the export operation on a resource @@ -707,18 +733,7 @@ pub fn invoke_export(resource: &DscResource, input: Option<&str>, target_resourc input }; if !input.is_empty() { - let schema = serde_json::from_str(&get_export_schema(resource, target_resource)?)?; - let compiled_schema = match Validator::new(&schema) { - Ok(schema) => schema, - Err(e) => { - return Err(DscError::Schema(e.to_string())); - }, - }; - let json: Value = serde_json::from_str(input)?; - if let Err(err) = compiled_schema.validate(&json) { - return Err(DscError::Schema(err.to_string())); - } - + verify_with_export_schema(input, resource, target_resource)?; command_input = get_command_input(export.input.as_ref(), input)?; } From 0655b44d6c9d8b15f452553035f6402604da6b39 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Wed, 10 Jun 2026 15:10:53 -0700 Subject: [PATCH 6/6] change to fallback to validate instead of trying it first --- lib/dsc-lib/src/dscresources/command_resource.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/dsc-lib/src/dscresources/command_resource.rs b/lib/dsc-lib/src/dscresources/command_resource.rs index 740e0984c..93701df60 100644 --- a/lib/dsc-lib/src/dscresources/command_resource.rs +++ b/lib/dsc-lib/src/dscresources/command_resource.rs @@ -621,7 +621,11 @@ fn verify_with_export_schema(input: &str, resource: &DscResource, target_resourc return Err(DscError::MissingManifest(resource.type_name.to_string())); }; - if manifest.validate.is_some() { + let Some(export) = manifest.export.as_ref() else { + return Err(DscError::SchemaNotAvailable(resource.type_name.to_string())); + }; + + if export.schema.is_none() && manifest.validate.is_some() { let result = invoke_validate(resource, input, target_resource)?; if result.valid { return Ok(()); @@ -635,10 +639,6 @@ fn verify_with_export_schema(input: &str, resource: &DscResource, target_resourc return Err(DscError::Validation(reason)); } - let Some(export) = manifest.export.as_ref() else { - return Err(DscError::SchemaNotAvailable(resource.type_name.to_string())); - }; - let schema = match export.schema { Some(ExportSchemaKind::Command(ref command)) => { let resource_type = match target_resource {