Skip to content

Run the scripts from Git Bash and MSYS2 on Windows - #47

Open
paolosalvatori wants to merge 5 commits into
mainfrom
smf-963-web-app-cosmosdb-nosql-api-sample-fails-on-windows-git-bash
Open

paolosalvatori wants to merge 5 commits into
mainfrom
smf-963-web-app-cosmosdb-nosql-api-sample-fails-on-windows-git-bash

Conversation

@paolosalvatori

@paolosalvatori paolosalvatori commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Motivation

On Windows, the scripts of this repository fail when they run from Git Bash or from another shell built on MSYS2.
When these shells start a Windows program such as the Azure CLI, they rewrite every argument that looks like an absolute POSIX path into a Windows path, so the Cosmos DB partition key path /username and the resource IDs the scripts pass to --scope or --vnet-subnet-id reach az as C:/Program Files/Git/... and the commands fail.
The same problem breaks the web-app-cosmosdb-nosql-api sample of localstack-azure-samples (SMF-963), and our CI does not see it because it runs on Linux.
Setting MSYS_NO_PATHCONV=1 turns the rewriting off, in Git Bash and in MSYS2 shells alike.

Fixes SMF-979

Changes

  • README.md gets a "Windows: Git Bash and MSYS2" section at the end of "Run against LocalStack": it asks Windows users of these shells to run export MSYS_NO_PATHCONV=1, set -o igncr and export SHELLOPTS before any script, explains why, and covers making the setting permanent, recognizing these shells with $MSYSTEM, and turning the conversion back on.
  • With the rewriting off, a Windows program no longer receives the Windows form of a local file, so every script that hands one to az, docker or curl now passes it through a small native_path helper, which returns cygpath -m of the path in Git Bash and MSYS2 and the path unchanged everywhere else, so Linux, macOS and WSL behave exactly as before:
    • the SSH public key in the four cluster scripts under scripts/;
    • the sample activities the Blob Storage and managed identity samples upload from a mktemp folder (01-deploy-resources.sh, Python and .NET);
    • the host folder the Azure Files sample mounts into its local container, and the LocalStack CA file the Cosmos DB sample mounts into its own (03-run-docker-container.sh, Python and .NET);
    • the cookie jar of tests/test-vacation-planner.sh.
  • For the same reason a Windows curl no longer receives /dev/null as the NUL device, so the end-to-end test and the Gateway API tutorial pass it -o "$(null_device)": NUL for a Windows curl in Git Bash and MSYS2, /dev/null everywhere else, MSYS2's own curl under /usr/bin included. Without it, the end-to-end test, which runs under set -e, stopped at its first form post on Windows. The README's tips tell script authors about both helpers.
  • Windows programs such as the Azure CLI and jq end their lines with a carriage return, which Bash keeps in $(...) and read, so the README also asks for set -o igncr and export SHELLOPTS: the bash of Git Bash and MSYS2 then drops it. mapfile keeps it even then, so the App Configuration scripts and the cluster scripts strip it with tr -d '\r' where they read fields with mapfile; without that, the App Configuration sample read the cluster's workload identity flags as true followed by a carriage return and stopped.

Tests

  • bash -n on every edited script, and shellcheck reports the same findings as on main for each of them.
  • The helper returns the path unchanged on Linux and the C:/... form when cygpath is on the PATH.
  • null_device returns /dev/null without cygpath, NUL with cygpath and a native curl first on the PATH, and /dev/null with cygpath and /usr/bin/curl.
  • The cluster script and the end-to-end test changed, so the CI of this pull request runs every app on Linux.
  • Windows is not covered by CI yet: Run all samples on a Windows runner from Git Bash #48 adds a manual Windows job built on this branch.

Related

🤖 Generated with Claude Code

https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh

Git Bash and MSYS2 shells rewrite every argument that looks like an absolute POSIX path before starting a Windows program, so Azure values such as the Cosmos DB partition key path /username and the resource IDs passed to --scope or --vnet-subnet-id reached az as Windows paths (SMF-963).
The README now asks Windows users of these shells to export MSYS_NO_PATHCONV=1, which turns the rewriting off, and explains why.
With the rewriting off, the local files the scripts hand to Windows programs need their Windows form: the SSH public key of the cluster scripts, the blobs the Blob Storage and managed identity samples upload, the host folder the Azure Files sample mounts into its local container, and the cookie jar of the end-to-end test.
A native_path helper in each of these scripts returns that form through cygpath when it exists and the path unchanged otherwise, so Linux, macOS and WSL behave exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The MSYS2 instructions and remaining unconverted native-tool file arguments leave advertised Windows workflows broken.

