Skip to content

Use JSON Schema defaults in synthetic test get_diff - #1670

Open
Steve Lee (SteveL-MSFT) wants to merge 4 commits into
mainfrom
stevel-msft-synthetic-test-schema-default
Open

Use JSON Schema defaults in synthetic test get_diff#1670
Steve Lee (SteveL-MSFT) wants to merge 4 commits into
mainfrom
stevel-msft-synthetic-test-schema-default

Conversation

@SteveL-MSFT

@SteveL-MSFT Steve Lee (SteveL-MSFT) commented Aug 11, 2026

Copy link
Copy Markdown
Member

Motivation

When a DSC resource does not implement the test operation, the engine performs a synthetic test by calling get and comparing expected vs actual state using get_diff(). Previously, if a property existed in the expected (desired) state but was missing from the actual (get) output, it was always reported as differing -- even if the resource simply omits properties whose values match the schema-defined default.

This causes false positives in synthetic test results. The most impactful case is Microsoft.Windows/FirewallRuleList where unspecifiedRulesAction is a write-only instruction that get never returns. Setting it to "ignore" (the documented default) permanently reports drift, making the property unusable for compliance reporting.

Approach

  • Introduced get_diff_with_schema(expected, actual, schema) which accepts an optional JSON Schema. When a property is in expected but absent from actual, the function looks up the schema's default value for that property. If the expected value matches the default, it is not flagged as a diff.
  • The existing get_diff(expected, actual) remains as a convenience wrapper (passes None for the schema), so all non-synthetic-test call sites are unaffected.
  • Both synthetic test paths (command resources and adapted resources) now retrieve the resource schema and pass it to the new function.
  • Schema is read directly from the RESOURCE_SCHEMAS cache (avoiding redundant serialization), with a fallback to get_schema() to populate the cache on a miss.

Test coverage

  • Rust unit tests (6 new): Cover matching/mismatching schema defaults for booleans and integers, missing defaults, and the no-schema fallback.
  • Pester integration tests (7 new): End-to-end validation using a new Test/SchemaDefault resource.
  • FirewallRuleList Pester tests (4 new): Verify that unspecifiedRulesAction: ignore no longer causes false drift, while non-default values (disable, remove) are still correctly reported.
  • Verified existing dsc_resource_test.tests.ps1 tests still pass with no regressions.

Fixes #1666

Update get_diff() to accept an optional JSON Schema parameter via the new
get_diff_with_schema() function. When a property exists in the expected
(desired) state but is missing from the actual state, the function now
checks the schema for a 'default' value for that property. If the expected
value matches the schema default, it is not reported as differing.

This improves synthetic test accuracy for resources that don't return
properties whose values match the schema-defined defaults.

- Add get_diff_with_schema() with optional schema parameter
- Keep get_diff() as a convenience wrapper (no schema)
- Update invoke_synthetic_test to retrieve and pass the resource schema
- Update DscResource synthetic test path for adapted resources
- Add get_schema_default() helper to extract defaults from JSON Schema
- Add Test/SchemaDefault test resource and dsctest subcommand
- Add Rust unit tests for schema default comparison logic
- Add Pester integration tests for end-to-end validation

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds schema-aware diffing for synthetic dsc resource test (when a resource lacks a native test operation), so missing properties in get output don’t produce false diffs when the desired value matches the JSON Schema default.

Changes:

  • Introduces get_diff_with_schema(expected, actual, schema) and a helper to read per-property schema defaults when actual omits a key.
  • Updates synthetic test paths (command + adapted resources) to retrieve the resource schema and pass it into diffing.
  • Adds new Rust + Pester tests, including a Test/SchemaDefault resource that omits defaulted fields from get output.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tools/dsctest/src/schema_default.rs Adds a dsctest input struct for the new schema-default test resource.
tools/dsctest/src/main.rs Adds schema-default subcommand and exposes its JSON schema via dsctest schema.
tools/dsctest/src/args.rs Wires new clap subcommand and schema enum variant.
tools/dsctest/dsctest.dsc.manifests.json Adds Test/SchemaDefault manifest with embedded schema defaults.
lib/dsc-lib/src/dscresources/dscresource.rs Adds schema-aware diffing and unit tests for default handling.
lib/dsc-lib/src/dscresources/command_resource.rs Passes resource schema into synthetic test diffing.
dsc/tests/dsc_schema_default.tests.ps1 Adds end-to-end tests verifying schema defaults are honored in synthetic tests.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread lib/dsc-lib/src/dscresources/dscresource.rs Outdated
Comment thread lib/dsc-lib/src/dscresources/command_resource.rs Outdated
…ation

- Change get_diff_with_schema from pub to pub(crate) since it is only
  used within the dsc-lib crate
- Read schema from RESOURCE_SCHEMAS cache directly (returns Value) instead
  of round-tripping through get_schema -> String -> from_str. Only calls
  get_schema to populate the cache on a miss.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add tests verifying that unspecifiedRulesAction set to the schema default
value 'ignore' is no longer reported as drift in synthetic test. Non-default
values ('disable', 'remove') are still correctly flagged.

Tests require elevation to create/remove firewall rules and are skipped
when not running as Administrator.

Fixes #1666

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown

😁 Code Coverage Report

Changed Code Coverage

90% (90%+ coverage)

Metric Value
Changed lines analyzed 86
Lines covered by tests 78
Coverage percentage 90%

🔵 Full Codebase Coverage

82% (good)

Metric Value
Total executable lines 18735
Lines covered by tests 15424
Coverage percentage 82%

Changed code coverage measures only Rust lines added/modified in this PR.
Full codebase coverage measures all instrumented Rust lines across the project.

…available

Move -Skip to Describe block and check for Get-NetFirewallRule cmdlet
availability in BeforeDiscovery. This prevents BeforeAll/AfterAll from
running on CI runners without the NetSecurity module.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Microsoft.Windows/FirewallRuleList: unspecifiedRulesAction is always reported as drift, so test and set never converge

2 participants