From 37751ca7824d81b710b47e4776b077d6207dce1c Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 15:46:53 +0000 Subject: [PATCH 1/8] feat: add az CLI shim for Azure token acquisition via ado-codespaces-auth --- src/artifacts-helper/scripts/az.sh | 117 +++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/artifacts-helper/scripts/az.sh diff --git a/src/artifacts-helper/scripts/az.sh b/src/artifacts-helper/scripts/az.sh new file mode 100644 index 0000000..b8b2b0f --- /dev/null +++ b/src/artifacts-helper/scripts/az.sh @@ -0,0 +1,117 @@ +#!/bin/bash +# Azure CLI shim for GitHub Codespaces +# Intercepts 'az account get-access-token' requests and uses azure-auth-helper +# to acquire tokens via the ado-codespaces-auth VS Code extension. +# +# This enables DefaultAzureCredential's AzureCliCredential to work in Codespaces +# without requiring 'az login' (which times out waiting for browser auth). +# +# To install: Copy this to /usr/local/share/codespace-shims/az +# The shims directory should already be in PATH for Codespaces. + +# If ACTIONS_ID_TOKEN_REQUEST_URL is set, we're in GitHub Actions - skip interception +if [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL}" ]; then + source "$(dirname $0)"/resolve-shim.sh + AZ_EXE="$(resolve_shim)" + exec "${AZ_EXE}" "$@" +fi + +source "$(dirname $0)"/resolve-shim.sh + +# Well-known resource type mappings (az account get-access-token --resource-type) +declare -A RESOURCE_TYPE_MAP=( + ["arm"]="https://management.azure.com" + ["aad-graph"]="https://graph.windows.net" + ["ms-graph"]="https://graph.microsoft.com" + ["batch"]="https://batch.core.windows.net" + ["data-lake"]="https://datalake.azure.net" + ["media"]="https://rest.media.azure.net" + ["oss-rdbms"]="https://ossrdbms-aad.database.windows.net" +) + +# Check if this is a get-access-token request that we should intercept +if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then + # Parse arguments to extract --resource, --scope, or --resource-type + resource="" + scope="" + resource_type="" + prev="" + + for arg in "${@:3}"; do + case "$prev" in + --resource) + resource="$arg" + ;; + --scope) + scope="$arg" + ;; + --resource-type) + resource_type="$arg" + ;; + esac + prev="$arg" + done + + # Resolve resource-type to resource URL if specified + if [[ -n "$resource_type" && -z "$resource" ]]; then + resource="${RESOURCE_TYPE_MAP[$resource_type]}" + fi + + # Determine the scope to request + # Priority: explicit --scope > --resource/.default > --resource-type/.default + request_scope="" + if [[ -n "$scope" ]]; then + request_scope="$scope" + elif [[ -n "$resource" ]]; then + # Append /.default if not already present + if [[ "$resource" == *"/.default" ]]; then + request_scope="$resource" + else + request_scope="${resource}/.default" + fi + fi + + # If we have a scope and azure-auth-helper exists, use it + if [[ -n "$request_scope" && -f "${HOME}/azure-auth-helper" ]]; then + # Get token from azure-auth-helper + token=$("${HOME}/azure-auth-helper" get-access-token "$request_scope" 2>/dev/null) + exit_code=$? + + if [[ $exit_code -eq 0 && -n "$token" ]]; then + # Calculate expiry timestamps (conservative 1 hour estimate) + # expires_on = POSIX timestamp, expiresOn = local datetime + if date --version >/dev/null 2>&1; then + # GNU date (Linux) + expires_on=$(date -d "+1 hour" "+%s") + expires_on_datetime=$(date -d "+1 hour" "+%Y-%m-%d %H:%M:%S.000000") + else + # BSD date (macOS) + expires_on=$(date -v+1H "+%s") + expires_on_datetime=$(date -v+1H "+%Y-%m-%d %H:%M:%S.000000") + fi + + # Return in az CLI JSON format (matching real az CLI output) + cat <&2 + exit 1 +fi \ No newline at end of file From 83b115031f2672d7949bde8b6d510493b2c30b16 Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:08:54 +0000 Subject: [PATCH 2/8] remove date --- src/artifacts-helper/scripts/az.sh | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/src/artifacts-helper/scripts/az.sh b/src/artifacts-helper/scripts/az.sh index b8b2b0f..2282258 100644 --- a/src/artifacts-helper/scripts/az.sh +++ b/src/artifacts-helper/scripts/az.sh @@ -78,26 +78,10 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then exit_code=$? if [[ $exit_code -eq 0 && -n "$token" ]]; then - # Calculate expiry timestamps (conservative 1 hour estimate) - # expires_on = POSIX timestamp, expiresOn = local datetime - if date --version >/dev/null 2>&1; then - # GNU date (Linux) - expires_on=$(date -d "+1 hour" "+%s") - expires_on_datetime=$(date -d "+1 hour" "+%Y-%m-%d %H:%M:%S.000000") - else - # BSD date (macOS) - expires_on=$(date -v+1H "+%s") - expires_on_datetime=$(date -v+1H "+%Y-%m-%d %H:%M:%S.000000") - fi - - # Return in az CLI JSON format (matching real az CLI output) + # Return in az CLI JSON format cat <&2 exit 1 -fi \ No newline at end of file +fi From 922312399b6ca1dd2926a8d9e62808d4f095603e Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:09:25 +0000 Subject: [PATCH 3/8] rename --- src/artifacts-helper/scripts/{az.sh => az} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/artifacts-helper/scripts/{az.sh => az} (100%) diff --git a/src/artifacts-helper/scripts/az.sh b/src/artifacts-helper/scripts/az similarity index 100% rename from src/artifacts-helper/scripts/az.sh rename to src/artifacts-helper/scripts/az From 1c1dfb2d8ced9edec0b7326ae5dbe5059a6a494e Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:17:04 +0000 Subject: [PATCH 4/8] Add az CLI shim for DefaultAzureCredential support in Codespaces --- src/artifacts-helper/NOTES.md | 8 ++++++-- src/artifacts-helper/README.md | 9 +++++++-- src/artifacts-helper/devcontainer-feature.json | 5 +++++ src/artifacts-helper/install.sh | 4 ++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/artifacts-helper/NOTES.md b/src/artifacts-helper/NOTES.md index 5e83843..056b7fe 100644 --- a/src/artifacts-helper/NOTES.md +++ b/src/artifacts-helper/NOTES.md @@ -1,6 +1,10 @@ This installs [Azure Artifacts Credential Provider](https://github.com/microsoft/artifacts-credprovider) -and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, and `pnpm`. -These dynamically sets an authentication token for pulling artifacts from a feed before running the command. +and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, `pnpm`, and `az`. +These dynamically set an authentication token for pulling artifacts from a feed before running the command. + +The `az` shim specifically intercepts `az account get-access-token` requests and uses the `azure-auth-helper` +to acquire tokens via the ado-codespaces-auth VS Code extension. This enables `DefaultAzureCredential`'s +`AzureCliCredential` to work in Codespaces without requiring `az login`. For `npm`, `yarn`, `rush`, and `pnpm` this requires that your `~/.npmrc` file is configured to use the ${ARTIFACTS_ACCESSTOKEN} environment variable for the `authToken`. A helper script has been added that you can use to write your `~/.npmrc` diff --git a/src/artifacts-helper/README.md b/src/artifacts-helper/README.md index 0d045d7..f7af629 100644 --- a/src/artifacts-helper/README.md +++ b/src/artifacts-helper/README.md @@ -24,6 +24,7 @@ Configures Codespace to authenticate with Azure Artifact feeds | npxAlias | Create alias for npx | boolean | true | | rushAlias | Create alias for rush | boolean | true | | pnpmAlias | Create alias for pnpm | boolean | true | +| azAlias | Create alias for az (Azure CLI) | boolean | true | | shimDirectory | Directory where the shims will be installed. This must be in $PATH, and needs to be as early as possible in priority for the scripts to override the base executables. | string | /usr/local/share/codespace-shims | | targetFiles | Comma separated list of files to write to. Default is '/etc/bash.bashrc,/etc/zsh/zshrc' for root and '~/.bashrc,~/.zshrc' for non-root | string | DEFAULT | | python | Install Python keyring helper for pip | boolean | false | @@ -35,8 +36,12 @@ Configures Codespace to authenticate with Azure Artifact feeds - `ms-codespaces-tools.ado-codespaces-auth` This installs [Azure Artifacts Credential Provider](https://github.com/microsoft/artifacts-credprovider) -and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, and `pnpm`. -These dynamically sets an authentication token for pulling artifacts from a feed before running the command. +and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, `pnpm`, and `az`. +These dynamically set an authentication token for pulling artifacts from a feed before running the command. + +The `az` shim specifically intercepts `az account get-access-token` requests and uses the `azure-auth-helper` +to acquire tokens via the ado-codespaces-auth VS Code extension. This enables `DefaultAzureCredential`'s +`AzureCliCredential` to work in Codespaces without requiring `az login`. For `npm`, `yarn`, `rush`, and `pnpm` this requires that your `~/.npmrc` file is configured to use the ${ARTIFACTS_ACCESSTOKEN} environment variable for the `authToken`. A helper script has been added that you can use to write your `~/.npmrc` diff --git a/src/artifacts-helper/devcontainer-feature.json b/src/artifacts-helper/devcontainer-feature.json index 2d7566b..8376a53 100644 --- a/src/artifacts-helper/devcontainer-feature.json +++ b/src/artifacts-helper/devcontainer-feature.json @@ -49,6 +49,11 @@ "default": true, "description": "Create alias for pnpm" }, + "azAlias": { + "type": "boolean", + "default": true, + "description": "Create alias for az (Azure CLI)" + }, "shimDirectory": { "type": "string", "default": "/usr/local/share/codespace-shims", diff --git a/src/artifacts-helper/install.sh b/src/artifacts-helper/install.sh index 5386350..2fb3f09 100755 --- a/src/artifacts-helper/install.sh +++ b/src/artifacts-helper/install.sh @@ -11,6 +11,7 @@ ALIAS_YARN="${YARNALIAS:-"true"}" ALIAS_NPX="${NPXALIAS:-"true"}" ALIAS_RUSH="${RUSHALIAS:-"true"}" ALIAS_PNPM="${PNPMALIAS:-"true"}" +ALIAS_AZ="${AZALIAS:-"true"}" INSTALL_PIP_HELPER="${PYTHON:-"false"}" SHIM_DIRECTORY="${SHIMDIRECTORY:-"/usr/local/share/codespace-shims/"}" @@ -39,6 +40,9 @@ if [ "${ALIAS_PNPM}" = "true" ]; then ALIASES_ARR+=('pnpm') ALIASES_ARR+=('pnpx') fi +if [ "${ALIAS_AZ}" = "true" ]; then + ALIASES_ARR+=('az') +fi # Source /etc/os-release to get OS info . /etc/os-release From 279265f7d67e108e5a24b96385c1b3e262ea7aff Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 16:34:03 +0000 Subject: [PATCH 5/8] readd , , and --- src/artifacts-helper/scripts/az | 47 +++++++++++++++------------------ 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/artifacts-helper/scripts/az b/src/artifacts-helper/scripts/az index 2282258..6b459d0 100644 --- a/src/artifacts-helper/scripts/az +++ b/src/artifacts-helper/scripts/az @@ -2,14 +2,8 @@ # Azure CLI shim for GitHub Codespaces # Intercepts 'az account get-access-token' requests and uses azure-auth-helper # to acquire tokens via the ado-codespaces-auth VS Code extension. -# -# This enables DefaultAzureCredential's AzureCliCredential to work in Codespaces -# without requiring 'az login' (which times out waiting for browser auth). -# -# To install: Copy this to /usr/local/share/codespace-shims/az -# The shims directory should already be in PATH for Codespaces. -# If ACTIONS_ID_TOKEN_REQUEST_URL is set, we're in GitHub Actions - skip interception +# If ACTIONS_ID_TOKEN_REQUEST_URL is set, we are in GitHub Actions - skip interception if [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL}" ]; then source "$(dirname $0)"/resolve-shim.sh AZ_EXE="$(resolve_shim)" @@ -31,23 +25,16 @@ declare -A RESOURCE_TYPE_MAP=( # Check if this is a get-access-token request that we should intercept if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then - # Parse arguments to extract --resource, --scope, or --resource-type resource="" scope="" resource_type="" prev="" - + for arg in "${@:3}"; do case "$prev" in - --resource) - resource="$arg" - ;; - --scope) - scope="$arg" - ;; - --resource-type) - resource_type="$arg" - ;; + --resource) resource="$arg" ;; + --scope) scope="$arg" ;; + --resource-type) resource_type="$arg" ;; esac prev="$arg" done @@ -58,12 +45,10 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then fi # Determine the scope to request - # Priority: explicit --scope > --resource/.default > --resource-type/.default request_scope="" if [[ -n "$scope" ]]; then request_scope="$scope" elif [[ -n "$resource" ]]; then - # Append /.default if not already present if [[ "$resource" == *"/.default" ]]; then request_scope="$resource" else @@ -73,21 +58,33 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then # If we have a scope and azure-auth-helper exists, use it if [[ -n "$request_scope" && -f "${HOME}/azure-auth-helper" ]]; then - # Get token from azure-auth-helper token=$("${HOME}/azure-auth-helper" get-access-token "$request_scope" 2>/dev/null) - exit_code=$? + if [[ $? -eq 0 && -n "$token" ]]; then + # Calculate expiry timestamps (conservative 1 hour estimate) + # expires_on = POSIX timestamp, expiresOn = local datetime + if date --version >/dev/null 2>&1; then + # GNU date (Linux) + expires_on=$(date -d "+1 hour" "+%s") + expires_on_datetime=$(date -d "+1 hour" "+%Y-%m-%d %H:%M:%S.000000") + else + # BSD date (macOS) + expires_on=$(date -v+1H "+%s") + expires_on_datetime=$(date -v+1H "+%Y-%m-%d %H:%M:%S.000000") + fi - if [[ $exit_code -eq 0 && -n "$token" ]]; then - # Return in az CLI JSON format + # Return in az CLI JSON format (matching real az CLI output) cat < Date: Tue, 13 Jan 2026 16:52:40 +0000 Subject: [PATCH 6/8] Bump version to 3.0.3 --- src/artifacts-helper/README.md | 9 ++------- src/artifacts-helper/devcontainer-feature.json | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/artifacts-helper/README.md b/src/artifacts-helper/README.md index f7af629..0d045d7 100644 --- a/src/artifacts-helper/README.md +++ b/src/artifacts-helper/README.md @@ -24,7 +24,6 @@ Configures Codespace to authenticate with Azure Artifact feeds | npxAlias | Create alias for npx | boolean | true | | rushAlias | Create alias for rush | boolean | true | | pnpmAlias | Create alias for pnpm | boolean | true | -| azAlias | Create alias for az (Azure CLI) | boolean | true | | shimDirectory | Directory where the shims will be installed. This must be in $PATH, and needs to be as early as possible in priority for the scripts to override the base executables. | string | /usr/local/share/codespace-shims | | targetFiles | Comma separated list of files to write to. Default is '/etc/bash.bashrc,/etc/zsh/zshrc' for root and '~/.bashrc,~/.zshrc' for non-root | string | DEFAULT | | python | Install Python keyring helper for pip | boolean | false | @@ -36,12 +35,8 @@ Configures Codespace to authenticate with Azure Artifact feeds - `ms-codespaces-tools.ado-codespaces-auth` This installs [Azure Artifacts Credential Provider](https://github.com/microsoft/artifacts-credprovider) -and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, `pnpm`, and `az`. -These dynamically set an authentication token for pulling artifacts from a feed before running the command. - -The `az` shim specifically intercepts `az account get-access-token` requests and uses the `azure-auth-helper` -to acquire tokens via the ado-codespaces-auth VS Code extension. This enables `DefaultAzureCredential`'s -`AzureCliCredential` to work in Codespaces without requiring `az login`. +and optionally configures shims which shadow `dotnet`, `nuget`, `npm`, `yarn`, `rush`, and `pnpm`. +These dynamically sets an authentication token for pulling artifacts from a feed before running the command. For `npm`, `yarn`, `rush`, and `pnpm` this requires that your `~/.npmrc` file is configured to use the ${ARTIFACTS_ACCESSTOKEN} environment variable for the `authToken`. A helper script has been added that you can use to write your `~/.npmrc` diff --git a/src/artifacts-helper/devcontainer-feature.json b/src/artifacts-helper/devcontainer-feature.json index 8376a53..a3d6049 100644 --- a/src/artifacts-helper/devcontainer-feature.json +++ b/src/artifacts-helper/devcontainer-feature.json @@ -1,7 +1,7 @@ { "name": "Azure Artifacts Credential Helper", "id": "artifacts-helper", - "version": "3.0.2", + "version": "3.0.3", "description": "Configures Codespace to authenticate with Azure Artifact feeds", "options": { "nugetURIPrefixes": { From 6d1fb8f64bd786fc3575c665528a237c4e4bbb2f Mon Sep 17 00:00:00 2001 From: Adrian Nadau Semb <31008843+ansemb@users.noreply.github.com> Date: Tue, 13 Jan 2026 17:06:53 +0000 Subject: [PATCH 7/8] fix copilot suggestions --- src/artifacts-helper/scripts/az | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/artifacts-helper/scripts/az b/src/artifacts-helper/scripts/az index 6b459d0..89156fd 100644 --- a/src/artifacts-helper/scripts/az +++ b/src/artifacts-helper/scripts/az @@ -5,12 +5,12 @@ # If ACTIONS_ID_TOKEN_REQUEST_URL is set, we are in GitHub Actions - skip interception if [ -n "${ACTIONS_ID_TOKEN_REQUEST_URL}" ]; then - source "$(dirname $0)"/resolve-shim.sh + source "$(dirname "$0")"/resolve-shim.sh AZ_EXE="$(resolve_shim)" exec "${AZ_EXE}" "$@" fi -source "$(dirname $0)"/resolve-shim.sh +source "$(dirname "$0")"/resolve-shim.sh # Well-known resource type mappings (az account get-access-token --resource-type) declare -A RESOURCE_TYPE_MAP=( @@ -31,10 +31,17 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then prev="" for arg in "${@:3}"; do - case "$prev" in - --resource) resource="$arg" ;; - --scope) scope="$arg" ;; - --resource-type) resource_type="$arg" ;; + case "$arg" in + --resource=*) resource="${arg#--resource=}" ;; + --scope=*) scope="${arg#--scope=}" ;; + --resource-type=*) resource_type="${arg#--resource-type=}" ;; + *) + case "$prev" in + --resource) resource="$arg" ;; + --scope) scope="$arg" ;; + --resource-type) resource_type="$arg" ;; + esac + ;; esac prev="$arg" done @@ -60,6 +67,10 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then if [[ -n "$request_scope" && -f "${HOME}/azure-auth-helper" ]]; then token=$("${HOME}/azure-auth-helper" get-access-token "$request_scope" 2>/dev/null) if [[ $? -eq 0 && -n "$token" ]]; then + # Escape token for safe JSON embedding (handle backslashes and quotes) + escaped_token="${token//\\/\\\\}" + escaped_token="${escaped_token//\"/\\\"}" + # Calculate expiry timestamps (conservative 1 hour estimate) # expires_on = POSIX timestamp, expiresOn = local datetime if date --version >/dev/null 2>&1; then @@ -75,7 +86,7 @@ if [[ "$1" == "account" && "$2" == "get-access-token" ]]; then # Return in az CLI JSON format (matching real az CLI output) cat < Date: Tue, 13 Jan 2026 17:07:43 +0000 Subject: [PATCH 8/8] add tests --- test/artifacts-helper/scenarios.json | 9 +++ test/artifacts-helper/test_az_shim.sh | 81 +++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100755 test/artifacts-helper/test_az_shim.sh diff --git a/test/artifacts-helper/scenarios.json b/test/artifacts-helper/scenarios.json index 516c9af..e3ca512 100644 --- a/test/artifacts-helper/scenarios.json +++ b/test/artifacts-helper/scenarios.json @@ -70,5 +70,14 @@ "nugetAlias": true } } + }, + "test_az_shim": { + "image": "mcr.microsoft.com/devcontainers/base:debian", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": {}, + "artifacts-helper": { + "azAlias": true + } + } } } \ No newline at end of file diff --git a/test/artifacts-helper/test_az_shim.sh b/test/artifacts-helper/test_az_shim.sh new file mode 100755 index 0000000..4b224c2 --- /dev/null +++ b/test/artifacts-helper/test_az_shim.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash + +# Import test library bundled with the devcontainer CLI +source dev-container-features-test-lib || exit 1 + +# Test that az shim is installed +check "az shim exists" test -f /usr/local/share/codespace-shims/az +check "az shim is executable" test -x /usr/local/share/codespace-shims/az + +# Test that az shim sources resolve-shim.sh +check "az shim sources resolve-shim.sh" grep -q 'source.*resolve-shim.sh' /usr/local/share/codespace-shims/az + +# Test GitHub Actions environment detection +check "az shim has GitHub Actions detection" grep -q 'ACTIONS_ID_TOKEN_REQUEST_URL' /usr/local/share/codespace-shims/az + +# Test that az shim intercepts get-access-token command +check "az shim intercepts get-access-token" grep -q 'get-access-token' /usr/local/share/codespace-shims/az + +# Test argument parsing handles both formats (--resource value and --resource=value) +check "az shim handles equals format args" grep -q '\-\-resource=\*' /usr/local/share/codespace-shims/az +check "az shim handles space-separated args" grep -q '\-\-resource)' /usr/local/share/codespace-shims/az + +# Test that az shim falls back to real az CLI for other commands +TEST_HOME=$(mktemp -d) +check "az shim falls back for non-token commands" bash -c ' + export HOME='"$TEST_HOME"' + # az --version should pass through to real az CLI (if installed) + # or fail gracefully if az is not installed + output=$(/usr/local/share/codespace-shims/az --version 2>&1) || true + # Check that it either shows az version or "not found" error - both are valid + echo "$output" | grep -qE "(azure-cli|Azure CLI|not found)" && echo "SUCCESS" || echo "FAILED" +' | grep -q "SUCCESS" + +# Test that az shim handles missing azure-auth-helper gracefully +check "az shim handles missing azure-auth-helper" bash -c ' + export HOME='"$TEST_HOME"' + # Remove azure-auth-helper if it exists + rm -f "${HOME}/azure-auth-helper" + # Call az account get-access-token - should fall through to real az + # (which will fail, but shim should not crash) + /usr/local/share/codespace-shims/az account get-access-token --resource https://management.azure.com 2>&1 || true + # If we get here, the shim handled it gracefully + echo "completed" +' | grep -q "completed" + +# Test that az shim returns proper JSON format when azure-auth-helper exists +check "az shim returns valid JSON format" bash -c ' + export HOME='"$TEST_HOME"' + # Create a mock azure-auth-helper that returns a test token + cat > "${HOME}/azure-auth-helper" << '\''HELPER'\'' +#!/bin/bash +echo "test-token-12345" +HELPER + chmod +x "${HOME}/azure-auth-helper" + + # Call the shim and verify JSON output + output=$(/usr/local/share/codespace-shims/az account get-access-token --resource https://management.azure.com 2>&1) + + # Check that output contains expected JSON fields + echo "$output" | grep -q "accessToken" && \ + echo "$output" | grep -q "tokenType" && \ + echo "$output" | grep -q "Bearer" && \ + echo "SUCCESS" || echo "FAILED" +' | grep -q "SUCCESS" + +# Test GitHub Actions bypass (simulate by setting the env var) +check "az shim bypasses interception in GitHub Actions" bash -c ' + export HOME='"$TEST_HOME"' + export ACTIONS_ID_TOKEN_REQUEST_URL="https://example.com/token" + # In Actions mode, shim should skip interception and call real az directly + # (will fail if az not installed, but should not attempt token interception) + output=$(/usr/local/share/codespace-shims/az account get-access-token --resource https://management.azure.com 2>&1) || true + # Should NOT contain our mock token (which means bypass worked) + echo "$output" | grep -qv "test-token-12345" && echo "SUCCESS" || echo "FAILED" +' | grep -q "SUCCESS" + +# Cleanup +rm -rf "$TEST_HOME" + +# Report results +reportResults