Repository navigation
(GH-579) Add dsclint executable - #1768
Draft
Gijs Reijn (Gijsreyn) wants to merge 6 commits into
Draft
Gijs Reijn (Gijsreyn) wants to merge 6 commits into
Gijs Reijn (Gijsreyn) wants to merge 6 commits into
Conversation
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Secure values can leak into diagnostics and logs, and validation mismatches produce incorrect lint results.
11 open issues
Redact secure values from lint trace logging · New Redact secure defaults from parser diagnostics · New Add or track the missing lint server API · New Correct secure output lint documentation and behavior · New Analyze embedded Group configurations in separate contexts · New Avoid recursive parsing in runtime root-only scopes · New Resolve references against evaluated resource names · New Unescape literal defaults before constraint validation · New Reject wrapped supplied secureString values · New Handle schema combinators with unknown expression values · New Validate escaped literals against runtime values · New
What changed in this PR
Adds dsc lint to detect configuration problems before execution, including duplicate resources and system-root usage checks requested in #842 and #591.
Changes:
- Adds configurable lint rules, structured diagnostics, discovery checks, and failure thresholds.
- Shares parsing and validation helpers with runtime code.
- Adds schemas, documentation, localization, and automated tests.
| File | Description |
|---|---|
| xtask/src/schemas/export.rs | Registers lint schemas for export. |
| lib/dsc-lib/tests/integration/schemas/schema_for.rs | Tests lint schema generation. |
| lib/dsc-lib/src/util.rs | Adds JSON/YAML value parsing. |
| lib/dsc-lib/src/parser/mod.rs | Adds parse-only expression support. |
| lib/dsc-lib/src/parser/functions.rs | Exposes function arguments. |
| lib/dsc-lib/src/parser/expressions.rs | Exposes expression structure. |
| lib/dsc-lib/src/lint/rules/resource.rs | Adds discovery-dependent resource checks. |
| lib/dsc-lib/src/lint/rules/parameter.rs | Adds parameter and variable checks. |
| lib/dsc-lib/src/lint/rules/mod.rs | Collects lint rules. |
| lib/dsc-lib/src/lint/rules/expression.rs | Adds expression validation rules. |
| lib/dsc-lib/src/lint/rules/environment.rs | Checks system-root usage and paths. |
| lib/dsc-lib/src/lint/rules/document.rs | Checks document structure and duplicates. |
| lib/dsc-lib/src/lint/rules/deprecation.rs | Checks deprecated and unsupported features. |
| lib/dsc-lib/src/lint/rules/dependency.rs | Checks dependencies and references. |
| lib/dsc-lib/src/lint/rule.rs | Defines rules and diagnostic collection. |
| lib/dsc-lib/src/lint/pointer.rs | Adds JSON pointer utilities. |
| lib/dsc-lib/src/lint/options.rs | Defines lint options and settings. |
| lib/dsc-lib/src/lint/expression_index.rs | Indexes expressions for rule evaluation. |
| lib/dsc-lib/src/lint/diagnostic.rs | Defines diagnostics and combined results. |
| lib/dsc-lib/src/lint/context.rs | Provides shared rule context. |
| lib/dsc-lib/src/lib.rs | Exposes the lint module. |
| lib/dsc-lib/src/functions/mod.rs | Adds non-executing argument validation. |
| lib/dsc-lib/src/dscresources/dscresource.rs | Collects all schema violations. |
| lib/dsc-lib/src/dscerror.rs | Integrates lint errors. |
| lib/dsc-lib/src/configure/mod.rs | Shares adapter-directive lookup. |
| lib/dsc-lib/locales/schemas.outputs.yaml | Describes lint output schemas. |
| lib/dsc-lib/locales/en-us.toml | Adds lint diagnostic messages. |
| dsc/tests/dsc_lint.tests.ps1 | Adds CLI lint coverage. |
| dsc/src/util.rs | Adds raw input reading and schemas. |
| dsc/src/subcommand.rs | Implements lint command handling. |
| dsc/src/main.rs | Dispatches lint and shares parameter merging. |
| dsc/src/args.rs | Defines lint arguments and schema options. |
| dsc/locales/en-us.toml | Adds CLI help and messages. |
| dsc/dsc.settings.json | Adds lint settings. |
| dsc/dsc_default.settings.json | Adds default lint settings. |
| docs/reference/schemas/outputs/lint/rules.md | Documents rule metadata output. |
| docs/reference/schemas/outputs/lint/result.md | Documents lint results. |
| docs/reference/cli/lint/rules.md | Documents the rule catalog. |
| docs/reference/cli/lint/index.md | Documents command usage and settings. |
| docs/reference/cli/index.md | Links the lint command reference. |
| CHANGELOG.md | Records the new capability. |
Review effort: Balanced
…in/add-dsc-lint-command # Conflicts: # dsc/src/subcommand.rs # xtask/src/schemas/export.rs
dsc lint commanddsclint executable
Collaborator
Author
|
Steve Lee (@SteveL-MSFT) - I converted it to a |
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Source snippets can expose secure values, output errors can be attributed to valid input, and empty documents bypass structured lint results.
5 open issues
11 resolved since last review
Redact secure defaults from parser diagnostics Redact secure values from lint trace logging Validate escaped literals against runtime values Handle schema combinators with unknown expression values Reject wrapped supplied secureString values Unescape literal defaults before constraint validation Resolve references against evaluated resource names Avoid recursive parsing in runtime root-only scopes Analyze embedded Group configurations in separate contexts Correct secure output lint documentation and behavior Add or track the missing lint server API
Review effort: Balanced
| return DscError::SchemaValidation(schema_error); | ||
| }; | ||
| let base = format!("/resources/{index}/properties"); | ||
| DscError::SchemaValidation(Box::new(schema_error.with_source(&source.text, &source.name, &base))) |
| }); | ||
| if holds_secure_value { | ||
| error = error.redacted(&t!("dscresources.commandResource.redactedSchemaErrorMessage")); | ||
| } else if let Ok(text) = serde_json::to_string_pretty(json) { |
| let first_line_end = map.text()[span.clone()].find('\n').map_or(span.end, |offset| span.start + offset); | ||
| let span = span.start..first_line_end.max(span.start); | ||
| let name = diagnostic.file.clone().unwrap_or_else(|| t!("lint.report.inputSourceName").to_string()); | ||
| Some((NamedSource::new(name, map.text().to_string()), LabeledSpan::new(None, span.start, span.len()))) |
| documents.push((None, read_input(Some(input), None)?)); | ||
| } | ||
| for file in &args.file { | ||
| let document = read_input(None, Some(file))?; |
Comment on lines
+623
to
+624
| let base = format!("/resources/{index}/properties"); | ||
| DscError::SchemaValidation(Box::new(schema_error.with_source(&source.text, &source.name, &base))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


PR Summary
This change:
dsclintexecutable. It checks a configuration document for problems without applyingit, reads one or more files or an inline document, and always writes a result with the
diagnostics, a summary, whether the document is valid, and whether discovery ran. It exits with
code 5 when a diagnostic reaches the level set by the fail-on option, which defaults to error.
schema and reports every violation with its JSON pointer, then indexes every expression once and
runs 43 rules across seven categories plus four fixed rules for parse, schema, unsupported
document type, and discovery failures. Rule levels can be changed per run or in a new lint
section of the settings file, with the policy file taking precedence.
the expression parser, argument-count and argument-kind checks on the function dispatcher
extracted from invoke, a schema validator that returns every violation instead of the first, and
a raw-text input reader in the CLI so a syntax error becomes a diagnostic instead of an early
exit. Parameter merging and parameter parsing move into helpers shared by the config and lint
commands.
integration test, and adds reference docs, a rules catalog, a changelog entry, 68 Rust unit
tests, and 43 Pester tests including a sweep of the shipped examples.
PR Context
DSC only finds most document mistakes when it runs the document. The hidden validate subcommand
is only called by the Group, Assertion and Include resources, reports a bare boolean, exits zero
even when invalid, and discovers resources before validating anything. Mistakes such as a
dependency on a resource that doesn't exist, a reference to a resource that hasn't run, a
condition written as a plain string, or a secure parameter with a hard-coded default are reported
late, without a location, or not at all.
Remarks on the design
skip it. Rules that depend on discovery report warnings rather than errors, so a build agent
without the resources still passes. The linter never invokes a resource; property checks only
use the schema embedded in the manifest.
pipeline always has something to show. The valid flag doesn't depend on the fail-on level.
JSON parsers keep no positions for values. The location field is in the schema from the start so
adding positions later isn't a breaking change.
rule exists because DSC doesn't auto-order on references the way ARM does. Duplicate and
dependency rules skip copy loops, whose names are only known at runtime. Secure default values
are never echoed in messages.