feat: add azd exec — run commands and scripts with azd environment context#7400
feat: add azd exec — run commands and scripts with azd environment context#7400jongio wants to merge 3 commits intoAzure:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds the first-party microsoft.azd.exec extension to the azure-dev repo, enabling azd exec to run scripts/inline commands with azd environment context and optional Key Vault secret resolution, plus MCP tooling. It also introduces/extends Key Vault reference parsing and host-side secret resolution so extensions receive resolved env vars.
Changes:
- Introduces the
cli/azd/extensions/microsoft.azd.execextension module (cobra command, executor, MCP server, skills, build scripts, metadata). - Adds Key Vault secret reference parsing/resolution helpers in core (
pkg/keyvault) and a new resolver in the extension SDK (pkg/azdext). - Wires Key Vault env var resolution into extension invocation and adds CI/release pipeline + registry/workflow entries for the new extension.
Reviewed changes
Copilot reviewed 31 out of 32 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| eng/pipelines/release-ext-microsoft-azd-exec.yml | Adds ADO release pipeline definition for the new extension. |
| .github/workflows/lint-ext-microsoft-azd-exec.yml | Adds GitHub Actions lint workflow scoped to the new extension module. |
| cli/azd/cmd/extensions.go | Resolves Key Vault secret references in azd-managed env vars before invoking extensions. |
| cli/azd/pkg/keyvault/keyvault.go | Adds support for @Microsoft.KeyVault(SecretUri=...) parsing + unified reference resolution + env var list resolver. |
| cli/azd/pkg/keyvault/keyvault_test.go | Adds unit tests for new reference parsing and env var secret resolution behavior. |
| cli/azd/pkg/cmdsubst/cmdsubst_additional_test.go | Updates KeyVaultService mock to satisfy the expanded interface. |
| cli/azd/pkg/azdext/keyvault_resolver.go | Adds SDK-side Key Vault resolver supporting multiple reference formats and caching. |
| cli/azd/pkg/azdext/keyvault_resolver_test.go | Adds comprehensive resolver tests (parsing, error classification, concurrency, env/map helpers). |
| cli/azd/extensions/registry.json | Registers the new microsoft.azd.exec extension (id/namespace/version/capabilities). |
| cli/azd/extensions/microsoft.azd.exec/version.txt | Introduces extension version tracking (0.5.0). |
| cli/azd/extensions/microsoft.azd.exec/README.md | Adds end-user docs for install/usage/features of azd exec. |
| cli/azd/extensions/microsoft.azd.exec/main.go | Adds extension entrypoint and error rendering. |
| cli/azd/extensions/microsoft.azd.exec/go.mod | Adds Pattern B module for the extension with replace to core azd module. |
| cli/azd/extensions/microsoft.azd.exec/go.sum | Adds extension module dependency lockfile. |
| cli/azd/extensions/microsoft.azd.exec/extension.yaml | Defines extension metadata/capabilities and MCP serve args/env mapping. |
| cli/azd/extensions/microsoft.azd.exec/.golangci.yaml | Adds extension-specific golangci-lint configuration. |
| cli/azd/extensions/microsoft.azd.exec/CHANGELOG.md | Adds initial changelog for the extension. |
| cli/azd/extensions/microsoft.azd.exec/build.sh | Adds cross-platform build script for producing extension binaries. |
| cli/azd/extensions/microsoft.azd.exec/build.ps1 | Adds PowerShell cross-platform build script for producing extension binaries. |
| cli/azd/extensions/microsoft.azd.exec/ci-build.ps1 | Adds CI build wrapper for the extension (flags/tags/ldflags). |
| cli/azd/extensions/microsoft.azd.exec/internal/cmd/root.go | Implements azd exec root command wiring, flags, env loading, and subcommands. |
| cli/azd/extensions/microsoft.azd.exec/internal/cmd/root_test.go | Adds basic tests for root/version command construction. |
| cli/azd/extensions/microsoft.azd.exec/internal/cmd/version.go | Implements version subcommand output. |
| cli/azd/extensions/microsoft.azd.exec/internal/cmd/mcp.go | Implements hidden MCP server command and tool handlers (exec/list shells/env). |
| cli/azd/extensions/microsoft.azd.exec/internal/cmd/mcp_test.go | Adds unit tests for MCP handlers, validation, and helper functions. |
| cli/azd/extensions/microsoft.azd.exec/internal/executor/executor.go | Implements script/inline execution and env preparation with optional Key Vault resolution. |
| cli/azd/extensions/microsoft.azd.exec/internal/executor/command_builder.go | Builds shell-specific exec command lines (including PowerShell quoting). |
| cli/azd/extensions/microsoft.azd.exec/internal/executor/command_builder_test.go | Adds tests for command construction and PowerShell arg quoting. |
| cli/azd/extensions/microsoft.azd.exec/internal/executor/errors.go | Adds typed executor errors (validation/shell/exit code). |
| cli/azd/extensions/microsoft.azd.exec/internal/executor/errors_test.go | Adds tests validating error messages and config validation. |
| cli/azd/extensions/microsoft.azd.exec/internal/skills/skills.go | Implements embedded Copilot skill installation to ~/.copilot/skills/azd-exec. |
| cli/azd/extensions/microsoft.azd.exec/internal/skills/azd-exec/SKILL.md | Adds embedded skill definition/documentation for the extension. |
cli/azd/extensions/microsoft.azd.exec/internal/executor/executor.go
Outdated
Show resolved
Hide resolved
cli/azd/extensions/microsoft.azd.exec/internal/skills/azd-exec/SKILL.md
Outdated
Show resolved
Hide resolved
cli/azd/extensions/microsoft.azd.exec/internal/skills/azd-exec/SKILL.md
Outdated
Show resolved
Hide resolved
81565b7 to
b721a0a
Compare
|
Dependent on #7314 |
Known Issue: Environment Value MungingWhen azd core already passes env vars directly to the extension process environment, so this roundtrip is only needed when PR #7314 addresses the core Tracking: depends on #7314 |
wbreza
left a comment
There was a problem hiding this comment.
Code Review — microsoft.azd.exec Extension
Good work on the clean architecture and comprehensive test coverage! A few items to consider before this is ready to merge.
What Looks Good ✅
- Clean package structure — 3 focused packages (
cmd,executor,shellutil) with clear separation of concerns - Strong error hierarchy — Typed errors enable programmatic handling and clear user messages
- Comprehensive table-driven tests — Platform-aware scaffolding, validation edge cases, and PowerShell quoting coverage
- Faithful exit code propagation — Critical for CI/CD usage, well-implemented
- Correct SDK usage —
NewExtensionRootCommand,PersistentPreRunEchain preservation,NewMetadataCommand
Summary
| Priority | Count |
|---|---|
| Critical | 0 |
| High | 2 |
| Medium | 3 |
| Low | 2 |
| Total | 7 |
Overall Assessment: Comment — see inline comments for details.
b721a0a to
b2cf453
Compare
|
How are we logging failures, preflight on the script (if needed), if the script itself fails does it use azd logs so we can report when a user has used exec and passed or failed and why Also how does this differ from hooks, pre and post? |
|
Good questions. On logging and error reporting: We're using the SDK's telemetry stack. On how this differs from hooks: Hooks are tied to azd lifecycle events. You define them in |
b2cf453 to
7cf929e
Compare
1e7bc49 to
b089007
Compare
b526874 to
a171856
Compare
wbreza
left a comment
There was a problem hiding this comment.
Code Review — microsoft.azd.exec Extension
Great extension contribution! The architecture is clean and well-thought-out — 3 focused packages with clear separation of concerns, comprehensive test coverage, and proper use of the extension SDK patterns. Looking forward to porting more extensions over to the azd official registry.
✅ What Looks Good
- Clean use of
azdext.Run()with the newWithExitCodeoption — elegant solution for exit code propagation - Thorough cmd.exe injection tests covering CWE-78 and CWE-93 edge cases
errors.AsType[*T]()used consistently throughout (Go 1.26 convention)- Security hardening flags in build scripts (
-trimpath,-buildmode=pie,-tags=cfi,cfg,osusergo) requiredAzdVersionproperly declared- Good error type hierarchy enabling programmatic handling
Summary
| Priority | Count |
|---|---|
| Critical | 0 |
| High | 0 |
| Medium | 2 |
| Low | 3 |
| Total | 5 |
Overall Assessment: Approve — well-structured extension with no blocking issues. See inline comments for minor suggestions.
cli/azd/extensions/microsoft.azd.exec/internal/executor/command_builder.go
Outdated
Show resolved
Hide resolved
cli/azd/extensions/microsoft.azd.exec/internal/executor/command_builder.go
Show resolved
Hide resolved
cli/azd/extensions/microsoft.azd.exec/internal/executor/command_builder.go
Show resolved
Hide resolved
aa57e4e to
585e164
Compare
1cc277b to
da28ca8
Compare
|
Looks like there's still some open discussion on #7423 to have this as a core feature instead of an extension |
da28ca8 to
af981a8
Compare
f8fc22f to
da7cd93
Compare
|
I think the cleanest direction here is to make direct process execution the default contract, and make Concretely, I’d prefer a v1 shape along these lines:
The reason I’m leaning this way is that it gives us a much clearer and more durable contract: “run this process with azd env injected, preserve argv exactly, return the child exit code, do not mutate the parent shell.” That seems to match the common scenarios here ( My concern with the current mixed model is not that it can’t be made to work, but that it makes the command contract harder to explain and reason about, which also applies to agents:
So my objective take is: the underlying capability is worth doing, but the mixed heuristic design is the weak part. If this graduates into a core command, I think the safest and clearest v1 is a narrow process-exec primitive, with |
wbreza
left a comment
There was a problem hiding this comment.
Code Re-Review — PR #7400
azd exec — run commands and scripts with azd environment context by @jongio
Re-review after force-push
Changes since my Apr 3 approval (aa57e4e) are trivial:
- Commit 2 (
b82c41e): Design specification document (docs only) - Commit 3 (
da7cd93): Go version bump 1.26.0→1.26.1, cspell config tweaks (4 lines)
No code logic changes. All 7 findings from my initial review remain addressed.
Prior Review: All ✅ Resolved
| # | Priority | Finding | Status |
|---|---|---|---|
| 1 | Medium | Shell validation bypass via empty --shell "" |
✅ |
| 2 | Medium | GOWORK=off in test instructions |
✅ |
| 3-7 | Low | Various minor items | ✅ |
✅ What Looks Good
- Clean architecture: 3 focused packages, no circular deps, 94% test coverage
- Proper use of
azdext.Run()withWithExitCodefor exit code propagation - Comprehensive cmd.exe injection tests (CWE-78, CWE-93)
errors.AsType[*T]()used consistently (Go 1.26)- Security hardening in build scripts
Overall Assessment: Re-approve — no logic changes since initial approval.
Review performed with GitHub Copilot CLI
|
Thanks for the detailed write-up. I've gone through each point carefully against the implementation and the DevX tradeoffs. On argv parsing (#1): The implementation uses Cobra's On inline shell cross-platform (#2): On cmd.exe surface area (#3): You're right that cmd.exe needs more handling than other shells. The implementation includes On file extension detection (#4): The detection chain (known extension -> shebang -> OS default) matches how every IDE, editor, and task runner handles this. On heuristic asymmetry (#5): The file-exists check is simple and predictable: if the first arg resolves to a file, run it as a script; otherwise execute as a command. The edge case where your CWD contains a file named On the overall shape: The tools you cite (dotenvx, doppler, op) are env-injection wrappers only. azd exec does more because the azd ecosystem spans multiple platforms and shell types. The heuristic optimizes for the common case - Actions I'll take from this:
|
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comprehensive design spec covering execution model, environment handling, security considerations, and alternatives considered. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bump microsoft.azd.exec go.mod from 1.26.0 to 1.26.1 to match repo - Add azvs, notwindows to cspell override for design-spec.md - Broaden cspell override glob to cover all extension files, not just .go Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
da7cd93 to
a263050
Compare
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
|
Adding some thoughts: I generally agree with @weikanglim's comments in #7423 on DiscoverabilityIf users don't have the extension installed, As a core command, we could also consider printing console messages or suggestion texts in various places like after Iteration speedThe iteration speed benefit of extensions is not as big now that we have weekly core releases. Extension to core graduation pathIf
|
|
We have decided to make this part of core, not an azd extension. I will be updating this PR with that new direction. |
Fixes #7520
Description
Add
azd execΓÇö a cross-platform command and script execution engine that runs programs with full azd environment context (environment variables, Key Vault secret resolution).This addresses long-standing requests for running scripts with azd env vars: #391, #1697, #2336, #4067.
Example Usage
Execution Modes
azd exec python script.pyexec.Command("python", "script.py")ΓÇö exact argv, no shellazd exec 'echo $VAR'bash -c "echo $VAR"ΓÇö shell expansion availableazd exec ./setup.shbash ./setup.shΓÇö shell detected from extensionazd exec --shell pwsh "cmd"pwsh -Command "cmd"ΓÇö explicit shellHeuristic: Multiple arguments without
--shell→ direct process execution (OS exec semantics). Single quoted argument or explicit--shell→ shell inline execution. File path → script file execution with auto-detected or explicit shell.Features
azd exec python script.pyjust worksArchitecture
3 focused internal packages, no circular dependencies, structured error types for programmatic handling.
Test Coverage
cmdexecutorshellutil23 tests passing. Table-driven tests with platform-aware scaffolding.
What's Included
cli/azd/extensions/microsoft.azd.exec/).github/workflows/lint-ext-microsoft-azd-exec.yml)eng/pipelines/release-ext-microsoft-azd-exec.yml)build.ps1,build.sh,ci-build.ps1)What's NOT Included (Follow-Up)
Dependencies
pkg/azdextSDK for extension bootstrap and gRPC clientOpen Discussion (ref: #7423)
The following items are open for broader team discussion. They don't block this PR but affect the longer-term direction:
1. Extension vs Core Command
This capability is implemented as an extension (
microsoft.azd.exec). Issue #7423 proposes a coreazd env execcommand for the same use case. The extension approach provides:The tradeoff is discoverability ΓÇö users need to install the extension. This should be evaluated based on adoption data.
2. Key Vault Secret Auto-Resolution
The azd host resolves
akvs://and@Microsoft.KeyVault(...)references before passing environment to extension subprocesses. This means child processes launched byazd execreceive materialized secrets in their environment. This is consistent with how azd hooks work today.weikanglim's concern: automatic secret materialization should be opt-in rather than implicit. If this is addressed, it should be at the host level (affecting all extensions/hooks), not the extension level. The extension has no mechanism to "un-resolve" secrets that the host already materialized.
Testing