Skip to content

[DevOps] PR Builds: PR deployment and cleanup workflows#2033

Draft
flanakin wants to merge 3 commits intodevfrom
flanakin/pr-deploy-workflows
Draft

[DevOps] PR Builds: PR deployment and cleanup workflows#2033
flanakin wants to merge 3 commits intodevfrom
flanakin/pr-deploy-workflows

Conversation

@flanakin
Copy link
Collaborator

🛠️ Description

Adds two GitHub Actions workflows for per-PR template deployment CI:

ftk-pr-deploy.yml

  • Triggers on PRs that change src/templates/** files (excluding docs/tests)
  • Parses PR body checkboxes (from [DevOps] PR Builds: Add deployment checkboxes to PR template #2031) to determine which deployments to run
  • 6 deployment variants run in parallel with isolated resource groups (pr-{number}-{variant}):
    • Hubs with ADX (managed exports)
    • Hubs with Fabric (manual exports)
    • Hubs storage-only (manual exports)
    • Hubs storage-only (no data)
    • Workbooks
    • Alerts
  • Posts PR comments with deployment status and Azure portal links
  • Supports fork PRs via Needs: Deployment label + pull_request_target (verifies no .github/ modifications)
  • Concurrency group cancels in-progress deployments on new pushes

ftk-pr-cleanup.yml

  • Triggers on PR close (merged or not)
  • Deletes all resource groups matching pr-{number}-*
  • Posts cleanup confirmation comment
  • Creates a GitHub issue assigned to the PR author if cleanup fails

Dependencies

This is PR D (final) of a multi-PR effort to add per-PR deployment CI.

📋 Checklist

🔬 How did you test this change?

  • 🤏 Lint tests
  • 🤞 PS -WhatIf / az validate
  • 👍 Manually deployed + verified
  • 💪 Unit tests
  • 🙌 Integration tests

🙋‍♀️ Do any of the following that apply?

  • 🚨 This is a breaking change.
  • 🤏 The change is less than 20 lines of code.

📑 Did you update docs/changelog.md?

  • ✅ Updated changelog (required for dev PRs)
  • ➡️ Will add log in a future PR (feature branch PRs only)
  • ❎ Log not needed (small/internal change)

📖 Did you update documentation?

  • ✅ Public docs in docs (required for dev)
  • ✅ Public docs in docs-mslearn (required for dev)
  • ✅ Internal dev docs in docs-wiki (required for dev)
  • ✅ Internal dev docs in src (required for dev)
  • ➡️ Will add docs in a future PR (feature branch PRs only)
  • ❎ Docs not needed (small/internal change)

Creates two GitHub Actions workflows for per-PR template deployments:

ftk-pr-deploy.yml:
- Triggers on PRs that change src/templates/** files
- Parses PR body checkboxes to determine deployment variants
- Supports: ADX (managed), Fabric (manual), manual, no-data, workbooks, alerts
- Each variant deploys in parallel with isolated resource groups (pr-{number}-{variant})
- Posts PR comments with deployment status and portal links
- Supports fork PRs via "Needs: Deployment" label + pull_request_target
- Verifies fork PRs don't modify .github/ files

ftk-pr-cleanup.yml:
- Triggers on PR close (merged or not)
- Deletes all resource groups matching pr-{number}-*
- Posts cleanup confirmation comment
- Creates GitHub issue assigned to PR author if cleanup fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@flanakin flanakin requested a review from MSBrett as a code owner February 28, 2026 11:47
Copilot AI review requested due to automatic review settings February 28, 2026 11:47
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Review 👀 PR that is ready to be reviewed label Feb 28, 2026
@microsoft-github-policy-service microsoft-github-policy-service bot added the Skill: DevOps GitHub setup and automation label Feb 28, 2026
@flanakin flanakin changed the title Add per-PR deployment and cleanup workflows [DevOps] PR Builds: PR deployment and cleanup workflows Feb 28, 2026
@flanakin flanakin marked this pull request as draft February 28, 2026 11:49
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds GitHub Actions workflows to support per-PR Azure template deployments (FinOps hubs + variants, workbooks, alerts) and automatic cleanup of PR-specific resource groups, aligning with the toolkit’s CI automation goals for validating src/templates/** changes.

Changes:

  • Introduces ftk-pr-deploy.yml to parse PR-body deployment checkboxes and run selected deployments with PR-scoped resource groups.
  • Introduces ftk-pr-cleanup.yml to delete PR-scoped resource groups on PR close and notify via PR comment / issue on failure.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

File Description
.github/workflows/ftk-pr-deploy.yml New per-PR deployment workflow (checkbox parsing, fork label gating, parallel deployment jobs, PR comments).
.github/workflows/ftk-pr-cleanup.yml New cleanup workflow to remove pr-{number}-* resource groups and report failures.

Comment on lines 79 to 105
- name: Parse deployment checkboxes
id: parse
run: |
body='${{ github.event.pull_request.body }}'

parse_checkbox() {
local pattern="$1"
local output_name="$2"
if echo "$body" | grep -qE "\- \[x\] $pattern"; then
echo "$output_name=true" >> "$GITHUB_OUTPUT"
return 0
else
echo "$output_name=false" >> "$GITHUB_OUTPUT"
return 1
fi
}

any=false

parse_checkbox "Hubs + ADX \(managed\)" "deploy-adx" && any=true
parse_checkbox "Hubs + Fabric \(manual\)" "deploy-fabric" && any=true
parse_checkbox "Hubs \(manual\)" "deploy-manual" && any=true
parse_checkbox "Hubs \(no data\)" "deploy-nodata" && any=true
parse_checkbox "Workbooks" "deploy-workbooks" && any=true
parse_checkbox "Alerts" "deploy-alerts" && any=true

echo "any-selected=$any" >> "$GITHUB_OUTPUT"
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

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

This workflow depends on PR-template checkboxes, but the current .github/PULL_REQUEST_TEMPLATE.md in the repo does not contain the referenced deployment options. As-is, any-selected will never become true and no deployments will run. Either include/update the PR template in this PR or ensure the checkbox text here matches the merged template exactly (and document the dependency).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is a known dependency. We're holding the PR in a draft state until #2031 is complete.

flanakin and others added 2 commits February 28, 2026 22:19
- Fix PR body script injection: use env var instead of inline interpolation
- Escape literal + in regex patterns for checkbox matching
- Fix azure/login: use @v2 release tag instead of branch ref
- Fix job name typo: "Hubs + (manual)" → "Hubs (manual)"
- Remove unused any-selected output

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Tighten pull_request_target condition to only fire on Needs: Deployment label
- Expand fork safety check to block src/scripts/ changes
- Add Fabric URI validation before deploy (fails fast as first step)
- Change cleanup trigger to pull_request_target for fork PR secret access
- Add -ErrorAction Stop to Remove-AzResourceGroup for proper error handling
- Fix assignee fallback for external contributors on cleanup failure issues

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@flanakin
Copy link
Collaborator Author

flanakin commented Mar 1, 2026

🤖 [AI][Claude] PR Update Summary

Addressed: 9 thread(s)

  • ✅ Implemented: 6
  • 🤔 Needs discussion: 3

Changes:

  • Tightened pull_request_target condition to only fire on Needs: Deployment label
  • Expanded fork safety check to also block src/scripts/ changes (security)
  • Added Fabric URI validation as first step in deploy-fabric job (fail fast)
  • Changed cleanup trigger to pull_request_target for fork PR secret access
  • Added -ErrorAction Stop to Remove-AzResourceGroup for proper try/catch behavior
  • Split issue creation and assignee into separate steps with fallback for external contributors

Push-backs (code already correct):

  • grep + escaping — patterns already use \+ which is correct in ERE
  • PR body injection — already using env: var, not inlined in shell
  • Deploy-Hub params dependency — known, covered by draft status

@flanakin flanakin added this to the v14 milestone Mar 2, 2026
shell: pwsh
run: |
./src/scripts/Deploy-Hub -PR -Name "${{ github.event.pull_request.number }}-fabric" `
-Fabric "${{ needs.check-options.outputs.fabric-uri }}" `
Copy link
Collaborator

Choose a reason for hiding this comment

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

Script injection risk: fabric-uri is extracted from the PR body (user-controlled) and interpolated directly into a shell command via ${{ needs.check-options.outputs.fabric-uri }}. A malicious PR body could inject arbitrary PowerShell here.

This should use an environment variable (like the PR body fix in commit 2):

    env:
      FABRIC_URI: ${{ needs.check-options.outputs.fabric-uri }}
    run: |
      ./src/scripts/Deploy-Hub -PR -Name "..." -Fabric "$env:FABRIC_URI" ...

enable-AzPSSession: true

- name: Deploy
shell: pwsh
Copy link
Collaborator

Choose a reason for hiding this comment

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

pull_request_target + checkout head.sha security concern: This is the classic pull_request_target vulnerability pattern. The fork safety check blocks .github/ and src/scripts/ modifications, but an attacker could still modify Bicep templates in src/templates/ to deploy malicious ARM resources using the CI credentials (Contributor + User Access Administrator on the subscription). The safety check would need to be much more restrictive (or use an approval gate on the ftk-pr environment) to fully mitigate this.


- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Massive step duplication: The Az module install + Azure login + checkout + post-comment steps are copy-pasted across all 6 jobs (~50 lines each). A reusable workflow or composite action would cut this significantly and make future updates (e.g., bumping module versions) a single-line change.

- name: Install Az modules
shell: pwsh
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Copy link
Collaborator

Choose a reason for hiding this comment

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

No job timeout: None of the deployment jobs set timeout-minutes. ADX deployments in particular can run long, and without a cap this could lead to runaway CI costs. Consider adding timeout-minutes: 30 (or appropriate value) to each job.

ref: ${{ github.event.pull_request.head.sha }}

- name: Azure login
uses: azure/login@v2
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hardcoded Az module versions: Az.Accounts 2.19.0, Az.Resources 6.16.2, Az.Storage 6.2.0 are pinned across 6 jobs with no note about when/how to update. These will go stale — consider centralizing them as workflow-level env variables at minimum.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs: Review 👀 PR that is ready to be reviewed Skill: DevOps GitHub setup and automation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants