Skip to content

Resolve relative launch.json workingDirectory against the workspace folder - #116

Merged
Chiara Mooney (chiaramooney) merged 1 commit into
microsoft:mainfrom
Sanjays2402:fix/112-relative-working-directory
Aug 3, 2026
Merged

Resolve relative launch.json workingDirectory against the workspace folder#116
Chiara Mooney (chiaramooney) merged 1 commit into
microsoft:mainfrom
Sanjays2402:fix/112-relative-working-directory

Conversation

@Sanjays2402

Copy link
Copy Markdown
Contributor

Description

Fixes the relative workingDirectory resolution described in #112.

WinAppDebugAdapterFactory.createDebugAdapterDescriptor passed config.workingDirectory straight through as the spawn cwd:

let cwd = folder.uri.fsPath;
if (config.workingDirectory) {
    cwd = config.workingDirectory;
}

A relative value from launch.json therefore resolved against the extension host's process.cwd() rather than the workspace folder, so winapp run started from an unrelated directory. On Windows the drive-relative form (C:out) has the same problem, resolving against the current directory of drive C: instead of the workspace.

This adds resolveWorkingDirectory() to src/winapp-cli-utils.ts and uses it for the spawn cwd. Absolute paths pass through unchanged, unset values keep falling back to the workspace folder, and everything else is resolved against folder.uri.fsPath. path.resolve also covers the drive-relative case.

The helper lives in winapp-cli-utils.ts rather than inline in extension.ts so it can be unit tested without the extension host, matching how project-resolver.ts and the other extracted helpers are tested here.

Usage Example

{
  "type": "winapp",
  "request": "launch",
  "name": "WinApp: Launch and Attach",
  "workingDirectory": "./subdir"
}

./subdir now resolves against the workspace folder instead of the extension host's cwd.

Related Issue

Fixes #112

Type of Change

  • 🐛 Bug fix

Checklist

  • New tests added for new functionality (if applicable)
  • Tested locally

Additional Notes

New unit tests in src/test/working-directory.test.ts cover unset, empty, relative, dot-prefixed, parent-relative, absolute, and (on Windows) drive-relative values, plus an explicit assertion that resolution does not fall back to process.cwd(). The file is registered in the test:unit script.

npm run test:unit goes from 715 to 722 tests, passing 701 to 708. The 14 failures are pre-existing on this machine and unrelated to this change: they are Windows-only suites (resolveWindowsPowerShellPath, isUsableElevatedCliPath, isArtifactWithinRoot, buildPackSuccessMessage) that fail identically on an unmodified main checkout, since I developed this on macOS. npx tsc -p ./ and npx eslint src are both clean (8 pre-existing warnings, 0 errors).

I could not run .\scripts\build-vsce.ps1 or the e2e suite, since both need Windows.

@chiaramooney

Copy link
Copy Markdown
Collaborator

Ran our PR Review agent on this PR. Just a couple small fixes. Please address and resolve merge conflicts and then we can merge your changes in!

PR Review — fix/112-relative-working-directory vs main  (1 commit, 4 files, +101/-6 lines)


Summary

Critical: 0   High: 0   Medium: 2   Low: 0


Coverage

security              ✓ clean

correctness           ⚠ 2 findings

extension-ux          ⚠ 1 finding

alternative-solution  ⚠ 1 finding

test-coverage         ⚠ 2 findings

docs-and-samples      ✓ clean

packaging             ✓ clean

multi-model           ✓ 0/0 critical+high confirmed


Findings

M1  src/winapp-cli-utils.ts:133-134   correctness, test-coverage   Root-relative Windows paths resolve against the process drive

M2  src/winapp-cli-utils.ts:137       correctness, extension-ux, alternative-solution, test-coverage   Cross-drive drive-relative paths remain process-dependent


Details


## M1  src/winapp-cli-utils.ts:133-134



- Severity: medium

- Confidence: high

- Domain: correctness, test-coverage

- Multi-model: not reviewed

- Finding: Windows root-relative paths such as `\out` are treated as absolute despite lacking a drive.

- Evidence: `path.isAbsolute(workingDirectory)` returns true for `\out`, so the helper returns it unchanged. `spawn` can then resolve it against the extension host’s current drive rather than the workspace drive.

- Recommendation: Distinguish fully qualified paths from root-relative paths, resolve the latter using the workspace drive, and add a cross-drive test.



## M2  src/winapp-cli-utils.ts:137



- Severity: medium

- Confidence: high

- Domain: correctness, extension-ux, alternative-solution, test-coverage

- Multi-model: not reviewed

- Finding: Drive-relative paths such as `C:out` only behave as intended when their drive matches the workspace.

- Evidence: `path.resolve(workspacePath, workingDirectory)` can consult drive C’s process-specific current directory when `workspacePath` is on D:. The test at `src/test/working-directory.test.ts:61-65` uses only a C: workspace and derives its expected value using the same operation as the implementation.

- Recommendation: Reject drive-relative values with an actionable message or define deterministic normalization semantics; add same-drive and cross-drive tests with independently specified expectations.

…older

The debug adapter passed config.workingDirectory straight to spawn, so a
relative value resolved against the extension host's process.cwd() instead
of the workspace folder. Windows drive-relative forms like C:out resolved
against the current directory of the drive.

Adds resolveWorkingDirectory() in winapp-cli-utils.ts and uses it for the
winapp run spawn cwd, with unit tests covering unset, relative, parent,
absolute, and drive-relative values.
@Sanjays2402
Sanjay Santhanam (Sanjays2402) force-pushed the fix/112-relative-working-directory branch from 81159be to 4afeb7e Compare August 2, 2026 06:53
@chiaramooney
Chiara Mooney (chiaramooney) merged commit 678ffc6 into microsoft:main Aug 3, 2026
6 checks passed
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.

Relative workingDirectory in launch.json resolves against extension host cwd, not workspace

2 participants