fix: resolve -C/--cwd relative path before extension invocation#8230
Conversation
When using 'azd -C <relative-path>', the relative path was applied twice: once by core azd (root.go) and again by the extension subprocess. This caused 'chdir path/path: no such file or directory' errors. Root cause: root.go changed CWD to the relative path, then passed the raw relative string as AZD_CWD to extensions. The extension resolved it again relative to the already-changed CWD, doubling the path. Fix (defense in depth, three layers): 1. root.go: resolve opts.Cwd to absolute with filepath.Abs() before any usage, and update the cobra persistent flag so middleware also gets the absolute path. 2. extensions.go: strip -C/--cwd from args passed to extension subprocess since core azd already handled it (the value is propagated via AZD_CWD env var instead). 3. azdext/extension_command.go: prefer AZD_CWD env var over the -C flag parsed from args, since the parent already resolved the path. Fixes #8229 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes a doubled-path bug when invoking azd extensions with a relative -C/--cwd value. Core azd was changing into the target directory and then propagating the still-relative flag value to the extension subprocess, which would filepath.Abs() it again against the already-changed CWD and fail. The fix applies defense in depth across the boundary between core azd and the extension SDK.
Changes:
- In
cmd/root.go, resolveopts.Cwdto an absolute path beforeos.Chdirand update the cobra--cwdpersistent flag so middleware sees the absolute value. - In
cmd/extensions.go, strip--cwd/-C(all forms) from the args passed to extension subprocesses, since the value is propagated viaAZD_CWD. - In
pkg/azdext/extension_command.go, makeAZD_CWDtake precedence over the parsed--cwdflag in the extension SDK, and add regression tests for the new behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| cli/azd/cmd/root.go | Resolves opts.Cwd to absolute and updates the persistent cobra flag before chdir. |
| cli/azd/cmd/root_test.go | New tests asserting relative -C is canonicalized and absolute paths are unchanged. |
| cli/azd/cmd/extensions.go | Adds stripCwdFlag and applies it to args forwarded to extensions. |
| cli/azd/cmd/extensions_test.go | Table-driven tests for the new stripCwdFlag helper. |
| cli/azd/pkg/azdext/extension_command.go | Extension SDK now prefers AZD_CWD over the --cwd flag (contains a dead else if branch). |
- Revert extension_command.go to original flag-wins-over-env-var precedence - Handle -Cvalue combined shorthand form in stripCwdFlag - Assert on Execute() error in tests instead of ignoring 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
|
* fix: resolve -C/--cwd relative path before extension invocation When using 'azd -C <relative-path>', the relative path was applied twice: once by core azd (root.go) and again by the extension subprocess. This caused 'chdir path/path: no such file or directory' errors. Root cause: root.go changed CWD to the relative path, then passed the raw relative string as AZD_CWD to extensions. The extension resolved it again relative to the already-changed CWD, doubling the path. Fix (defense in depth, three layers): 1. root.go: resolve opts.Cwd to absolute with filepath.Abs() before any usage, and update the cobra persistent flag so middleware also gets the absolute path. 2. extensions.go: strip -C/--cwd from args passed to extension subprocess since core azd already handled it (the value is propagated via AZD_CWD env var instead). 3. azdext/extension_command.go: prefer AZD_CWD env var over the -C flag parsed from args, since the parent already resolved the path. Fixes #8229 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address Copilot review feedback (iteration 1) - Revert extension_command.go to original flag-wins-over-env-var precedence - Handle -Cvalue combined shorthand form in stripCwdFlag - Assert on Execute() error in tests instead of ignoring 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>
Description
When using
azd -C <relative-path>(e.g.,azd ai agent init -C myFolder), the relative path was applied twice — once by core azd and again by the extension subprocess — causingchdir path/path: no such file or directoryerrors.Root Cause
root.gocreates the directory and callsos.Chdir("myFolder")→ CWD changes to/abs/myFolder"myFolder"is propagated to the extension subprocess (via args andAZD_CWDenv var)filepath.Abs("myFolder")against the already-changed CWD →/abs/myFolder/myFolder(doubled)Fix (defense in depth, three layers)
cmd/root.go: Resolveopts.Cwdto absolute withfilepath.Abs()before any usage, and update the cobra persistent flag so middleware also gets the absolute path.cmd/extensions.go: Strip-C/--cwdfrom args passed to extension subprocess since core azd already handled it (the value is propagated viaAZD_CWDenv var instead).pkg/azdext/extension_command.go: PreferAZD_CWDenv var over the-Cflag parsed from args, since the parent already resolved the path.Testing
TestRootCmd_CwdRelativePathResolvedToAbsoluteandTestRootCmd_CwdAbsolutePathUnchangedTestStripCwdFlag(table-driven, all flag forms)cmd/,pkg/extensions/,pkg/azdext/passReproduction
Fixes #8229
Related to #8209