Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/plugins/azure-skills/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "azure",
"description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from Claude Code.",
"version": "1.1.98",
"version": "1.1.104",
"author": {
"name": "Microsoft",
"url": "https://www.microsoft.com"
Expand Down
2 changes: 1 addition & 1 deletion .github/plugins/azure-skills/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "azure",
"description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from Cursor.",
"version": "1.1.98",
"version": "1.1.104",
"author": {
"name": "Microsoft",
"url": "https://www.microsoft.com"
Expand Down
2 changes: 1 addition & 1 deletion .github/plugins/azure-skills/.plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "azure",
"description": "Microsoft Azure MCP and Skills integration for cloud resource management, deployments, and Azure services. Manage your Azure infrastructure, monitor applications, and deploy resources directly from your development environment.",
"version": "1.1.98",
"version": "1.1.104",
"author": {
"name": "Microsoft",
"url": "https://www.microsoft.com"
Expand Down
24 changes: 24 additions & 0 deletions .github/plugins/azure-skills/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,29 @@
# Changelog

## 1.1.104

- feat: set azd user agent env ([#2882](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2882))

## 1.1.103

- fix: split prompt-agent tool references into tools/prompt-agent/ ([#2857](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2857))

## 1.1.102

- feat: replace azure-validate AZCLI/Bicep validation steps with a shared script ([#2856](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2856))

## 1.1.101

- feat: replace azure-validate Aspire Functions secret-storage scan with a script ([#2854](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2854))

## 1.1.100

- feat: replace azure-validate Aspire ACA env-var setup with a script ([#2855](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2855))

## 1.1.99

- feat: script-ify Terraform validation preflight sequence (azure-validate) ([#2862](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2862))

## 1.1.98

- fix: improve canvas-entry gate logic and add plugin-contributed extension detection ([#2866](https://github.com/microsoft/GitHub-Copilot-for-Azure/pull/2866))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: "Pre-deployment validation for Azure readiness. Run deep checks on
license: MIT
metadata:
author: Microsoft
version: "1.1.2"
version: "1.1.6"
---

# Azure Validate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,25 @@ This check is required when **all** of these are true:

## Detection

Search for `AddAzureFunctionsProject` in the AppHost source file(s):
Run the scan script — it finds `*.cs` files that call `AddAzureFunctionsProject`, checks whether each one already sets `AzureWebJobsSecretStorageType`, and prints a single verdict so you don't have to parse raw grep output.

**Bash** — [`scripts/scan-aspire-functions-secrets.sh`](scripts/scan-aspire-functions-secrets.sh):
```bash
grep -rn "AddAzureFunctionsProject" . --include="*.cs"
./scripts/scan-aspire-functions-secrets.sh [directory] # directory defaults to .
```

**PowerShell:**
**PowerShell** — [`scripts/scan-aspire-functions-secrets.ps1`](scripts/scan-aspire-functions-secrets.ps1):
```powershell
Get-ChildItem -Recurse -Filter "*.cs" | Select-String "AddAzureFunctionsProject" -List
.\scripts\scan-aspire-functions-secrets.ps1 [-Path <directory>] # -Path defaults to .
```

If found, check whether `AzureWebJobsSecretStorageType` is already configured in those same file(s):
The script prints one of three verdicts:

```bash
# Check only the AppHost file(s) that contain AddAzureFunctionsProject
find . -name "*.cs" -path "*AppHost*" -print0 | xargs -0 grep -l "AddAzureFunctionsProject" 2>/dev/null | xargs grep -l "AzureWebJobsSecretStorageType"
```

**PowerShell:**
```powershell
Get-ChildItem -Recurse -Filter "*.cs" |
Where-Object { $_.FullName -match "AppHost" } |
Select-String "AddAzureFunctionsProject" -List |
ForEach-Object { Select-String "AzureWebJobsSecretStorageType" -Path $_.Path }
```

**If `AddAzureFunctionsProject` is present but `AzureWebJobsSecretStorageType` is NOT configured in the same file → fix is required.**
| Verdict | Meaning | Action |
|---------|---------|--------|
| `NOT APPLICABLE` | No `AddAzureFunctionsProject` call found | Skip this check |
| `ALREADY CONFIGURED` | Every matching file already sets `AzureWebJobsSecretStorageType` | No change required |
| `FIX REQUIRED` | Matching file(s) call `AddAzureFunctionsProject` but omit the setting (file/line listed) | Apply the **Fix** below to each listed file |

## Fix

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,84 +9,54 @@ Validation steps for Azure CLI deployments.

## Validation Steps

- [ ] 1. Azure CLI Installation
- [ ] 2. Authentication
- [ ] 3. Bicep Compilation
- [ ] 4. Template Validation
- [ ] 5. What-If Preview
- [ ] 6. Docker Build (if containerized)
- [ ] 7. Azure Policy Validation
- [ ] 1. Core Validation (CLI, auth, build, validate, what-if) — run [`validate-deployment` script](../scripts/validate-deployment.sh)
- [ ] 2. Docker Build (if containerized)
- [ ] 3. Azure Policy Validation

## Validation Details

### 1. Azure CLI Installation
### 1. Core Validation Script

Verify Azure CLI is installed:
The core validation checks are a fixed, deterministic sequence. Run the shared
**validate-deployment** helper instead of executing and parsing each command by hand. It
confirms the Azure CLI is installed and authenticated, compiles the Bicep template
(`az bicep build`), validates it against the target scope (`az deployment ... validate`),
and runs a what-if preview — printing a compact PASS/FAIL summary plus a what-if change
count (Create/Modify/Delete).

```bash
az version
```

**If not installed:**
```
mcp_azure_mcp_extension_cli_install(cli-type: "az")
```

### 2. Authentication
- Bash: [`../scripts/validate-deployment.sh`](../scripts/validate-deployment.sh)
- PowerShell: [`../scripts/validate-deployment.ps1`](../scripts/validate-deployment.ps1)

```bash
az account show
```
**Subscription scope:**

**If not logged in:**
```bash
az login
../scripts/validate-deployment.sh --scope sub --location <location>
```

**Set subscription:**
```bash
az account set --subscription <subscription-id>
```powershell
../scripts/validate-deployment.ps1 -Scope sub -Location <location>
```

### 3. Bicep Compilation
**Resource group scope:**

```bash
az bicep build --file ./infra/main.bicep
../scripts/validate-deployment.sh --scope group --resource-group <rg-name>
```

### 4. Template Validation

```bash
# Subscription scope
az deployment sub validate \
--location <location> \
--template-file ./infra/main.bicep \
--parameters ./infra/main.parameters.json

# Resource group scope
az deployment group validate \
--resource-group <rg-name> \
--template-file ./infra/main.bicep \
--parameters ./infra/main.parameters.json
```powershell
../scripts/validate-deployment.ps1 -Scope group -ResourceGroup <rg-name>
```

### 5. What-If Preview
Defaults: `--template ./infra/main.bicep`, `--parameters ./infra/main.parameters.json`
(skipped if absent). Pass `--subscription <id>` to target a specific subscription.

```bash
# Subscription scope
az deployment sub what-if \
--location <location> \
--template-file ./infra/main.bicep \
--parameters ./infra/main.parameters.json

# Resource group scope
az deployment group what-if \
--resource-group <rg-name> \
--template-file ./infra/main.bicep \
--parameters ./infra/main.parameters.json
```
**Interpreting results:**

- `OVERALL: PASS` — all five checks passed; record the summary in Section 7 (Validation Proof).
- Any step `FAIL` — the script prints the failing command's error. Remediate:
- **Authenticated** fails → `az login`, then `az account set --subscription <id>`.
- **Azure CLI installed** fails → install via `mcp_azure_mcp_extension_cli_install(cli-type: "az")`.
- Otherwise see [Error handling](./errors.md).

### 6. Docker Build (if containerized)
### 2. Docker Build (if containerized)

**Before building**, validate the Docker build context:

Expand All @@ -105,7 +75,7 @@ npm install --package-lock-only
docker build -t <image>:test ./src/<service>
```

### 7. Azure Policy Validation
### 3. Azure Policy Validation

See [Policy Validation Guide](../../policy-validation.md) for instructions on retrieving and validating Azure policies for your subscription.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,14 @@ See [Aspire Functions Secrets Reference](../../aspire-functions-secrets.md) for

When using Aspire with Container Apps in "limited mode" (in-memory infrastructure generation), `azd provision` creates Azure resources but doesn't automatically populate environment variables that `azd deploy` needs.

**Check if environment variables are set:**
**Run the helper script** ([scripts/set-aspire-aca-env.sh](scripts/set-aspire-aca-env.sh) or [scripts/set-aspire-aca-env.ps1](scripts/set-aspire-aca-env.ps1)). It sets `AZURE_CONTAINER_REGISTRY_ENDPOINT`, `AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID`, and `MANAGED_IDENTITY_CLIENT_ID` (only the ones that are missing).

**bash:**
```bash
azd env get-values | grep -E "AZURE_CONTAINER_REGISTRY_ENDPOINT|AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID|MANAGED_IDENTITY_CLIENT_ID"
```

**If any are missing, set them now BEFORE running `azd deploy`:**

```bash
# Get resource group name
RG_NAME=$(azd env get-values | grep AZURE_RESOURCE_GROUP | cut -d'=' -f2 | tr -d '"')

# Set required variables
azd env set AZURE_CONTAINER_REGISTRY_ENDPOINT $(az acr list --resource-group "$RG_NAME" --query "[0].loginServer" -o tsv)
azd env set AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID $(az identity list --resource-group "$RG_NAME" --query "[0].id" -o tsv)
azd env set MANAGED_IDENTITY_CLIENT_ID $(az identity list --resource-group "$RG_NAME" --query "[0].clientId" -o tsv)
./scripts/set-aspire-aca-env.sh # or: -e <azd-env-name>
```

**PowerShell:**
```powershell
# Get resource group name
$rgName = (azd env get-values | Select-String 'AZURE_RESOURCE_GROUP').Line.Split('=')[1].Trim('"')

# Set required variables
azd env set AZURE_CONTAINER_REGISTRY_ENDPOINT (az acr list --resource-group $rgName --query "[0].loginServer" -o tsv)
azd env set AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID (az identity list --resource-group $rgName --query "[0].id" -o tsv)
azd env set MANAGED_IDENTITY_CLIENT_ID (az identity list --resource-group $rgName --query "[0].clientId" -o tsv)
./scripts/set-aspire-aca-env.ps1 # or: -Environment <azd-env-name>
```

**Why this is needed:** Aspire's "limited mode" generates infrastructure in-memory. While `azd provision` creates all necessary Azure resources (Container Registry, Managed Identity, Container Apps Environment), it doesn't populate the environment variables that reference those resources. The `azd deploy` phase requires these variables to authenticate with the container registry and configure managed identity bindings.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<#
.SYNOPSIS
Set the Container Apps environment variables that Aspire "limited mode" leaves unpopulated.

.DESCRIPTION
When Aspire runs in "limited mode", `azd provision` creates the Azure resources
(Container Registry, Managed Identity, Container Apps Environment) but does NOT populate the
env vars that `azd deploy` needs to reference them. This script fills that gap.

Run it AFTER `azd provision` but BEFORE `azd deploy`.

The script only sets a variable if it is currently missing, and prints what it did so the
result can be understood without re-inspecting `azd env get-values`:
AZURE_CONTAINER_REGISTRY_ENDPOINT <- az acr list ... [0].loginServer
AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID <- az identity list ... [0].id
MANAGED_IDENTITY_CLIENT_ID <- az identity list ... [0].clientId

.PARAMETER Environment
Optional azd environment name (forwarded to `azd env` calls).
Defaults to the current/default azd environment.

.EXAMPLE
./set-aspire-aca-env.ps1

.EXAMPLE
./set-aspire-aca-env.ps1 -Environment my-azd-env
#>

param(
[string]$Environment
)

# Shared `-e <name>` argument list for azd calls (empty when no env name given).
$azdEnvArgs = @()
if ($Environment) {
$azdEnvArgs = @('-e', $Environment)
}

# Capture azd environment values and verify the call succeeded. PowerShell does not treat a
# native command's non-zero exit code as a terminating error, so check $LASTEXITCODE explicitly
# rather than relying on $ErrorActionPreference.
$azdOutput = azd env get-values @azdEnvArgs
if ($LASTEXITCODE -ne 0) {
Write-Error "'azd env get-values' failed with exit code $LASTEXITCODE. Run 'azd provision' before this script so the azd environment is available."
exit 1
}

# Load azd environment values into a hashtable.
$azdValues = @{}
foreach ($line in $azdOutput) {
if (-not $line) { continue }
$name, $value = $line.Split('=', 2)
$azdValues[$name] = $value.Trim('"')
}

$rgName = $azdValues['AZURE_RESOURCE_GROUP']
if (-not $rgName) {
Write-Error "AZURE_RESOURCE_GROUP is not set in the azd environment. Run 'azd provision' before this script so the resource group is available."
exit 1
}

function Set-IfMissing {
param(
[string]$VarName,
[string]$Description,
[scriptblock]$ValueCommand
)

$existing = $azdValues[$VarName]
if ($existing) {
Write-Host "${VarName}: already present ($existing)"
return
}

$value = (& $ValueCommand)
if (-not $value) {
Write-Error "Could not resolve $VarName ($Description) in resource group '$rgName'. Confirm 'azd provision' completed and the resource exists."
exit 1
}

azd env set @azdEnvArgs $VarName $value
Write-Host "${VarName}: set to $value"
}

Write-Host "Resource group: $rgName"

Set-IfMissing `
-VarName 'AZURE_CONTAINER_REGISTRY_ENDPOINT' `
-Description 'container registry login server' `
-ValueCommand { az acr list --resource-group $rgName --query "[0].loginServer" -o tsv }

Set-IfMissing `
-VarName 'AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID' `
-Description 'managed identity resource id' `
-ValueCommand { az identity list --resource-group $rgName --query "[0].id" -o tsv }

Set-IfMissing `
-VarName 'MANAGED_IDENTITY_CLIENT_ID' `
-Description 'managed identity client id' `
-ValueCommand { az identity list --resource-group $rgName --query "[0].clientId" -o tsv }

Write-Host "Aspire Container Apps environment variables are ready for 'azd deploy'."
Loading
Loading