From e354cbc846e759b9178ab559da7e113026e447da Mon Sep 17 00:00:00 2001 From: "Tom Meschter (from Dev Box)" Date: Mon, 27 Jul 2026 11:25:59 -0700 Subject: [PATCH 1/4] feat: add azure-validate workflow.ps1 step-driver script Replace the inline nine-step table in SKILL.md with a workflow.ps1 script that walks the agent through each validation step one at a time, tracking progress via completedStep in .azure/validate-status.json. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 59ff3cb9-ce5c-4e7e-945b-5e597907a727 --- plugin/skills/azure-validate/SKILL.md | 27 ++- .../references/scripts/workflow.ps1 | 158 ++++++++++++++++++ 2 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 plugin/skills/azure-validate/references/scripts/workflow.ps1 diff --git a/plugin/skills/azure-validate/SKILL.md b/plugin/skills/azure-validate/SKILL.md index 34cd94fe3..221bda08b 100644 --- a/plugin/skills/azure-validate/SKILL.md +++ b/plugin/skills/azure-validate/SKILL.md @@ -38,25 +38,18 @@ metadata: ## Steps -| # | Action | Reference | -|---|--------|-----------| -| 1 | **Load Plan** — Read `.azure/deployment-plan.md` for recipe and configuration. If missing → run azure-prepare first | `.azure/deployment-plan.md` | -| 2 | **Add Validation Steps** — Copy recipe "Validation Steps" to `.azure/deployment-plan.md` as children of "All validation checks pass" | [recipes/README.md](references/recipes/README.md), `.azure/deployment-plan.md` | -| 3 | **Run Validation** — Execute recipe-specific validation commands | [recipes/README.md](references/recipes/README.md) | -| 4 | **Build Verification** — Build the project and fix any errors before proceeding | See recipe | -| 5 | **Static Role Verification** — Review Bicep/Terraform for correct RBAC role assignments in code | [role-verification.md](references/role-verification.md) | -| 6 | **Record Proof** — Populate **Section 7: Validation Proof** with commands run and results | `.azure/deployment-plan.md` | -| 7 | **Resolve Errors** — Fix failures before proceeding | See recipe's `errors.md` | -| 8 | **Update Status** — Only after ALL checks pass, set status to `Validated` | `.azure/deployment-plan.md` | -| 9 | **Deploy (only if the user asked to deploy)** — If the user explicitly requested deployment, invoke **azure-deploy**. Otherwise STOP and report validation results | — | +Run the workflow script and follow its instructions. It walks you through each validation step one at a time: + +```bash +pwsh references/scripts/workflow.ps1 -WorkspacePath +``` + +Each run prints the next actions to take. Perform the actions, then re-run the script. Repeat until the script reports that the azure-validate workflow is complete. + > **⛔ VALIDATION AUTHORITY** > -> This skill is the officially verified way to set plan status to `Validated`. You MUST follow these steps to make sure every prerequisite is fulfilled before setting status to `Validated`: -> 1. Run actual validation commands (azd provision --preview, bicep build, terraform validate, etc.) -> 2. Populate **Section 7: Validation Proof** with the commands you ran and their results -> 3. Only then set status to `Validated` -> -> Do NOT set status to `Validated` without running checks and recording proof. +> This skill is the officially verified way to set plan status to `Validated`. You MUST follow the script's instructions to completion before setting status to `Validated`. +> Do NOT set status to `Validated` without doing so. --- diff --git a/plugin/skills/azure-validate/references/scripts/workflow.ps1 b/plugin/skills/azure-validate/references/scripts/workflow.ps1 new file mode 100644 index 000000000..2139819f4 --- /dev/null +++ b/plugin/skills/azure-validate/references/scripts/workflow.ps1 @@ -0,0 +1,158 @@ +<# +.SYNOPSIS + Walks the agent through the azure-validate workflow, one step at a time. +.PARAMETER WorkspacePath + Path to the workspace being validated (required). +#> +param( + [string]$WorkspacePath +) + +enum ValidationStep { + None + LoadPlan + AddValidationSteps + RunValidation + BuildVerification + StaticRoleVerification + RecordProof + ResolveErrors + UpdateStatus + Deploy +} + +if (-not $WorkspacePath) { + Write-Error "WorkspacePath is required." + exit 2 +} + +# Step 0: Initialize status file +# If .azure/validate-status.json doesn't exist, create it with completedStep = None. +$validateStatusPath = Join-Path -Path $WorkspacePath -ChildPath ".azure/validate-status.json" +if (-not (Test-Path -Path $validateStatusPath)) { + # Create the .azure directory if it doesn't exist + $azureDir = Join-Path -Path $WorkspacePath -ChildPath ".azure" + if (-not (Test-Path -Path $azureDir)) { + New-Item -ItemType Directory -Path $azureDir | Out-Null + } + + # Create the validate-status.json file + $validateStatus = @{ + completedStep = [ValidationStep]::None.ToString() + } + $validateStatus | ConvertTo-Json | Set-Content -Path $validateStatusPath + + Write-Output "Created '.azure/validate-status.json' to track validation progress." +} else { + # Load the existing validate-status.json + $validateStatus = Get-Content -Path $validateStatusPath | ConvertFrom-Json +} + +$completedStep = [ValidationStep]::None +$rawCompletedStep = $validateStatus.completedStep +if (-not [string]::IsNullOrEmpty($rawCompletedStep)) { + if (-not [enum]::TryParse([ValidationStep], $rawCompletedStep, $true, [ref]$completedStep)) { + Write-Error "Error: The completedStep property in `.azure/validate-status.json` has an invalid value: '$rawCompletedStep'." + Write-Error "Action: Set completedStep to a valid value, or 'None' to start over." + exit 2 + } +} + +# Step 1: Load Plan +# Instruct the agent to load the deployment plan, then advance completedStep to `LoadPlan` and re-run this script. +if ($completedStep -eq [ValidationStep]::None) { + Write-Output "Action: Read `.azure/deployment-plan.md` for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.ps1." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `LoadPlan`, and re-run workflow.ps1." + Write-Output "Reference: `.azure/deployment-plan.md" + exit 0 +} + +# Step 2: Add Validation Steps +# Once the plan is loaded, instruct the agent to copy the recipe's "Validation Steps" into the plan, +# then advance completedStep to `AddValidationSteps` and re-run this script. +if ($completedStep -eq [ValidationStep]::LoadPlan) { + Write-Output "Action: Copy the recipe's `Validation Steps` into `.azure/deployment-plan.md` as children of `All validation checks pass`." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `AddValidationSteps`, and re-run workflow.ps1." + Write-Output "Reference: references/recipes/README.md, `.azure/deployment-plan.md" + exit 0 +} + +# Step 3: Run Validation +# With the validation steps recorded, instruct the agent to execute the recipe-specific validation commands, +# then advance completedStep to `RunValidation` and re-run this script. +if ($completedStep -eq [ValidationStep]::AddValidationSteps) { + Write-Output "Action: Execute the recipe-specific validation commands." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `RunValidation`, and re-run workflow.ps1." + Write-Output "Reference: references/recipes/README.md" + exit 0 +} + +# Step 4: Build Verification +# With validation run, instruct the agent to build the project and fix any errors, +# then advance completedStep to `BuildVerification` and re-run this script. +if ($completedStep -eq [ValidationStep]::RunValidation) { + Write-Output "Action: Build the project and fix any errors before proceeding." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `BuildVerification`, and re-run workflow.ps1." + Write-Output "Reference: See the recipe for build details." + exit 0 +} + +# Step 5: Static Role Verification +# With the build verified, instruct the agent to review the Bicep/Terraform for correct RBAC role assignments, +# then advance completedStep to `StaticRoleVerification` and re-run this script. +if ($completedStep -eq [ValidationStep]::BuildVerification) { + Write-Output "Action: Review the Bicep/Terraform for correct RBAC role assignments in code." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `StaticRoleVerification`, and re-run workflow.ps1." + Write-Output "Reference: references/role-verification.md" + exit 0 +} + +# Step 6: Record Proof +# With roles verified, instruct the agent to record validation proof in the plan, +# then advance completedStep to `RecordProof` and re-run this script. +if ($completedStep -eq [ValidationStep]::StaticRoleVerification) { + Write-Output "Action: Populate **Section 7: Validation Proof** in the plan with the commands run and their results." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `RecordProof`, and re-run workflow.ps1." + Write-Output "Reference: `.azure/deployment-plan.md" + exit 0 +} + +# Step 7: Resolve Errors +# With proof recorded, instruct the agent to fix any failures before proceeding, +# then advance completedStep to `ResolveErrors` and re-run this script. +if ($completedStep -eq [ValidationStep]::RecordProof) { + Write-Output "Action: Fix any validation failures before proceeding." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `ResolveErrors`, and re-run workflow.ps1." + Write-Output "Reference: See the recipe's errors.md." + exit 0 +} + +# Step 8: Update Status +# Only after ALL checks pass, instruct the agent to set the plan status to `Validated`, +# then advance completedStep to `UpdateStatus` and re-run this script. +if ($completedStep -eq [ValidationStep]::ResolveErrors) { + Write-Output "Action: Only after ALL checks pass, set the plan status to `Validated`." + Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `UpdateStatus`, and re-run workflow.ps1." + Write-Output "Reference: `.azure/deployment-plan.md" + exit 0 +} + +# Step 9: Deploy +# With status updated, deploy only if the user explicitly asked to deploy; otherwise stop and report results. +# Then advance completedStep to `Deploy` and re-run this script. +if ($completedStep -eq [ValidationStep]::UpdateStatus -or $completedStep -eq [ValidationStep]::Deploy) { + # Set the completedStep to Deploy + $completedStep = [ValidationStep]::Deploy + $validateStatus.completedStep = $completedStep.ToString() + $validateStatus | ConvertTo-Json | Set-Content -Path $validateStatusPath + + Write-Output "Action: The azure-validate workflow is complete. If the user explicitly requested deployment, invoke azure-deploy. Otherwise STOP and report the validation results." + + exit 0 +} + + + + + + From ec0be35c047ffadde02ed4e5648a2a7c02bdef7e Mon Sep 17 00:00:00 2001 From: "Tom Meschter (from Dev Box)" Date: Mon, 27 Jul 2026 12:33:20 -0700 Subject: [PATCH 2/4] feat: drive azure-validate workflow via -CompletedStep param workflow.ps1 now accepts a -CompletedStep parameter and writes the progress to .azure/validate-status.json itself, instead of instructing the agent to edit the file. The agent starts the workflow by calling the script with no -CompletedStep, and each response tells it which value to pass next. This eliminates a per-step tool call by the agent. SKILL.md updated to document the new invocation pattern. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 59ff3cb9-ce5c-4e7e-945b-5e597907a727 --- plugin/skills/azure-validate/SKILL.md | 12 +- .../references/scripts/workflow.ps1 | 117 ++++++------------ 2 files changed, 51 insertions(+), 78 deletions(-) diff --git a/plugin/skills/azure-validate/SKILL.md b/plugin/skills/azure-validate/SKILL.md index 221bda08b..7a477be9c 100644 --- a/plugin/skills/azure-validate/SKILL.md +++ b/plugin/skills/azure-validate/SKILL.md @@ -38,13 +38,21 @@ metadata: ## Steps -Run the workflow script and follow its instructions. It walks you through each validation step one at a time: +Run the workflow script and follow its instructions. It walks you through each validation step one at a time. + +Start the workflow by calling the script **without** `-CompletedStep`: ```bash pwsh references/scripts/workflow.ps1 -WorkspacePath ``` -Each run prints the next actions to take. Perform the actions, then re-run the script. Repeat until the script reports that the azure-validate workflow is complete. +Each run prints the next action to take and the value to pass for `-CompletedStep`. Perform the action, then re-run the script passing that value: + +```bash +pwsh references/scripts/workflow.ps1 -WorkspacePath -CompletedStep +``` + +The script records progress itself in `.azure/validate-status.json`. Repeat until it reports that the azure-validate workflow is complete. > **⛔ VALIDATION AUTHORITY** > diff --git a/plugin/skills/azure-validate/references/scripts/workflow.ps1 b/plugin/skills/azure-validate/references/scripts/workflow.ps1 index 2139819f4..515d2ba64 100644 --- a/plugin/skills/azure-validate/references/scripts/workflow.ps1 +++ b/plugin/skills/azure-validate/references/scripts/workflow.ps1 @@ -3,9 +3,15 @@ Walks the agent through the azure-validate workflow, one step at a time. .PARAMETER WorkspacePath Path to the workspace being validated (required). +.PARAMETER CompletedStep + The workflow step the agent just completed. Omit this on the first call to + start the workflow. The script records the value in + .azure/validate-status.json and returns the next action to take, along with + the value to pass as -CompletedStep on the next call. #> param( - [string]$WorkspacePath + [string]$WorkspacePath, + [string]$CompletedStep ) enum ValidationStep { @@ -18,7 +24,6 @@ enum ValidationStep { RecordProof ResolveErrors UpdateStatus - Deploy } if (-not $WorkspacePath) { @@ -26,133 +31,93 @@ if (-not $WorkspacePath) { exit 2 } -# Step 0: Initialize status file -# If .azure/validate-status.json doesn't exist, create it with completedStep = None. -$validateStatusPath = Join-Path -Path $WorkspacePath -ChildPath ".azure/validate-status.json" -if (-not (Test-Path -Path $validateStatusPath)) { - # Create the .azure directory if it doesn't exist - $azureDir = Join-Path -Path $WorkspacePath -ChildPath ".azure" - if (-not (Test-Path -Path $azureDir)) { - New-Item -ItemType Directory -Path $azureDir | Out-Null - } - - # Create the validate-status.json file - $validateStatus = @{ - completedStep = [ValidationStep]::None.ToString() +# Resolve the step the agent just completed. +# Omitting -CompletedStep signals the start of the workflow (None). +$step = [ValidationStep]::None +if (-not [string]::IsNullOrEmpty($CompletedStep)) { + if (-not [enum]::TryParse([ValidationStep], $CompletedStep, $true, [ref]$step)) { + $validValues = ([enum]::GetNames([ValidationStep])) -join ", " + Write-Error "Error: '-CompletedStep $CompletedStep' is not a valid step. Valid values: $validValues" + exit 2 } - $validateStatus | ConvertTo-Json | Set-Content -Path $validateStatusPath - - Write-Output "Created '.azure/validate-status.json' to track validation progress." -} else { - # Load the existing validate-status.json - $validateStatus = Get-Content -Path $validateStatusPath | ConvertFrom-Json } -$completedStep = [ValidationStep]::None -$rawCompletedStep = $validateStatus.completedStep -if (-not [string]::IsNullOrEmpty($rawCompletedStep)) { - if (-not [enum]::TryParse([ValidationStep], $rawCompletedStep, $true, [ref]$completedStep)) { - Write-Error "Error: The completedStep property in `.azure/validate-status.json` has an invalid value: '$rawCompletedStep'." - Write-Error "Action: Set completedStep to a valid value, or 'None' to start over." - exit 2 - } +# Record progress in .azure/validate-status.json (creating it if needed). +$azureDir = Join-Path -Path $WorkspacePath -ChildPath ".azure" +if (-not (Test-Path -Path $azureDir)) { + New-Item -ItemType Directory -Path $azureDir | Out-Null } +$validateStatusPath = Join-Path -Path $azureDir -ChildPath "validate-status.json" +@{ completedStep = $step.ToString() } | ConvertTo-Json | Set-Content -Path $validateStatusPath + +# Emit the next action based on the step just completed. # Step 1: Load Plan -# Instruct the agent to load the deployment plan, then advance completedStep to `LoadPlan` and re-run this script. -if ($completedStep -eq [ValidationStep]::None) { +if ($step -eq [ValidationStep]::None) { Write-Output "Action: Read `.azure/deployment-plan.md` for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.ps1." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `LoadPlan`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep LoadPlan after completing the action." Write-Output "Reference: `.azure/deployment-plan.md" exit 0 } # Step 2: Add Validation Steps -# Once the plan is loaded, instruct the agent to copy the recipe's "Validation Steps" into the plan, -# then advance completedStep to `AddValidationSteps` and re-run this script. -if ($completedStep -eq [ValidationStep]::LoadPlan) { +if ($step -eq [ValidationStep]::LoadPlan) { Write-Output "Action: Copy the recipe's `Validation Steps` into `.azure/deployment-plan.md` as children of `All validation checks pass`." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `AddValidationSteps`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep AddValidationSteps after completing the action." Write-Output "Reference: references/recipes/README.md, `.azure/deployment-plan.md" exit 0 } # Step 3: Run Validation -# With the validation steps recorded, instruct the agent to execute the recipe-specific validation commands, -# then advance completedStep to `RunValidation` and re-run this script. -if ($completedStep -eq [ValidationStep]::AddValidationSteps) { +if ($step -eq [ValidationStep]::AddValidationSteps) { Write-Output "Action: Execute the recipe-specific validation commands." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `RunValidation`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep RunValidation after completing the action." Write-Output "Reference: references/recipes/README.md" exit 0 } # Step 4: Build Verification -# With validation run, instruct the agent to build the project and fix any errors, -# then advance completedStep to `BuildVerification` and re-run this script. -if ($completedStep -eq [ValidationStep]::RunValidation) { +if ($step -eq [ValidationStep]::RunValidation) { Write-Output "Action: Build the project and fix any errors before proceeding." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `BuildVerification`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep BuildVerification after completing the action." Write-Output "Reference: See the recipe for build details." exit 0 } # Step 5: Static Role Verification -# With the build verified, instruct the agent to review the Bicep/Terraform for correct RBAC role assignments, -# then advance completedStep to `StaticRoleVerification` and re-run this script. -if ($completedStep -eq [ValidationStep]::BuildVerification) { +if ($step -eq [ValidationStep]::BuildVerification) { Write-Output "Action: Review the Bicep/Terraform for correct RBAC role assignments in code." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `StaticRoleVerification`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep StaticRoleVerification after completing the action." Write-Output "Reference: references/role-verification.md" exit 0 } # Step 6: Record Proof -# With roles verified, instruct the agent to record validation proof in the plan, -# then advance completedStep to `RecordProof` and re-run this script. -if ($completedStep -eq [ValidationStep]::StaticRoleVerification) { +if ($step -eq [ValidationStep]::StaticRoleVerification) { Write-Output "Action: Populate **Section 7: Validation Proof** in the plan with the commands run and their results." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `RecordProof`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep RecordProof after completing the action." Write-Output "Reference: `.azure/deployment-plan.md" exit 0 } # Step 7: Resolve Errors -# With proof recorded, instruct the agent to fix any failures before proceeding, -# then advance completedStep to `ResolveErrors` and re-run this script. -if ($completedStep -eq [ValidationStep]::RecordProof) { +if ($step -eq [ValidationStep]::RecordProof) { Write-Output "Action: Fix any validation failures before proceeding." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `ResolveErrors`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep ResolveErrors after completing the action." Write-Output "Reference: See the recipe's errors.md." exit 0 } # Step 8: Update Status -# Only after ALL checks pass, instruct the agent to set the plan status to `Validated`, -# then advance completedStep to `UpdateStatus` and re-run this script. -if ($completedStep -eq [ValidationStep]::ResolveErrors) { +if ($step -eq [ValidationStep]::ResolveErrors) { Write-Output "Action: Only after ALL checks pass, set the plan status to `Validated`." - Write-Output "Then set the completedStep property in `.azure/validate-status.json` to `UpdateStatus`, and re-run workflow.ps1." + Write-Output "Next: re-run workflow.ps1 with -CompletedStep UpdateStatus after completing the action." Write-Output "Reference: `.azure/deployment-plan.md" exit 0 } -# Step 9: Deploy -# With status updated, deploy only if the user explicitly asked to deploy; otherwise stop and report results. -# Then advance completedStep to `Deploy` and re-run this script. -if ($completedStep -eq [ValidationStep]::UpdateStatus -or $completedStep -eq [ValidationStep]::Deploy) { - # Set the completedStep to Deploy - $completedStep = [ValidationStep]::Deploy - $validateStatus.completedStep = $completedStep.ToString() - $validateStatus | ConvertTo-Json | Set-Content -Path $validateStatusPath - +# Step 9: Deploy (workflow complete) +if ($step -eq [ValidationStep]::UpdateStatus) { Write-Output "Action: The azure-validate workflow is complete. If the user explicitly requested deployment, invoke azure-deploy. Otherwise STOP and report the validation results." - exit 0 } - - - - - - From e8f79ce3fb19c8ee2ac97e79c8ca1f9fbb6d7a97 Mon Sep 17 00:00:00 2001 From: "Tom Meschter (from Dev Box)" Date: Mon, 27 Jul 2026 14:10:45 -0700 Subject: [PATCH 3/4] feat: add bash workflow.sh for azure-validate Add a Mac/Linux bash equivalent of workflow.ps1 that drives the azure-validate workflow step-by-step via --completed-step, mirroring the PowerShell script's output exactly. Link both scripts (and restore recipe/role reference links) from SKILL.md so orphan detection passes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 59ff3cb9-ce5c-4e7e-945b-5e597907a727 --- plugin/skills/azure-validate/SKILL.md | 13 +- .../references/scripts/workflow.sh | 134 ++++++++++++++++++ 2 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 plugin/skills/azure-validate/references/scripts/workflow.sh diff --git a/plugin/skills/azure-validate/SKILL.md b/plugin/skills/azure-validate/SKILL.md index 7a477be9c..f14455c58 100644 --- a/plugin/skills/azure-validate/SKILL.md +++ b/plugin/skills/azure-validate/SKILL.md @@ -38,21 +38,18 @@ metadata: ## Steps -Run the workflow script and follow its instructions. It walks you through each validation step one at a time. +Run the workflow script and follow its instructions. It walks you through each validation step one at a time, recording progress in `.azure/validate-status.json`. Use [references/scripts/workflow.ps1](references/scripts/workflow.ps1) on Windows or [references/scripts/workflow.sh](references/scripts/workflow.sh) on macOS/Linux. -Start the workflow by calling the script **without** `-CompletedStep`: +Start by calling the script **without** the completed-step argument: ```bash pwsh references/scripts/workflow.ps1 -WorkspacePath +# macOS/Linux: bash references/scripts/workflow.sh --workspace-path ``` -Each run prints the next action to take and the value to pass for `-CompletedStep`. Perform the action, then re-run the script passing that value: +Each run prints the next action and the value to pass next. Perform the action, then re-run with that value (`-CompletedStep ` for pwsh, `--completed-step ` for bash). Repeat until it reports the azure-validate workflow is complete. -```bash -pwsh references/scripts/workflow.ps1 -WorkspacePath -CompletedStep -``` - -The script records progress itself in `.azure/validate-status.json`. Repeat until it reports that the azure-validate workflow is complete. +The steps reference recipe details in [references/recipes/README.md](references/recipes/README.md) and role checks in [references/role-verification.md](references/role-verification.md). > **⛔ VALIDATION AUTHORITY** > diff --git a/plugin/skills/azure-validate/references/scripts/workflow.sh b/plugin/skills/azure-validate/references/scripts/workflow.sh new file mode 100644 index 000000000..1cf28eaab --- /dev/null +++ b/plugin/skills/azure-validate/references/scripts/workflow.sh @@ -0,0 +1,134 @@ +#!/usr/bin/env bash +# workflow.sh +# Walks the agent through the azure-validate workflow, one step at a time. +# +# Usage: +# ./workflow.sh --workspace-path [--completed-step ] +# +# Options: +# --workspace-path Path to the workspace being validated (required). +# --completed-step The workflow step the agent just completed. Omit +# on the first call to start the workflow. The +# script records the value in +# .azure/validate-status.json and returns the next +# action to take, along with the value to pass as +# --completed-step on the next call. +# +# Exit codes: +# 0 - next action emitted (or workflow complete) +# 2 - usage / argument error (missing workspace path or invalid step) + +set -uo pipefail + +# Valid workflow steps, in order. +VALID_STEPS=(None LoadPlan AddValidationSteps RunValidation BuildVerification \ + StaticRoleVerification RecordProof ResolveErrors UpdateStatus) + +# Ensure an option that consumes a value actually has one ($@ = remaining args). +need_val() { + [ "$#" -ge 2 ] || { echo "ERROR: $1 requires a value." >&2; exit 2; } +} + +WORKSPACE_PATH="" +COMPLETED_STEP="" + +while [ $# -gt 0 ]; do + case "$1" in + --workspace-path) need_val "$@"; WORKSPACE_PATH="$2"; shift 2 ;; + --completed-step) need_val "$@"; COMPLETED_STEP="$2"; shift 2 ;; + -h|--help) + grep '^#' "$0" | grep -v '^#!' | sed 's/^# \{0,1\}//' + exit 0 ;; + *) + echo "Unknown argument: $1" >&2 + exit 2 ;; + esac +done + +if [ -z "$WORKSPACE_PATH" ]; then + echo "ERROR: --workspace-path is required." >&2 + exit 2 +fi + +# Resolve the step the agent just completed (case-insensitive). +# Omitting --completed-step signals the start of the workflow (None). +STEP="None" +if [ -n "$COMPLETED_STEP" ]; then + STEP="" + for valid in "${VALID_STEPS[@]}"; do + if [ "$(printf '%s' "$COMPLETED_STEP" | tr '[:upper:]' '[:lower:]')" = \ + "$(printf '%s' "$valid" | tr '[:upper:]' '[:lower:]')" ]; then + STEP="$valid" + break + fi + done + if [ -z "$STEP" ]; then + printf 'Error: '\''--completed-step %s'\'' is not a valid step. Valid values: %s\n' \ + "$COMPLETED_STEP" "$(printf '%s, ' "${VALID_STEPS[@]}" | sed 's/, $//')" >&2 + exit 2 + fi +fi + +# Record progress in .azure/validate-status.json (creating it if needed). +AZURE_DIR="$WORKSPACE_PATH/.azure" +mkdir -p "$AZURE_DIR" +VALIDATE_STATUS_PATH="$AZURE_DIR/validate-status.json" +printf '{\n "completedStep": "%s"\n}\n' "$STEP" > "$VALIDATE_STATUS_PATH" + +# Emit the next action based on the step just completed. +case "$STEP" in + None) + # Step 1: Load Plan + echo "Action: Read .azure/deployment-plan.md for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.sh." + echo "Next: re-run workflow.sh with --completed-step LoadPlan after completing the action." + echo "Reference: .azure/deployment-plan.md" + ;; + LoadPlan) + # Step 2: Add Validation Steps + echo "Action: Copy the recipe's Validation Steps into .azure/deployment-plan.md as children of All validation checks pass." + echo "Next: re-run workflow.sh with --completed-step AddValidationSteps after completing the action." + echo "Reference: references/recipes/README.md, .azure/deployment-plan.md" + ;; + AddValidationSteps) + # Step 3: Run Validation + echo "Action: Execute the recipe-specific validation commands." + echo "Next: re-run workflow.sh with --completed-step RunValidation after completing the action." + echo "Reference: references/recipes/README.md" + ;; + RunValidation) + # Step 4: Build Verification + echo "Action: Build the project and fix any errors before proceeding." + echo "Next: re-run workflow.sh with --completed-step BuildVerification after completing the action." + echo "Reference: See the recipe for build details." + ;; + BuildVerification) + # Step 5: Static Role Verification + echo "Action: Review the Bicep/Terraform for correct RBAC role assignments in code." + echo "Next: re-run workflow.sh with --completed-step StaticRoleVerification after completing the action." + echo "Reference: references/role-verification.md" + ;; + StaticRoleVerification) + # Step 6: Record Proof + echo "Action: Populate **Section 7: Validation Proof** in the plan with the commands run and their results." + echo "Next: re-run workflow.sh with --completed-step RecordProof after completing the action." + echo "Reference: .azure/deployment-plan.md" + ;; + RecordProof) + # Step 7: Resolve Errors + echo "Action: Fix any validation failures before proceeding." + echo "Next: re-run workflow.sh with --completed-step ResolveErrors after completing the action." + echo "Reference: See the recipe's errors.md." + ;; + ResolveErrors) + # Step 8: Update Status + echo "Action: Only after ALL checks pass, set the plan status to Validated." + echo "Next: re-run workflow.sh with --completed-step UpdateStatus after completing the action." + echo "Reference: .azure/deployment-plan.md" + ;; + UpdateStatus) + # Step 9: Deploy (workflow complete) + echo "Action: The azure-validate workflow is complete. If the user explicitly requested deployment, invoke azure-deploy. Otherwise STOP and report the validation results." + ;; +esac + +exit 0 From b6137dd7b1fad05cb720148913cace10a65af6d0 Mon Sep 17 00:00:00 2001 From: "Tom Meschter (from Dev Box)" Date: Mon, 27 Jul 2026 14:44:08 -0700 Subject: [PATCH 4/4] fix: address workflow script review feedback - Validate the workspace path exists and is a directory, failing early with a clear message instead of a later New-Item/Set-Content error. - Emit intended Markdown backticks in agent-facing output by using single-quoted PowerShell strings (backticks were being consumed as PowerShell escapes); mirror the same output in workflow.sh. - Write validate-status.json as UTF-8 without BOM so non-PowerShell JSON consumers can parse it (Windows PowerShell 5.1 defaulted to UTF-16LE). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 59ff3cb9-ce5c-4e7e-945b-5e597907a727 --- .../references/scripts/workflow.ps1 | 22 ++++++++++++------- .../references/scripts/workflow.sh | 19 ++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/plugin/skills/azure-validate/references/scripts/workflow.ps1 b/plugin/skills/azure-validate/references/scripts/workflow.ps1 index 515d2ba64..bd45a2561 100644 --- a/plugin/skills/azure-validate/references/scripts/workflow.ps1 +++ b/plugin/skills/azure-validate/references/scripts/workflow.ps1 @@ -31,6 +31,11 @@ if (-not $WorkspacePath) { exit 2 } +if (-not (Test-Path -Path $WorkspacePath -PathType Container)) { + Write-Error "Error: WorkspacePath '$WorkspacePath' does not exist or is not a directory." + exit 2 +} + # Resolve the step the agent just completed. # Omitting -CompletedStep signals the start of the workflow (None). $step = [ValidationStep]::None @@ -48,23 +53,24 @@ if (-not (Test-Path -Path $azureDir)) { New-Item -ItemType Directory -Path $azureDir | Out-Null } $validateStatusPath = Join-Path -Path $azureDir -ChildPath "validate-status.json" -@{ completedStep = $step.ToString() } | ConvertTo-Json | Set-Content -Path $validateStatusPath +$validateStatusJson = @{ completedStep = $step.ToString() } | ConvertTo-Json +[System.IO.File]::WriteAllText($validateStatusPath, $validateStatusJson + [Environment]::NewLine, (New-Object System.Text.UTF8Encoding($false))) # Emit the next action based on the step just completed. # Step 1: Load Plan if ($step -eq [ValidationStep]::None) { - Write-Output "Action: Read `.azure/deployment-plan.md` for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.ps1." + Write-Output 'Action: Read `.azure/deployment-plan.md` for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.ps1.' Write-Output "Next: re-run workflow.ps1 with -CompletedStep LoadPlan after completing the action." - Write-Output "Reference: `.azure/deployment-plan.md" + Write-Output 'Reference: `.azure/deployment-plan.md' exit 0 } # Step 2: Add Validation Steps if ($step -eq [ValidationStep]::LoadPlan) { - Write-Output "Action: Copy the recipe's `Validation Steps` into `.azure/deployment-plan.md` as children of `All validation checks pass`." + Write-Output 'Action: Copy the recipe''s `Validation Steps` into `.azure/deployment-plan.md` as children of `All validation checks pass`.' Write-Output "Next: re-run workflow.ps1 with -CompletedStep AddValidationSteps after completing the action." - Write-Output "Reference: references/recipes/README.md, `.azure/deployment-plan.md" + Write-Output 'Reference: references/recipes/README.md, `.azure/deployment-plan.md' exit 0 } @@ -96,7 +102,7 @@ if ($step -eq [ValidationStep]::BuildVerification) { if ($step -eq [ValidationStep]::StaticRoleVerification) { Write-Output "Action: Populate **Section 7: Validation Proof** in the plan with the commands run and their results." Write-Output "Next: re-run workflow.ps1 with -CompletedStep RecordProof after completing the action." - Write-Output "Reference: `.azure/deployment-plan.md" + Write-Output 'Reference: `.azure/deployment-plan.md' exit 0 } @@ -110,9 +116,9 @@ if ($step -eq [ValidationStep]::RecordProof) { # Step 8: Update Status if ($step -eq [ValidationStep]::ResolveErrors) { - Write-Output "Action: Only after ALL checks pass, set the plan status to `Validated`." + Write-Output 'Action: Only after ALL checks pass, set the plan status to `Validated`.' Write-Output "Next: re-run workflow.ps1 with -CompletedStep UpdateStatus after completing the action." - Write-Output "Reference: `.azure/deployment-plan.md" + Write-Output 'Reference: `.azure/deployment-plan.md' exit 0 } diff --git a/plugin/skills/azure-validate/references/scripts/workflow.sh b/plugin/skills/azure-validate/references/scripts/workflow.sh index 1cf28eaab..3896dc3db 100644 --- a/plugin/skills/azure-validate/references/scripts/workflow.sh +++ b/plugin/skills/azure-validate/references/scripts/workflow.sh @@ -50,6 +50,11 @@ if [ -z "$WORKSPACE_PATH" ]; then exit 2 fi +if [ ! -d "$WORKSPACE_PATH" ]; then + echo "Error: --workspace-path '$WORKSPACE_PATH' does not exist or is not a directory." >&2 + exit 2 +fi + # Resolve the step the agent just completed (case-insensitive). # Omitting --completed-step signals the start of the workflow (None). STEP="None" @@ -79,15 +84,15 @@ printf '{\n "completedStep": "%s"\n}\n' "$STEP" > "$VALIDATE_STATUS_PATH" case "$STEP" in None) # Step 1: Load Plan - echo "Action: Read .azure/deployment-plan.md for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.sh." + echo "Action: Read \`.azure/deployment-plan.md\` for recipe and configuration. If missing, run azure-prepare first, then come back to workflow.sh." echo "Next: re-run workflow.sh with --completed-step LoadPlan after completing the action." - echo "Reference: .azure/deployment-plan.md" + echo "Reference: \`.azure/deployment-plan.md" ;; LoadPlan) # Step 2: Add Validation Steps - echo "Action: Copy the recipe's Validation Steps into .azure/deployment-plan.md as children of All validation checks pass." + echo "Action: Copy the recipe's \`Validation Steps\` into \`.azure/deployment-plan.md\` as children of \`All validation checks pass\`." echo "Next: re-run workflow.sh with --completed-step AddValidationSteps after completing the action." - echo "Reference: references/recipes/README.md, .azure/deployment-plan.md" + echo "Reference: references/recipes/README.md, \`.azure/deployment-plan.md" ;; AddValidationSteps) # Step 3: Run Validation @@ -111,7 +116,7 @@ case "$STEP" in # Step 6: Record Proof echo "Action: Populate **Section 7: Validation Proof** in the plan with the commands run and their results." echo "Next: re-run workflow.sh with --completed-step RecordProof after completing the action." - echo "Reference: .azure/deployment-plan.md" + echo "Reference: \`.azure/deployment-plan.md" ;; RecordProof) # Step 7: Resolve Errors @@ -121,9 +126,9 @@ case "$STEP" in ;; ResolveErrors) # Step 8: Update Status - echo "Action: Only after ALL checks pass, set the plan status to Validated." + echo "Action: Only after ALL checks pass, set the plan status to \`Validated\`." echo "Next: re-run workflow.sh with --completed-step UpdateStatus after completing the action." - echo "Reference: .azure/deployment-plan.md" + echo "Reference: \`.azure/deployment-plan.md" ;; UpdateStatus) # Step 9: Deploy (workflow complete)