2 open issues
What changed in this PR

This PR improves Windows shell support for the AKS samples by documenting path-conversion settings and explicitly converting local file paths for Windows tools.

Changes:

  • Adds Git Bash and MSYS2 setup guidance.
  • Adds native_path helpers for SSH keys, uploaded sample files, and Docker bind mounts.
  • Converts the end-to-end test’s cookie-jar path.
File Description
tests/​test-vacation-planner.sh Converts the cookie-jar path for curl.
scripts/​01-user-assigned-managed-identity.sh Converts the SSH public-key path for Azure CLI.
scripts/​01-system-assigned-managed-identity.sh Converts the SSH public-key path for Azure CLI.
samples/​web-app-managed-identity/​python/​scripts/​01-deploy-resources.sh Converts the sample upload directory path.
samples/​web-app-managed-identity/​dotnet/​scripts/​01-deploy-resources.sh Converts the sample upload directory path.
samples/​web-app-file-storage/​python/​scripts/​03-run-docker-container.sh Converts the Docker bind-mount host path.
samples/​web-app-file-storage/​dotnet/​scripts/​03-run-docker-container.sh Converts the Docker bind-mount host path.
samples/​web-app-blob-storage/​python/​scripts/​01-deploy-resources.sh Converts the sample upload directory path.
samples/​web-app-blob-storage/​dotnet/​scripts/​01-deploy-resources.sh Converts the sample upload directory path.
README.md Documents Windows shell configuration and path handling.

Review effort: Balanced

Comment thread README.md
Comment thread README.md
paolosalvatori and others added 4 commits October 23, 2026 16:42
With MSYS_NO_PATHCONV=1, az could not open the SSH public key that scripts/01-basic-cluster.sh and scripts/01-configurable-cluster.sh pass to --ssh-key-value, and docker could not mount the LocalStack CA file the Cosmos DB container scripts write next to themselves.
Both now go through native_path, as in the other scripts.

The end-to-end test assigns mktemp's result on its own line again, so a mktemp failure still stops it under set -e, and the helper follows the two-space indentation of the files that use it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh
With MSYS_NO_PATHCONV=1 these shells no longer turn a /dev/null argument into nul for Windows programs, so a Windows curl given -o /dev/null cannot open its output and exits with code 23 as soon as a response has a body.
The end-to-end test, which runs under set -e, would stop at its first form post, and the Gateway API tutorial would report a failed routing check.
A null_device helper returns NUL for a Windows curl in these shells and /dev/null everywhere else, MSYS2's own curl included, and the three curl calls that discard a body use it.
The README says so, and tells script authors to do the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh
… programs

Windows programs such as the Azure CLI and jq end every line with a carriage return, which Bash keeps in $(...) and read, so a name or an ID read from az --output tsv carries a trailing \r.
In the Windows CI run, the App Configuration sample's private endpoint failed twice with ResourceNotFound for a key vault that existed, its name ending in that \r.
MSYS2's bash, which Git Bash ships, drops carriage returns from command substitution and read when its igncr option is on, and an exported SHELLOPTS passes the option to the scripts, so the README asks for set -o igncr and export SHELLOPTS next to MSYS_NO_PATHCONV=1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh
On Windows the Azure CLI ends every line with a carriage return, and bash's igncr option drops it from $(...) and read but not from mapfile.
The App Configuration samples read several fields at once with mapfile, so in the Windows CI the key vault ID kept its \r and the private endpoint failed with ResourceNotFound, and the AKS sample read the cluster's OIDC and workload identity flags as "true\r".
Every mapfile that reads az output, in those samples and in the AKS cluster scripts, now reads it through tr -d '\r', which changes nothing on Linux and macOS, and the README says igncr does not cover mapfile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhZ2ojsEXd2SGMo7s9uiZh
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.

2 participants