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 |
Wallace Breza (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
Wallace Breza (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.
Wallace Breza (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.
Wallace Breza (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