Skip to content

[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
Azure:mainfrom
coopercox-ms:users/coopercox/az-validate
Open

Cooper Cox (coopercox-ms) wants to merge 2 commits into
Azure:mainfrom
coopercox-ms:users/coopercox/az-validate

Conversation

@coopercox-ms

Copy link
Copy Markdown
Member

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

  • Input: --command (one or more commands), --script (script text) or --file (a script file; .ps1/.psm1 are read as PowerShell, other files as Bash). Scripts are tokenised, never run: variables and $(...) are treated as placeholders, and az commands inside $(...), loops, if blocks and pipelines are found and checked.
  • Core and installed-extension commands are parsed with the installed CLI's own parser, so results match the installed version and need no network. Commands from extensions that aren't installed are checked against the published command metadata (two public, read-only endpoints; cached for 12 hours; --offline turns downloads off).
  • Placeholders (<rg>, $RG, "$(az ...)", @file) count as valid values and are listed; real values are checked.
  • Output: one JSON document (schemaVersion 1.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-file also 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, @file and 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 only validate. Each rule has a test through get_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 MetadataLimits note.


This checklist is used to make sure that common guidelines for a pull request are followed.

Related command

az validate

General Guidelines

  • Have you run azdev style <YOUR_EXT> locally? (pip install azdev required)
    azdev style validate and azdev linter validate pass. azdev test validate: 68 passed with azure-cli 2.91.0 and dev; the same tests pass on Linux and on 2.86.0, the minimum version.
  • Have you run python scripts/ci/test_index.py -q locally? (pip install azdev required)
    Passed (9 tests, 2 skipped outside CI).
  • My extension version conforms to the Extension version schema

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.json automatically.
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.

… 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.
@yonzhan

Copy link
Copy Markdown
Collaborator

az validate

@coopercox-ms
Cooper Cox (coopercox-ms) marked this pull request as ready for review October 13, 2026 03:27
Copilot AI balanced review requested due to automatic review settings October 13, 2026 03:27

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.

🟡 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)])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants