Repository navigation
[Validate] az validate: Add new extension to check command syntax and parameters without running them - #10461
Open
Cooper Cox (coopercox-ms) wants to merge 2 commits into
Open
Cooper Cox (coopercox-ms) wants to merge 2 commits into
Cooper Cox (coopercox-ms) wants to merge 2 commits into
Conversation
… parameters without running them Add the validate extension (1.0.0b1, preview). `az validate` checks Azure CLI commands, and the az commands in Bash and PowerShell scripts, without running them: command names, parameter names, required parameters and the values the parser can check (choices, numbers, --query). Core and installed extension commands are parsed by the installed CLI; commands from extensions that aren't installed are checked against published command metadata. The result is one JSON document. It never runs the checked commands, installs extensions, signs in, prompts, or reads files named in the checked commands. Tests cover each of these through the CLI entry point.
CI agents have the azure-devops extension preinstalled, so the test's assumption that 'az devops' comes from an extension that isn't installed didn't hold there.
Collaborator
|
az validate |
Cooper Cox (coopercox-ms)
marked this pull request as ready for review
October 13, 2026 03:27
Copilot started reviewing on behalf of
Cooper Cox (coopercox-ms)
October 13, 2026 03:28
View session
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Metadata-backed options can miss absent values, and same-line commands before syntax errors are skipped.
2 open findings
What changed in this PR
Adds the preview validate extension for safely checking Azure CLI command and script syntax without execution.
Changes:
- Implements command parsing, shell scanning, metadata lookup, sandboxing, and structured output.
- Adds extensive command, metadata, shell, and safety tests.
- Adds packaging, documentation, ownership, and service metadata.
| File | Description |
|---|---|
.github/CODEOWNERS |
Assigns validate extension owners. |
src/service_name.json |
Registers az validate. |
src/validate/setup.py |
Defines extension packaging. |
src/validate/setup.cfg |
Adds package configuration. |
src/validate/README.md |
Documents installation and behavior. |
src/validate/HISTORY.rst |
Records the initial release. |
src/validate/azext_validate/__init__.py |
Defines the command loader. |
src/validate/azext_validate/azext_metadata.json |
Sets preview and minimum CLI metadata. |
src/validate/azext_validate/commands.py |
Registers az validate. |
src/validate/azext_validate/custom.py |
Implements the command entry point. |
src/validate/azext_validate/_params.py |
Defines command arguments. |
src/validate/azext_validate/_help.py |
Provides CLI help and examples. |
src/validate/azext_validate/_format.py |
Formats table output. |
src/validate/azext_validate/_engine.py |
Safely parses commands with Azure CLI. |
src/validate/azext_validate/_validator.py |
Coordinates validation and results. |
src/validate/azext_validate/_shell.py |
Tokenizes Bash and PowerShell. |
src/validate/azext_validate/_sandbox.py |
Blocks unsafe parser operations. |
src/validate/azext_validate/_extmeta.py |
Retrieves and interprets extension metadata. |
src/validate/azext_validate/tests/__init__.py |
Initializes the test package. |
src/validate/azext_validate/tests/latest/__init__.py |
Initializes latest-version tests. |
src/validate/azext_validate/tests/latest/_base.py |
Provides shared test infrastructure. |
src/validate/azext_validate/tests/latest/_fake_metadata.py |
Provides synthetic metadata responses. |
src/validate/azext_validate/tests/latest/test_validate_commands.py |
Tests validation and output behavior. |
src/validate/azext_validate/tests/latest/test_validate_metadata.py |
Tests metadata-backed validation. |
src/validate/azext_validate/tests/latest/test_validate_safety.py |
Tests safety guarantees. |
src/validate/azext_validate/tests/latest/test_validate_shell.py |
Tests script scanning. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+301
to
+302
| else: | ||
| kwargs['nargs'] = param.get('nargs', '?') if options else param.get('nargs', None) |
| syntax_error = Outcome().fail(Finding( | ||
| 'ShellSyntax', 'The {} text can\'t be parsed: {}.'.format(dialect, ex.reason), | ||
| line=ex.line, column=ex.column)) | ||
| prefix = '\n'.join(text.splitlines()[:max(ex.line - 1, 0)]) |
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.

Adds a new preview extension,
validate(1.0.0b1), with one command:az validate. It checks Azure CLI commands without running them, for example commands written by people, scripts or AI assistants.Today the only way to find a misspelled parameter, a missing required parameter or an invalid choice is to run the command. That can change resources, prompt, or, for a command from a missing extension, install the extension and run the command.
What it does
--command(one or more commands),--script(script text) or--file(a script file;.ps1/.psm1are read as PowerShell, other files as Bash). Scripts are tokenised, never run: variables and$(...)are treated as placeholders, and az commands inside$(...), loops,ifblocks and pipelines are found and checked.--offlineturns downloads off).<rg>,$RG,"$(az ...)",@file) count as valid values and are listed; real values are checked.schemaVersion1.0) with a status per command, structured error codes, parameter names, suggestions and line/column. Values from the checked command are never echoed. The exit code is 0 for invalid commands.--output-filealso writes the JSON to a file.Safety
The checked command is never run, installed, read from or prompted for: a parser subclass turns every print, exit,
@fileand dynamic-install path into data; install and run hooks are swapped for refusers; and an audit-hook sandbox blocks network, process, prompt and file access while a checked command is loaded and parsed. Telemetry records onlyvalidate. Each rule has a test throughget_default_cli().invoke(or a subprocess).Limitations
It checks syntax and parameters, not Azure state or rules a command only applies when it runs. Published metadata doesn't record which parameters are flags, so commands from uninstalled extensions get a
MetadataLimitsnote.This checklist is used to make sure that common guidelines for a pull request are followed.
Related command
az validateGeneral Guidelines
azdev style <YOUR_EXT>locally? (pip install azdevrequired)azdev style validateandazdev linter validatepass.azdev test validate: 68 passed with azure-cli 2.91.0 anddev; the same tests pass on Linux and on 2.86.0, the minimum version.python scripts/ci/test_index.py -qlocally? (pip install azdevrequired)Passed (9 tests, 2 skipped outside CI).
For new extensions:
About Extension Publish
There is a pipeline to automatically build, upload and publish extension wheels.
Once your pull request is merged into main branch, a new pull request will be created to update
src/index.jsonautomatically.You only need to update the version information in file setup.py and historical information in file HISTORY.rst in your PR but do not modify
src/index.json.