feat: add azd exec — run commands and scripts with azd environment context#7400
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. |
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
wbreza
left a comment
There was a problem hiding this comment.
Code Review — �zd exec
PR #7400 adds �zd exec, a cross-platform command/script execution engine that runs programs with full azd environment context (env vars, Key Vault secret resolution), implemented as a core command with a new pkg/exec/scripting package.
🔴 Must Fix
1. Windows Command Injection via Shell Metacharacters
- File: cli/azd/pkg/exec/scripting/command_builder.go (Windows path)
- Issue: When cmd.exe /c is used, arguments are joined into a single string. Shell metacharacters (&, |, (, )) in user-provided arguments can break out and execute arbitrary commands. E.g., �zd exec "echo test & whoami" executes both commands. The inline cmd.exe path also doesn't escape % characters (unlike the script file path), allowing %VAR% environment variable expansion.
- Contrast: The Unix path properly uses positional parameters ("", "") preventing injection.
- Suggested fix: Escape shell metacharacters on Windows inline path, matching the existing script file path behavior.
2. PR Description / Implementation Mismatch
- Issue: The PR description documents an extension at cli/azd/extensions/microsoft.azd.exec/ with build scripts, pipelines, extension.yaml, and 94.3% test coverage across extension packages. The actual diff shows a core command at cli/azd/cmd/exec.go with pkg/exec/scripting/. The design note mentions moving to core, but the description body was never updated.
- Suggested fix: Update the PR description to accurately describe the core command implementation.
🟡 Should Fix
3. Secret Exposure to Subprocesses
- File: cli/azd/cmd/exec.go (�uildChildEnv)
- Resolved Key Vault secrets are passed to child processes. While secrets aren't leaked to the parent process via os.Setenv (good), any child command can dump them with �nv or set. Consider documenting this risk or providing an opt-in mechanism for secret resolution.
4. Exit Code Propagation Complexity
- Exit codes go through a multi-layer wrap/unwrap chain: �xec.ExitError → scripting.ExecutionError → internal.ExitCodeError. This works correctly (validated by TestExecAction_ExitCodePropagation), but ensure this test runs cross-platform in CI.
5. Missing Windows %VAR% Expansion Test
- File: cli/azd/cmd/exec_test.go
- No test verifies that %WINDIR% or similar Windows-style references are not unexpectedly expanded in inline cmd.exe commands. This is the test-side companion to Finding #1.
6. Shell Detection Test Coverage
- Shell auto-detection from file extensions (.sh → bash, .ps1 → pwsh) should have explicit tests for all supported shells on each platform, including fallback behavior when a shell isn't available.
🟢 Nitpick
7. Scope Clarity — Several foundational changes (�rrors.go, main.go, �nvironment-variables.md) aren't called out in the PR description. A brief mention would help reviewers.
8. cspell Dictionary — stretchr addition is fine (testify package author), minor housekeeping.
Overall: Core architecture is sound — proper DI patterns, clean package separation in pkg/exec/scripting/, correct exit code propagation, and secrets isolated from the parent process. The Windows command injection (#1) is the key item to address.
wbreza
left a comment
There was a problem hiding this comment.
Re-Review — �zd exec (commit a1d8ecf)
The latest commit directly addresses the blocking findings from my prior review. Security fix verified, interactive mode corrected, tests improved.
Previously Flagged → Now Resolved
- ✅ Windows
%VAR%expansion (CVE-2024-24576 class) — Fixed with%→%%escaping in both file paths (buildCommand) and arguments (quoteCmdArg). Test updated to verify%%PATH%%output. - ✅ Stdin gating —
cmd.Stdinnow gated onconfig.Interactivewith parity across bothExecuteDirectandexecuteCommandpaths. - ✅ Ctrl-C in interactive mode —
CREATE_NEW_PROCESS_GROUPskipped wheninteractive=true, matching UnixSetpgidbehavior. Ctrl-C now correctly reaches the child process. - ✅ Job Object handle leak —
CloseHandleadded afterTerminateJobObjectin the kill closure. - ✅ Exit code test portability — Replaced shell-dependent
exit 42with a compiled Go binary (testdata/exit42.go), portable across all platforms.
Residual Items (non-blocking)
- 🟡 Delayed expansion
!VAR!—!characters are not escaped inquoteCmdArg. If cmd.exe has delayed expansion enabled (SetLocal EnableDelayedExpansion),!VAR!references would expand. Low practical risk (delayed expansion is off by default), but worth a follow-up. - 🟡 Exit code test coverage — The updated test exercises
ExecuteDirect(direct binary path) but not the fullexecAction.Run()→ shell-dispatch path. Consider adding a companion test for shell-wrapped exit code propagation. - 🟡 PR description — Still describes the extension architecture (
cli/azd/extensions/microsoft.azd.exec/). Should be updated to reflect the core command implementation.
Verdict
Approve — The blocking security vulnerability is resolved with correct escaping. Interactive mode, process tree management, and test portability are all properly addressed. Remaining items are improvements, not blockers.
wbreza
left a comment
There was a problem hiding this comment.
Re-Approval — azd exec (commit 718e8c6)
Single new commit since last approval: adds //nolint:gosec // G204 to the test build command in exec_test.go. This is a standard lint suppression for a known test fixture — no functional or security impact.
Standing approval unchanged. Previously noted non-blocking items remain:
- Delayed expansion
!VAR!unescaped (low practical risk — off by default) - Exit code test covers
ExecuteDirectonly, not shell-dispatch path - PR description still describes extension architecture
Move the microsoft.azd.exec extension into azd-core as a built-in top-level command. This provides 'azd exec' for running commands and scripts with full azd environment context, including automatic Key Vault secret resolution for both akvs:// and @Microsoft.KeyVault references. Three execution modes (selected by heuristic): - Direct exec: azd exec python script.py (exact argv, no shell) - Shell inline: azd exec 'echo \' (shell expansion) - Script file: azd exec ./setup.sh (shell auto-detected from ext) New packages: - pkg/exec/scripting/ — execution engine, shell detection, command builder with Windows cmd.exe CmdLine override - cmd/exec.go — ActionDescriptor command with --shell/-s, --interactive/-i flags and IoC-injected environment + keyvault Resolves design decisions from Issue Azure#7423: - D1: Top-level 'azd exec' (not 'azd env exec') - D2: Stable GA (not beta) - D3: Automatic secret resolution (matches hooks behavior) - D4: In-process env loading via IoC Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add cmd/exec_test.go with 6 tests covering: - Environment variable injection from azd env - Key Vault secret reference resolution (akvs://) - Secret resolution failure error propagation - Invalid shell validation - Direct exec mode with multiple args - Command metadata (Use, Args validator, flag parsing) Update docs/environment-variables.md with azd exec section documenting execution modes (script file, direct exec, shell inline), flags, and automatic Key Vault secret resolution behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…dleware cleanup - Add ExitCodeError type to internal/errors.go for custom exit codes - Update main.go to extract exit code from ExitCodeError instead of hardcoded 1 - Replace os.Exit(exitCode) in exec action with returning ExitCodeError - Fix potential panic in logDebugInfo when cmdArgs is empty - Make ValidShells unexported to prevent external mutation; add IsSupportedShell() - Add test for @Microsoft.KeyVault reference format resolution - Add test for exit code propagation via ExitCodeError Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address findings from adversarial security review:
- F1+F4+F7: Replace os.Setenv with scoped child env slice passed via
Config.Env. Secrets never leak into the parent process or telemetry
subprocesses. Extract buildChildEnv() as a testable method.
- F5: Escape embedded double-quotes in scriptOrPath for cmd.exe file
execution to prevent injection via script.bat\" & calc & \"x.
- F8: Guard ExitCodeError{ExitCode:0} in main.go — only override the
default exit code 1 when ExitCode is non-zero, preventing silent
success on Windows TerminateProcess edge cases.
- F12: Replace partial controlCharReplacer (7 of 33 chars) with
stripControlChars() that removes all ASCII control chars 0x00-0x1F
and 0x7F using strings.Map.
- F13: Combine containsPrintable() with TrimSpace check in
ExecuteInline to reject both whitespace-only and control-char-only
input.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eanup F15: Prevent unsafe inline fallback when input looks like a file path. If the input contains path separators or has a known script extension (.sh, .ps1, .cmd, .bat, .py, etc.), error on file-not-found instead of falling through to ExecuteInline. This stops typos like 'azd exec typo.sh' from executing unexpected commands found on PATH. F6: Add process tree cleanup using OS-native process groups. - POSIX: Setpgid + SIGKILL to process group on context cancellation - Windows: CREATE_NEW_PROCESS_GROUP + Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE Refactor runCommand to use Start()+Wait() with a cancellation goroutine that kills the entire process tree, matching the pattern in pkg/exec/CmdTree. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Run gofmt on all scripting package files - Add //nolint:gosec for G101 (test credential constants) and G703 (test path traversal) - Update TestUsage snapshot for new --fail-on-prompt global flag from main Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
gosec G101 reports on the map literal line, not the value line. Extract the akvs:// string to a variable so the nolint:gosec directive is on the same line as the flagged string literal, matching the pattern in TestExecAction_ResolvesSecretReferences. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…windows.go Add log.Printf at all four best-effort Job Object setup fallback points (CreateJobObject, SetInformationJobObject, OpenProcess, AssignProcessToJobObject) to aid diagnosis of orphaned child processes on Windows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…teractive, fix Ctrl-C in interactive mode, strengthen exit-code test - Escape % as %% in cmd.exe paths and args to prevent env var expansion (CVE-2024-24576 class) - Gate cmd.Stdin on e.config.Interactive in ExecuteDirect (parity with executeCommand) - Skip CREATE_NEW_PROCESS_GROUP when interactive=true (match Unix Setpgid behavior) - Close Job Object handle after TerminateJobObject in kill closure - Replace shell-dependent exit-code test with portable compiled binary approach Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Review Comment Resolution SummaryRebased onto current main ( ✅ Confirmed Fixed
|
| Thread | Issue | Status |
|---|---|---|
| 5 | Race between cmd.Start() and AssignProcessToJobObject |
Go os/exec doesn't expose CREATE_SUSPENDED. Standard pattern used by Docker/containerd. Grandchild spawned in the gap is unlikely and mitigated by KILL_ON_JOB_CLOSE on the parent. |
💬 Disagree — intentional behavior
| Thread | Issue | Status |
|---|---|---|
| 3 | Extensionless file dispatch via default shell | This is intentional — unknown file types are dispatched through the platform default shell, matching the behavior of ./script on Unix (which uses the shell/shebang). Users running ELF binaries should use azd exec ./mybinary arg1 which routes through ExecuteDirect. |
c227033 to
6bf1f01
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Global flags changed upstream (removed --fail-on-prompt, updated --no-prompt wording). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure Dev CLI Install InstructionsInstall scriptsMacOS/Linux
bash: pwsh: WindowsPowerShell install MSI install Standalone Binary
MSI
Documentationlearn.microsoft.com documentationtitle: Azure Developer CLI reference
|
azd exec has been merged into core Azure Developer CLI as microsoft.azd.exec via Azure/azure-dev#7400. Remove from registry and website. - Remove jongio.azd.exec from registry.json - Remove exec extension card from website - Update copy from 4 extensions to 3 - Remove exec from install commands Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ap (#8221) The changelog generation skill missed PR #7400 (azd exec) in the 1.25.1 release notes. The PR was in the commit range but was silently skipped during processing. Changes: - Add #7400 entry to CHANGELOG.md under 1.25.1 Features Added - Add reverse cross-reference (coverage check) to changelog skill Step 5 that verifies every commit in range is either included or has an explicit exclusion reason, preventing silent omissions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ntext (#7400) * feat: add azd exec as a core command Move the microsoft.azd.exec extension into azd-core as a built-in top-level command. This provides 'azd exec' for running commands and scripts with full azd environment context, including automatic Key Vault secret resolution for both akvs:// and @Microsoft.KeyVault references. Three execution modes (selected by heuristic): - Direct exec: azd exec python script.py (exact argv, no shell) - Shell inline: azd exec 'echo \' (shell expansion) - Script file: azd exec ./setup.sh (shell auto-detected from ext) New packages: - pkg/exec/scripting/ — execution engine, shell detection, command builder with Windows cmd.exe CmdLine override - cmd/exec.go — ActionDescriptor command with --shell/-s, --interactive/-i flags and IoC-injected environment + keyvault Resolves design decisions from Issue #7423: - D1: Top-level 'azd exec' (not 'azd env exec') - D2: Stable GA (not beta) - D3: Automatic secret resolution (matches hooks behavior) - D4: In-process env loading via IoC Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test/docs: add exec action tests and update environment docs Add cmd/exec_test.go with 6 tests covering: - Environment variable injection from azd env - Key Vault secret reference resolution (akvs://) - Secret resolution failure error propagation - Invalid shell validation - Direct exec mode with multiple args - Command metadata (Use, Args validator, flag parsing) Update docs/environment-variables.md with azd exec section documenting execution modes (script file, direct exec, shell inline), flags, and automatic Key Vault secret resolution behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: replace os.Exit in exec action with ExitCodeError for proper middleware cleanup - Add ExitCodeError type to internal/errors.go for custom exit codes - Update main.go to extract exit code from ExitCodeError instead of hardcoded 1 - Replace os.Exit(exitCode) in exec action with returning ExitCodeError - Fix potential panic in logDebugInfo when cmdArgs is empty - Make ValidShells unexported to prevent external mutation; add IsSupportedShell() - Add test for @Microsoft.KeyVault reference format resolution - Add test for exit code propagation via ExitCodeError Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * security: scope child env, harden cmd.exe quoting, guard exit code Address findings from adversarial security review: - F1+F4+F7: Replace os.Setenv with scoped child env slice passed via Config.Env. Secrets never leak into the parent process or telemetry subprocesses. Extract buildChildEnv() as a testable method. - F5: Escape embedded double-quotes in scriptOrPath for cmd.exe file execution to prevent injection via script.bat\" & calc & \"x. - F8: Guard ExitCodeError{ExitCode:0} in main.go — only override the default exit code 1 when ExitCode is non-zero, preventing silent success on Windows TerminateProcess edge cases. - F12: Replace partial controlCharReplacer (7 of 33 chars) with stripControlChars() that removes all ASCII control chars 0x00-0x1F and 0x7F using strings.Map. - F13: Combine containsPrintable() with TrimSpace check in ExecuteInline to reject both whitespace-only and control-char-only input. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * security: prevent inline fallback for file paths, add process tree cleanup F15: Prevent unsafe inline fallback when input looks like a file path. If the input contains path separators or has a known script extension (.sh, .ps1, .cmd, .bat, .py, etc.), error on file-not-found instead of falling through to ExecuteInline. This stops typos like 'azd exec typo.sh' from executing unexpected commands found on PATH. F6: Add process tree cleanup using OS-native process groups. - POSIX: Setpgid + SIGKILL to process group on context cancellation - Windows: CREATE_NEW_PROCESS_GROUP + Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE Refactor runCommand to use Start()+Wait() with a cancellation goroutine that kills the entire process tree, matching the pattern in pkg/exec/CmdTree. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: resolve CI lint failures (gofmt, gosec) and update snapshots - Run gofmt on all scripting package files - Add //nolint:gosec for G101 (test credential constants) and G703 (test path traversal) - Update TestUsage snapshot for new --fail-on-prompt global flag from main Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add remaining gosec nolint directives for test credentials Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: move gosec nolint directive to variable declaration line gosec G101 reports on the map literal line, not the value line. Extract the akvs:// string to a variable so the nolint:gosec directive is on the same line as the flagged string literal, matching the pattern in TestExecAction_ResolvesSecretReferences. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add diagnostic logging to Job Object fallback paths in proctree_windows.go Add log.Printf at all four best-effort Job Object setup fallback points (CreateJobObject, SetInformationJobObject, OpenProcess, AssignProcessToJobObject) to aid diagnosis of orphaned child processes on Windows. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address review feedback - escape cmd.exe %VAR%, gate stdin on interactive, fix Ctrl-C in interactive mode, strengthen exit-code test - Escape % as %% in cmd.exe paths and args to prevent env var expansion (CVE-2024-24576 class) - Gate cmd.Stdin on e.config.Interactive in ExecuteDirect (parity with executeCommand) - Skip CREATE_NEW_PROCESS_GROUP when interactive=true (match Unix Setpgid behavior) - Close Job Object handle after TerminateJobObject in kill closure - Replace shell-dependent exit-code test with portable compiled binary approach Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: add gosec nolint comment for test build command Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: move nolint directive above line to satisfy lll lint rule Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: update exec usage snapshot after rebase onto main Global flags changed upstream (removed --fail-on-prompt, updated --no-prompt wording). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: therealjohn <1501196+therealjohn@users.noreply.github.com>
…ap (#8221) The changelog generation skill missed PR #7400 (azd exec) in the 1.25.1 release notes. The PR was in the commit range but was silently skipped during processing. Changes: - Add #7400 entry to CHANGELOG.md under 1.25.1 Features Added - Add reverse cross-reference (coverage check) to changelog skill Step 5 that verifies every commit in range is either included or has an explicit exclusion reason, preventing silent omissions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: therealjohn <1501196+therealjohn@users.noreply.github.com>
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