Skip to content

Instantly share code, notes, and snippets.

@joperezr
Created January 12, 2026 18:39
Show Gist options
  • Select an option

  • Save joperezr/bd762931321aab1fde098d491a8fe609 to your computer and use it in GitHub Desktop.

Select an option

Save joperezr/bd762931321aab1fde098d491a8fe609 to your computer and use it in GitHub Desktop.
Aspire Release Automation

Product Requirements Document: Aspire Release Automation

Document Version: 1.0
Last Updated: January 9, 2026
Author: Release Engineering Team
Status: Draft - Pending Review


Table of Contents

  1. Executive Summary
  2. Problem Statement
  3. Goals and Objectives
  4. Scope
  5. Current Manual Release Process
  6. Proposed Automated Solution
  7. Detailed Requirements
  8. Architecture and Design
  9. Security Considerations
  10. Implementation Plan
  11. Testing Strategy
  12. Rollback Plan
  13. Success Metrics
  14. Open Questions
  15. Appendix

Executive Summary

This document outlines the requirements for automating the release process for the dotnet/aspire repository. The current release process is entirely manual, requiring a release manager to perform multiple sequential tasks including NuGet package publishing, Git tagging, GitHub release creation, merge PR creation, dependency flow channel promotion, and baseline version updates.

The proposed solution splits automation between Azure DevOps (AzDO) pipelines for infrastructure-related tasks (NuGet publishing, darc channel promotion) and GitHub Actions workflows for GitHub-specific tasks (tagging, release creation, merge PR creation, baseline version update PRs).


Problem Statement

Current Challenges

  1. Manual Process Risk: The release process involves 8+ distinct manual steps, each with potential for human error.
  2. Single Point of Failure: Only the release manager (or a small group) knows the complete process, creating a bus factor issue.
  3. Time-Consuming: Each release takes significant manual effort that could be automated.
  4. Inconsistency: Manual processes can lead to inconsistent release artifacts (e.g., release notes formatting, tag naming).
  5. Security Token Management: Short-lived API tokens are generated manually for each release.
  6. Knowledge Transfer: Onboarding new release managers requires extensive documentation and shadowing.

Business Impact

  • Release delays due to release manager availability
  • Potential for shipping incorrect packages or missing steps
  • Inefficient use of engineering time
  • Difficulty scaling release operations

Goals and Objectives

Primary Goals

  1. Automate 90%+ of the release process while maintaining human oversight for critical decisions
  2. Enable any maintainer to execute a release with minimal training
  3. Reduce release time from hours to minutes
  4. Eliminate human error in repetitive tasks
  5. Maintain audit trail of all release actions
  6. Ensure idempotency - workflows/pipelines can be safely re-run on failure without duplicating work
  7. Document the release process publicly - create comprehensive documentation so the process is transparent and accessible

Non-Goals

  1. Automating aka.ms link updates (handled separately)
  2. Fully unattended releases (human initiation and approval required)
  3. Automating release branch creation (this is a separate process)

Scope

In Scope

Task Automation Target
Download signed packages from AzDO build AzDO Pipeline
Publish packages to NuGet.org AzDO Pipeline
Promote build to Aspire GA channel (darc) AzDO Pipeline
Create Git tag from build commit GitHub Actions
Push tag to GitHub GitHub Actions
Create GitHub Release with auto-generated notes GitHub Actions
Create merge PR (release → main) GitHub Actions
Create PR to update PackageValidationBaselineVersion GitHub Actions
Public release process documentation docs/release-process.md

Out of Scope

  • aka.ms link updates
  • Release branch creation/management
  • Pre-release validation/testing
  • Communication/announcement automation
  • VS Code extension marketplace publishing (if applicable)

Current Manual Release Process

Step-by-Step Breakdown

┌─────────────────────────────────────────────────────────────────┐
│                    CURRENT MANUAL PROCESS                       │
├─────────────────────────────────────────────────────────────────┤
│ 1. Generate short-lived NuGet API token (1 day)                │
│    └─► Security: Minimize exposure window                       │
│                                                                 │
│ 2. Identify final build from release branch in AzDO            │
│    └─► Example: Build 20260109.1 from release/13.2              │
│                                                                 │
│ 3. Download "PackageArtifacts" from selected build              │
│    └─► Contains all signed .nupkg files                         │
│                                                                 │
│ 4. Push all packages to NuGet.org                               │
│    └─► Command: for /f %x in ('dir /s /b *.nupkg')             │
│                 do dotnet nuget push %x -k <key> -s nuget.org   │
│                                                                 │
│ 5. Tag the commit with version (e.g., v13.2.0)                 │
│    └─► git tag v13.2.0 <commit-sha>                            │
│    └─► git push origin v13.2.0                                  │
│                                                                 │
│ 6. Create GitHub Release from tag                               │
│    └─► Use "Auto-generate release notes" feature                │
│                                                                 │
│ 7. Create merge PR: release/13.2 → main                        │
│    └─► Manual review required for release-specific changes      │
│                                                                 │
│ 8. Promote build to GA channel using darc                       │
│    └─► darc add-build-to-channel <BARBuildId>                   │
│         --channel 'Aspire 9.x GA'                               │
│                                                                 │
│ 9. Update PackageValidationBaselineVersion in PR               │
│    └─► src/Directory.Build.props                                │
│    └─► Current value: 13.0.2 → New value: 13.2.0               │
└─────────────────────────────────────────────────────────────────┘

Current File Locations

Item Location
Package Validation Baseline src/Directory.Build.propsPackageValidationBaselineVersion
darc initialization eng/common/darc-init.ps1
Build pipeline eng/pipelines/azure-pipelines.yml
Existing GH workflows .github/workflows/*.yml

Proposed Automated Solution

Architecture Overview

┌──────────────────────────────────────────────────────────────────────────┐
│                        RELEASE AUTOMATION ARCHITECTURE                    │
├──────────────────────────────────────────────────────────────────────────┤
│                                                                          │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    AZURE DEVOPS PIPELINE                         │    │
│  │              (release-publish-nuget.yml)                         │    │
│  │                                                                   │    │
│  │  INPUTS:                                                         │    │
│  │  ├─ AzDO Build ID (required)                                     │    │
│  │  ├─ Release Version (e.g., 13.2.0) (required)                   │    │
│  │  ├─ GA Channel Name (optional, default: "Aspire 9.x GA")        │    │
│  │  ├─ Dry Run Mode (optional, default: false)                      │    │
│  │  ├─ Skip NuGet Publish (optional, for re-runs)                  │    │
│  │  └─ Skip Channel Promotion (optional, for re-runs)              │    │
│  │                                                                   │    │
│  │  AUTO-EXTRACTED:                                                 │    │
│  │  └─ BAR Build ID (from build tags: "BAR ID - NNNNNN")           │    │
│  │                                                                   │    │
│  │  SECRETS (from Variable Groups):                                 │    │
│  │  ├─ NuGetApiKey (stored in secure variable group)               │    │
│  │  └─ Darc: Maestro Production (Azure service connection)         │    │
│  │                                                                   │    │
│  │  STEPS (all idempotent):                                         │    │
│  │  1. Extract BAR Build ID from build tags                        │    │
│  │  2. Download PackageArtifacts from specified build               │    │
│  │  3. Validate package signatures                                  │    │
│  │  4. Push packages to NuGet.org (--skip-duplicate)               │    │
│  │  5. Promote build to GA channel via darc                         │    │
│  │  6. Output: Commit SHA, Package list, Success/Failure status     │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                    │                                     │
│                                    ▼                                     │
│  ┌─────────────────────────────────────────────────────────────────┐    │
│  │                    GITHUB ACTIONS WORKFLOW                       │    │
│  │                   (release-github-tasks.yml)                     │    │
│  │                                                                   │    │
│  │  TRIGGER: workflow_dispatch (manual)                             │    │
│  │                                                                   │    │
│  │  INPUTS:                                                         │    │
│  │  ├─ Release Version (e.g., 13.2.0) (required)                   │    │
│  │  ├─ Commit SHA to tag (required)                                │    │
│  │  ├─ Release Branch (e.g., release/13.2) (required)              │    │
│  │  ├─ Is Prerelease (optional, default: false)                    │    │
│  │  ├─ Skip Tag/Release (optional, for re-runs)                    │    │
│  │  ├─ Skip Merge PR (optional, for re-runs)                       │    │
│  │  └─ Skip Baseline PR (optional, for re-runs)                    │    │
│  │                                                                   │    │
│  │  USES APPROVED ACTIONS ONLY:                                     │    │
│  │  ├─ actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683   │    │
│  │  ├─ dotnet/actions-create-pull-request@e8d799aa1...             │    │
│  │  └─ gh CLI (pre-installed on runners)                           │    │
│  │                                                                   │    │
│  │  PERMISSIONS (using GITHUB_TOKEN):                               │    │
│  │  ├─ contents: write (for tags)                                   │    │
│  │  └─ pull-requests: write (for PRs)                              │    │
│  │                                                                   │    │
│  │  JOBS (all idempotent - skip if already done):                  │    │
│  │                                                                   │    │
│  │  Job 1: create-tag-and-release                                   │    │
│  │  ├─ Check if tag exists, skip if so                             │    │
│  │  ├─ Create annotated tag v{version} at commit                   │    │
│  │  ├─ Check if release exists, skip if so                         │    │
│  │  └─ Create GitHub Release with auto-generated notes              │    │
│  │                                                                   │    │
│  │  Job 2: create-merge-pr                                          │    │
│  │  ├─ Use dotnet/actions-create-pull-request                      │    │
│  │  └─ (handles existing PR gracefully)                            │    │
│  │                                                                   │    │
│  │  Job 3: create-baseline-version-pr                               │    │
│  │  ├─ Update PackageValidationBaselineVersion                     │    │
│  │  └─ Use dotnet/actions-create-pull-request                      │    │
│  └─────────────────────────────────────────────────────────────────┘    │
│                                                                          │
└──────────────────────────────────────────────────────────────────────────┘

Workflow Sequence

┌────────────────────────────────────────────────────────────────────────┐
│                         RELEASE WORKFLOW SEQUENCE                       │
├────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│   PHASE 1: NUGET PUBLISHING (AzDO Pipeline)                            │
│   ─────────────────────────────────────────                            │
│                                                                         │
│   Release Manager                                                       │
│        │                                                                │
│        ├─► 1. Identify final build in AzDO (Build ID only)            │
│        │      (BAR Build ID is auto-extracted from build tags)         │
│        │                                                                │
│        ├─► 2. Queue AzDO pipeline with parameters:                     │
│        │      • Build ID: 20260109.1                                   │
│        │      • Version: 13.2.0                                        │
│        │      • Channel: "Aspire 9.x GA" (optional, has default)       │
│        │                                                                │
│        └─► 3. Pipeline executes:                                       │
│              ├─ Extracts BAR Build ID from build tags                  │
│              ├─ Downloads PackageArtifacts                             │
│              ├─ Validates signatures                                    │
│              ├─ Pushes to NuGet.org (idempotent with --skip-duplicate) │
│              ├─ Promotes to GA channel (idempotent)                    │
│              └─ Outputs commit SHA                                      │
│                                                                         │
│   ════════════════════════════════════════════════════════════════     │
│                                                                         │
│   PHASE 2: GITHUB TASKS (GitHub Actions)                               │
│   ──────────────────────────────────────                               │
│                                                                         │
│   Release Manager                                                       │
│        │                                                                │
│        ├─► 4. Trigger GitHub workflow with parameters:                 │
│        │      • Version: 13.2.0                                        │
│        │      • Commit SHA: abc123def456                               │
│        │      • Release Branch: release/13.2                           │
│        │                                                                │
│        └─► 5. Workflow executes (parallel jobs):                       │
│              │  (All jobs are idempotent - safe to re-run)             │
│              │                                                          │
│              ├─► Job A: Create & push tag v13.2.0                      │
│              │          Create GitHub Release                           │
│              │          (skips if already exists)                       │
│              │                                                          │
│              ├─► Job B: Create merge PR (release/13.2 → main)         │
│              │          (skips if PR already exists)                   │
│              │                                                          │
│              └─► Job C: Create baseline version update PR              │
│                         (skips if PR already exists)                   │
│                                                                         │
│   ════════════════════════════════════════════════════════════════     │
│                                                                         │
│   PHASE 3: MANUAL REVIEW & MERGE                                       │
│   ──────────────────────────────────────                               │
│                                                                         │
│   Maintainers                                                           │
│        │                                                                │
│        ├─► 6. Review merge PR, resolve conflicts, adjust as needed    │
│        │                                                                │
│        └─► 7. Review baseline version PR, approve and merge           │
│                                                                         │
└────────────────────────────────────────────────────────────────────────┘

Detailed Requirements

R1: Azure DevOps Pipeline - NuGet Publishing

R1.1 Pipeline Definition

Requirement Details
ID R1.1
Name Create release publishing pipeline
Priority P0 (Critical)
Description Create a new AzDO pipeline release-publish-nuget.yml in eng/pipelines/

1ES Pipeline Template Compliance:

The pipeline MUST extend the 1ES Pipeline Templates to be compliant with Microsoft org requirements. This is the same pattern used by the main build pipeline (eng/pipelines/azure-pipelines.yml).

resources:
  repositories:
    - repository: 1ESPipelineTemplates
      type: git
      name: 1ESPipelineTemplates/1ESPipelineTemplates
      ref: refs/tags/release

extends:
  template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
  parameters:
    featureFlags:
      autoEnablePREfastWithNewRuleset: false
      autoEnableRoslynWithNewRuleset: false
    sdl:
      sourceAnalysisPool:
        name: NetCore1ESPool-Internal
        image: windows.vs2022preview.amd64
        os: windows
    stages:
      # Pipeline stages defined here

This template provides:

  • SDL (Security Development Lifecycle) compliance scanning
  • Proper pool configuration for internal pipelines
  • Component governance integration
  • Required security tooling

Pipeline Parameters:

parameters:
  - name: AzdoBuildId
    displayName: 'Azure DevOps Build ID'
    type: string
    # Required - the build containing PackageArtifacts to publish
  
  - name: ReleaseVersion
    displayName: 'Release Version (e.g., 13.2.0)'
    type: string
    # Required - used for logging and validation
  
  - name: GaChannelName
    displayName: 'GA Channel Name'
    type: string
    default: 'Aspire 9.x GA'
    # Optional - defaults to current GA channel
  
  - name: DryRun
    displayName: 'Dry Run (skip actual publish)'
    type: boolean
    default: false
  
  # === IDEMPOTENCY FLAGS ===
  # These flags allow re-running the pipeline after partial failures
  # by skipping already-completed steps
  
  - name: SkipNuGetPublish
    displayName: 'Skip NuGet Publishing (already completed)'
    type: boolean
    default: false
    # Set to true if packages were already published and only channel promotion failed
  
  - name: SkipChannelPromotion
    displayName: 'Skip Channel Promotion (already completed)'
    type: boolean
    default: false
    # Set to true if channel promotion was already done

Automatic BAR Build ID Extraction:

The pipeline will automatically extract the BAR Build ID from the AzDO build tags. Each build has a tag in the format BAR ID - 293764 added during the build process. The pipeline will:

  1. Query the specified AzDO build for its tags
  2. Parse the tag matching pattern BAR ID - (\d+)
  3. Extract the numeric BAR Build ID
  4. Use this for darc channel promotion

This eliminates the need for manual BAR Build ID lookup.

# Example: Extract BAR Build ID from build tags
$buildTags = $(Build.Tags)  # or via REST API
$barIdTag = $buildTags | Where-Object { $_ -match 'BAR ID - (\d+)' }
if ($barIdTag -match 'BAR ID - (\d+)') {
    $barBuildId = $Matches[1]
    Write-Host "Extracted BAR Build ID: $barBuildId"
}

Variable Groups Required:

Variable Group Variables Purpose
Aspire-Release-Secrets (new) NuGetApiKey Long-lived NuGet.org API key
Publish-Build-Assets (existing) MaestroAccessToken For darc operations

R1.2 Package Download and Validation

Requirement Details
ID R1.2
Name Download and validate packages
Priority P0 (Critical)

Steps:

  1. Use DownloadPipelineArtifact@2 task to download PackageArtifacts from specified build
  2. List all .nupkg files and log count
  3. Validate that expected packages are present (configurable list or pattern)
  4. Verify package signatures using dotnet nuget verify

R1.3 NuGet Publishing

Requirement Details
ID R1.3
Name Push packages to NuGet.org
Priority P0 (Critical)

Implementation Notes:

  • Use dotnet nuget push with --skip-duplicate to handle retries gracefully
  • Implement retry logic (3 attempts with exponential backoff)
  • Log each package push result
  • Continue on individual package failure but report overall status
  • Support dry-run mode that logs what would be published

Example Script Logic:

$packages = Get-ChildItem -Path $artifactsPath -Filter "*.nupkg" -Recurse
foreach ($package in $packages) {
    $retryCount = 0
    $maxRetries = 3
    do {
        $result = dotnet nuget push $package.FullName `
            --api-key $env:NUGET_API_KEY `
            --source https://api.nuget.org/v3/index.json `
            --skip-duplicate
        if ($LASTEXITCODE -eq 0) { break }
        $retryCount++
        Start-Sleep -Seconds ([Math]::Pow(2, $retryCount))
    } while ($retryCount -lt $maxRetries)
}

R1.4 Channel Promotion via darc

Requirement Details
ID R1.4
Name Promote build to GA channel
Priority P0 (Critical)

Required Permissions and Infrastructure:

Based on the existing eng/common/core-templates/post-build/post-build.yml template, channel promotion requires:

  1. Azure Service Connection: Darc: Maestro Production

    • This provides authentication to the Maestro/BAR API
    • Uses AzureCLI@2 task with this subscription
  2. Pool: NetCore1ESPool-Publishing-Internal (for dnceng projects)

    • Image: windows.vs2019.amd64
  3. Variable Groups:

    • Publish-Build-Assets (provides MaestroAccessToken if needed)
  4. darc Installation: Via eng/common/darc-init.ps1

Steps:

  1. Use AzureCLI@2 task with azureSubscription: "Darc: Maestro Production"
  2. Install darc using eng/common/darc-init.ps1
  3. Execute promotion command:
    $darc = Get-Darc
    & $darc add-build-to-channel `
      --id $BarBuildId `
      --channel '$GaChannelName' `
      --ci
  4. Verify promotion succeeded

Idempotency:

  • Running add-build-to-channel for a build already in the channel is a no-op
  • The command will succeed without error if build is already promoted

Reference Implementation: See eng/common/post-build/publish-using-darc.ps1


R2: GitHub Actions Workflow - GitHub Tasks

R2.1 Workflow Definition

Requirement Details
ID R2.1
Name Create GitHub release workflow
Priority P0 (Critical)
Description Create .github/workflows/release-github-tasks.yml

Workflow Inputs:

on:
  workflow_dispatch:
    inputs:
      release_version:
        description: 'Release version (e.g., 13.2.0)'
        required: true
        type: string
      commit_sha:
        description: 'Commit SHA to tag'
        required: true
        type: string
      release_branch:
        description: 'Release branch (e.g., release/13.2)'
        required: true
        type: string
      is_prerelease:
        description: 'Mark as pre-release'
        required: false
        type: boolean
        default: false
      
      # === IDEMPOTENCY FLAGS ===
      # These flags allow re-running the workflow after partial failures
      # by skipping already-completed steps
      
      skip_tag_and_release:
        description: 'Skip tag and release creation (already completed)'
        required: false
        type: boolean
        default: false
      skip_merge_pr:
        description: 'Skip merge PR creation (already completed)'
        required: false
        type: boolean
        default: false
      skip_baseline_pr:
        description: 'Skip baseline version PR creation (already completed)'
        required: false
        type: boolean
        default: false

Required Permissions:

permissions:
  contents: write
  pull-requests: write

R2.2 Tag and Release Creation

Requirement Details
ID R2.2
Name Create Git tag and GitHub Release
Priority P0 (Critical)

Implementation:

  1. Check if tag already exists - if so, skip tag creation (idempotent)
  2. Create annotated tag v{version} at specified commit
  3. Push tag to origin
  4. Check if release already exists - if so, skip release creation (idempotent)
  5. Use gh CLI (pre-installed on GitHub runners) to create release with auto-generated notes
  6. Mark as pre-release if specified

Idempotency Handling:

  • Tag already exists → Log warning, skip tag creation, continue to release
  • Release already exists → Log warning, skip release creation, job succeeds
  • This allows safe re-runs without manual cleanup

Example:

# Check if tag exists
if git ls-remote --tags origin | grep -q "refs/tags/v$VERSION"; then
  echo "Tag v$VERSION already exists, skipping tag creation"
else
  git tag -a "v$VERSION" "$COMMIT_SHA" -m "Release $VERSION"
  git push origin "v$VERSION"
fi

# Check if release exists
if gh release view "v$VERSION" &>/dev/null; then
  echo "Release v$VERSION already exists, skipping release creation"
else
  gh release create "v$VERSION" \
    --title "$VERSION" \
    --generate-notes \
    --target "$COMMIT_SHA" \
    $([[ "$IS_PRERELEASE" == "true" ]] && echo "--prerelease")
fi

R2.3 Merge PR Creation

Requirement Details
ID R2.3
Name Create merge PR from release branch to main
Priority P0 (Critical)

Implementation:

  1. Check if a merge PR already exists for this branch → main (idempotent)
  2. Use the approved dotnet/actions-create-pull-request action (already vetted and used in repo)
  3. Set appropriate title: Merge {release_branch} to main after {version} release
  4. Add body with context about release
  5. Add labels: area-infrastructure
  6. Do NOT auto-merge (requires human review for release-specific changes)

Approved Action Reference:

- uses: dotnet/actions-create-pull-request@e8d799aa1f8b17f324f9513832811b0a62f1e0b1
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
    branch: ${{ inputs.release_branch }}
    base: main
    # ... other parameters

Idempotency Handling:

  • If PR already exists → Log the existing PR number, skip creation, job succeeds
  • The dotnet/actions-create-pull-request action handles this gracefully

PR Body Template:

## Merge Release Branch to Main

This PR merges the `{release_branch}` branch back to `main` after the `{version}` release.

### ⚠️ Manual Review Required

Some changes in the release branch may be release-specific and should NOT be merged to main:
- Version pinning changes
- Release-specific configuration

Please review carefully and adjust as needed before merging.

### Checklist
- [ ] Reviewed diff for release-specific changes
- [ ] Resolved any merge conflicts
- [ ] CI passing

R2.4 Baseline Version Update PR

Requirement Details
ID R2.4
Name Create PR to update PackageValidationBaselineVersion
Priority P1 (High)

Implementation:

  1. Check if branch update-baseline-version-{version} already exists (idempotent)
  2. Check if PR already exists for this update (idempotent)
  3. Create new branch update-baseline-version-{version}
  4. Update src/Directory.Build.props:
    • Change PackageValidationBaselineVersion from current to new version
  5. Commit with message: Update PackageValidationBaselineVersion to {version}
  6. Use the approved dotnet/actions-create-pull-request action to create PR to main

Approved Action Reference:

- uses: dotnet/actions-create-pull-request@e8d799aa1f8b17f324f9513832811b0a62f1e0b1
  with:
    token: ${{ secrets.GITHUB_TOKEN }}
    branch: update-baseline-version-${{ inputs.release_version }}
    base: main
    commit-message: "Update PackageValidationBaselineVersion to ${{ inputs.release_version }}"
    title: "Update PackageValidationBaselineVersion to ${{ inputs.release_version }}"
    # ... other parameters

Idempotency Handling:

  • If branch exists with same changes → Action updates existing branch/PR
  • If PR already exists → Log the existing PR number, skip creation

File to Modify: src/Directory.Build.props

<PackageValidationBaselineVersion>13.2.0</PackageValidationBaselineVersion>

R3: Error Handling, Idempotency, and Recovery

R3.1 Idempotency Design Principles

Both the AzDO pipeline and GitHub workflow are designed to be idempotent - they can be safely re-run after partial failures without duplicating work or causing errors.

Two-Level Idempotency:

  1. Automatic Idempotency: Steps that automatically detect and skip already-completed work
  2. Manual Skip Flags: Boolean parameters to explicitly skip steps that are known to be complete

R3.2 AzDO Pipeline Error Handling

Scenario Automatic Handling Manual Recovery
Build artifact not found Fail with clear error message Fix build ID and re-run
Package signature validation fails Fail pipeline, log affected packages Investigate and re-run
NuGet push fails (network) Retry 3x with exponential backoff Re-run pipeline
Package already on NuGet --skip-duplicate handles gracefully No action needed
NuGet push partially succeeds Continue with remaining, report failures Re-run (duplicates skipped)
darc promotion fails Fail pipeline with error details Re-run with SkipNuGetPublish=true
Build already in channel darc handles gracefully (no-op) No action needed

R3.3 GitHub Actions Error Handling

Scenario Automatic Handling Manual Recovery
Tag already exists Skip tag creation, log warning, continue No action needed
Release already exists Skip release creation, log warning No action needed
PR creation fails Fail job with API error details Re-run with skip_tag_and_release=true
Merge PR already exists dotnet/actions-create-pull-request handles No action needed
Baseline branch exists Action updates existing No action needed
Baseline PR exists Log existing PR, continue No action needed

R3.4 Recovery Scenarios

Scenario A: AzDO pipeline fails during channel promotion

Re-run pipeline with:
  SkipNuGetPublish: true
  SkipChannelPromotion: false

Scenario B: GitHub workflow fails during merge PR creation

Re-run workflow with:
  skip_tag_and_release: true
  skip_merge_pr: false
  skip_baseline_pr: false

Scenario C: Need to re-run entire workflow (safe)

Re-run with all defaults - idempotent steps will skip automatically

R4: Release Process Documentation

R4.1 Documentation Deliverable

Requirement Details
ID R4.1
Name Create public release process documentation
Priority P1 (High)
Location docs/release-process.md

Purpose:

  • Provide a single source of truth for the release process
  • Enable any maintainer to execute a release
  • Increase transparency for the community
  • Reduce bus factor for release operations

Documentation Structure:

# Aspire Release Process

## Overview
- What gets released (NuGet packages, GitHub release, etc.)
- Release cadence and versioning scheme

## Prerequisites
- Required permissions (AzDO, GitHub)
- Access to variable groups (who to contact)

## Release Checklist
- [ ] Pre-release verification steps
- [ ] AzDO pipeline execution
- [ ] GitHub workflow execution  
- [ ] Post-release verification
- [ ] Manual follow-up tasks (aka.ms links, announcements)

## Step-by-Step Guide

### Phase 1: Publish to NuGet (AzDO Pipeline)
1. Identify the build to release
2. Navigate to the release pipeline
3. Queue with required parameters
4. Monitor and verify completion

### Phase 2: GitHub Tasks (GitHub Workflow)
1. Trigger the workflow
2. Provide required inputs
3. Verify tag, release, and PRs created

### Phase 3: Post-Release
1. Review and merge the merge PR
2. Review and merge the baseline version PR
3. Update aka.ms links (separate process)
4. Announcements (if applicable)

## Troubleshooting
- Common issues and solutions
- How to re-run after failures
- Who to contact for help

## Appendix
- Link to this PRD
- Link to pipeline/workflow definitions

R4.2 Documentation Maintenance

Aspect Approach
Updates Documentation updated alongside pipeline/workflow changes
Review Part of PR review for release automation changes
Versioning Lives in main branch, applies to all release branches

Security Considerations

S0: Approved Dependencies and Actions

All automation must use only pre-approved actions and dependencies that have been vetted by the security team. This avoids introducing new dependencies that require additional security review.

Approved GitHub Actions

Action Version/SHA Usage
actions/checkout @11bd71901bbe5b1630ceea73d27597364c9af683 (v4.2.2) Repository checkout
dotnet/actions-create-pull-request @e8d799aa1f8b17f324f9513832811b0a62f1e0b1 PR creation
actions/github-script @60a0d83039c74a4aee543508d2ffcb1c3799cdea (v7.0.1) GitHub API calls
actions/setup-dotnet @v4 .NET SDK setup

Note: The gh CLI is pre-installed on all GitHub-hosted runners and does not require a separate action.

Approved AzDO Tasks

Task Version Usage
DownloadPipelineArtifact@2 Built-in Download build artifacts
PowerShell@2 Built-in Script execution
AzureCLI@2 Built-in Azure/Maestro authentication
NuGetAuthenticate@1 Built-in NuGet feed auth
UseDotNet@2 Built-in .NET SDK setup

Existing Infrastructure

The pipeline leverages existing Arcade infrastructure:

  • eng/common/darc-init.ps1 - darc installation
  • eng/common/tools.ps1 - Common tooling (Get-Darc function)
  • eng/common/post-build/publish-using-darc.ps1 - Reference implementation
  • eng/common/core-templates/post-build/setup-maestro-vars.yml - Maestro variable setup

S1: NuGet API Key Management

Consideration Implementation
Key Storage Azure DevOps secure variable group (encrypted at rest)
Key Scope Scoped to dotnet-aspire namespace only
Key Rotation Annual rotation, documented procedure
Key Expiration 1 year validity, calendar reminder for renewal
Access Control Variable group restricted to release pipeline and authorized users

S2: GitHub Token Usage

Token Scope Notes
GITHUB_TOKEN Automatic Used for tag, release, PR operations
Permissions Minimal required contents: write, pull-requests: write
No PAT Required Using built-in token avoids long-lived credential storage

S3: Audit Trail

  • All pipeline runs are logged in AzDO with full parameter visibility
  • All GitHub Actions runs are logged with inputs
  • Both systems provide who triggered the workflow

S4: Security Sensitivity Review - What Can Be Public

Since the pipeline definitions, workflow files, and documentation will be checked into the public repository, we must ensure no security-sensitive information is exposed.

✅ Safe to Document Publicly

Item Reason
Variable group names (e.g., Aspire-Release-Secrets) Names don't expose values; access is controlled by AzDO permissions
Service connection names (e.g., Darc: Maestro Production) Names don't expose credentials; connections are managed by AzDO
Pool names (e.g., NetCore1ESPool-Publishing-Internal) Infrastructure names are not sensitive
Channel names (e.g., Aspire 9.x GA) Public information about release channels
NuGet.org source URL Public endpoint
Build ID formats and tag patterns Operational information, not credentials
Workflow/pipeline parameter names Configuration, not secrets
GitHub Actions used (with SHAs) Public actions, pinned for security
AzDO task names and versions Built-in Microsoft tasks
File paths in the repository Public repository structure
Process steps and procedures Transparency helps community understanding

🔒 Kept Secret (Not in Code/Docs)

Item Where Stored Access Control
NuGet API Key AzDO Variable Group (encrypted) Pipeline + authorized users only
Maestro/BAR credentials Azure Service Connection Managed by AzDO, accessed via AzureCLI@2
GITHUB_TOKEN GitHub-provided at runtime Automatic, scoped to workflow run

Security Verification Checklist

  • No API keys, tokens, or passwords in pipeline/workflow YAML
  • No connection strings or endpoints that aren't public
  • No internal URLs that shouldn't be exposed
  • Variable group names reference only (values are secret)
  • Service connection names reference only (credentials managed by AzDO)
  • Documentation describes process, not credentials
  • All GitHub Actions pinned to SHA (prevents supply chain attacks)

Why This Is Safe

  1. Execution requires permissions: Even with full knowledge of the process, only authorized users can:

    • Trigger the AzDO pipeline (requires AzDO project permissions)
    • Trigger the GitHub workflow (requires repo write access)
    • Access the variable groups (requires explicit AzDO grant)
    • Use the service connections (requires explicit AzDO grant)
  2. Secrets are never in code: All sensitive values are stored in:

    • AzDO secure variable groups (encrypted at rest)
    • Azure service connections (managed credentials)
    • GitHub's runtime token injection
  3. Transparency benefits outweigh risks:

    • Community can understand and contribute to the process
    • Other .NET repos can learn from/adopt similar patterns
    • Reduces bus factor by making process discoverable

S5: Threat Model

This section provides a holistic threat model for the release automation system, identifying potential threats and their mitigations.

Threat Model Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                         RELEASE AUTOMATION ATTACK SURFACE                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │                     AZURE DEVOPS PIPELINE                              │ │
│  │                                                                        │ │
│  │  Access Model: PRIVATE (Internal AzDO project)                        │ │
│  │  ├─ Trigger: Only authenticated users with pipeline permissions       │ │
│  │  ├─ Logs: Visible only to project members                            │ │
│  │  └─ Secrets: Encrypted variable groups, service connections          │ │
│  │                                                                        │ │
│  │  Assets Protected:                                                    │ │
│  │  ├─ NuGet API Key (publishes to nuget.org)                           │ │
│  │  ├─ Maestro/BAR credentials (darc channel promotion)                  │ │
│  │  └─ Signed package artifacts                                          │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                    │                                         │
│                                    ▼                                         │
│  ┌────────────────────────────────────────────────────────────────────────┐ │
│  │                     GITHUB ACTIONS WORKFLOW                            │ │
│  │                                                                        │ │
│  │  Access Model: PUBLIC repo, RESTRICTED trigger                        │ │
│  │  ├─ Trigger: workflow_dispatch requires write access                  │ │
│  │  ├─ Logs: PUBLIC (anyone can view workflow run logs)                 │ │
│  │  └─ Secrets: GITHUB_TOKEN only (no custom secrets)                   │ │
│  │                                                                        │ │
│  │  Assets Protected:                                                    │ │
│  │  ├─ Git tags (version history integrity)                             │ │
│  │  ├─ GitHub Releases (official release artifacts)                      │ │
│  │  └─ Pull requests (code changes to main branch)                       │ │
│  └────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

T1: Azure DevOps Pipeline Threats

ID Threat Likelihood Impact Mitigation
T1.1 Malicious insider publishes tampered packages Low Critical • Only signed packages from official build can be published
• Pipeline downloads from specific build ID, not arbitrary source
• Audit trail of who triggered pipeline and with what parameters
Package signatures verified via dotnet nuget verify before push
T1.2 Compromised NuGet API key Low Critical • Key stored in encrypted AzDO variable group
• Key scoped to dotnet-aspire namespace only (cannot publish other packages)
• Annual key rotation
• Key access limited to pipeline and specific users
--skip-duplicate prevents republishing existing versions
T1.3 Supply chain attack on AzDO tasks Very Low High • Only built-in Microsoft AzDO tasks used
• 1ES Pipeline Templates provide SDL compliance
• No third-party marketplace tasks
T1.4 Unauthorized pipeline trigger Very Low High • AzDO project is internal (requires Microsoft auth)
• Pipeline trigger requires explicit permission grant
• All runs logged with triggering user identity
T1.5 Build artifact tampering Very Low Critical • Artifacts downloaded from AzDO using authenticated API
Package signatures verified before push (fails if tampered)
• Build ID explicitly specified (no "latest" ambiguity)
T1.6 Promotion to wrong channel Low Medium • Channel name is a parameter with sensible default
• darc promotion is idempotent (re-running is safe)
• Channel list is public, mistakes are visible and reversible
T1.7 Secrets leaked in logs Low Critical • AzDO automatically masks variable group secrets in logs
• No Write-Host of sensitive values
• Logs only visible to project members

T2: GitHub Actions Workflow Threats

ID Threat Likelihood Impact Mitigation
T2.1 Unauthorized workflow trigger Very Low Medium workflow_dispatch requires write permission to repo
Additional check: workflow verifies actor has admin or maintain permission
• Only org members/collaborators have write access
• Trigger logged with user identity in workflow run
T2.2 Tag pointing to malicious commit Low High • Commit SHA is explicit input (not "latest")
• Commit must exist in repo (can't reference external code)
• Tag creation is visible in repo history
• GitHub Release points to specific SHA
T2.3 Secrets leaked in public logs Medium Low No custom secrets used - only GITHUB_TOKEN
GITHUB_TOKEN is automatically masked
• Workflow inputs (version, SHA, branch) are not sensitive
• No API keys or credentials in GitHub workflow
T2.4 Malicious PR modifies workflow then triggers it Very Low Medium workflow_dispatch runs from default branch only
• PR changes to workflow don't affect dispatch runs until merged
• Workflow file changes require PR review and approval
T2.5 GITHUB_TOKEN abuse Low Medium • Token scoped to minimal permissions (contents: write, pull-requests: write)
• Token expires when workflow completes
• Cannot push to protected branches without approval
• Cannot access other repositories
T2.6 Creating release for wrong version Low Low • Version format validated (SemVer regex)
• Release creation is idempotent (can't duplicate)
• Releases are public and visible for review
• Can delete and recreate if needed
T2.7 PR to main with malicious code Low Medium • PRs require review before merge (not auto-merged)
• Branch protection rules enforced
• CI must pass before merge
• Human approval required
T2.8 Information disclosure via logs Medium Low • Only non-sensitive info logged (version, branch, SHA)
• No internal URLs, tokens, or keys exposed
• Process documentation is intentionally public

T3: Cross-System Threats

ID Threat Likelihood Impact Mitigation
T3.1 Mismatch between AzDO and GitHub operations Medium Low • Both systems use same version parameter
• Commit SHA links the two workflows
• Idempotent design allows re-running to fix mismatches
T3.2 Race condition in parallel execution Low Low • GitHub workflow has concurrency group (only one runs at a time)
• AzDO pipeline should be manually sequenced
• Operations are idempotent
T3.3 Social engineering to trigger release Low High • Requires AzDO access (Microsoft auth) for NuGet publishing
• Requires GitHub write access for tagging
• Two separate systems = two separate compromise needed

T4: Visibility Analysis - What Can Attackers See?

Public Information (visible to anyone):

  • Workflow YAML file contents (process steps, action versions)
  • Workflow run logs (inputs, step outputs, timing)
  • Created tags and releases
  • Created PRs and their contents
  • Documentation of the release process

Private Information (requires authentication):

  • AzDO pipeline definition (internal project)
  • AzDO pipeline logs and parameters
  • NuGet API key value
  • Maestro/BAR credentials
  • Who triggered AzDO pipeline

Security Implication: An attacker with knowledge of the process but without credentials cannot:

  • Trigger either workflow (requires auth)
  • Access the NuGet API key
  • Publish packages to NuGet.org
  • Promote builds in Maestro/BAR

T5: Specific Mitigation Details

GitHub Actions Log Visibility

Since GitHub Actions logs are public, the workflow is designed to avoid logging sensitive information:

# ✅ SAFE to log (non-sensitive):
echo "Release Version: ${{ inputs.release_version }}"
echo "Commit SHA: ${{ inputs.commit_sha }}"
echo "Release Branch: ${{ inputs.release_branch }}"
echo "Tag created: v$VERSION"
echo "PR created: #123"

# ❌ NEVER logged (but doesn't exist in GH workflow anyway):
# - API keys
# - Tokens (GITHUB_TOKEN is auto-masked)
# - Internal URLs
# - Credentials
workflow_dispatch Security Model
┌─────────────────────────────────────────────────────────────────┐
│               workflow_dispatch TRIGGER SECURITY                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Who can trigger (GitHub level)?                                │
│  ├─ ✅ Org members with write access                           │
│  ├─ ✅ Outside collaborators with write access                 │
│  ├─ ❌ Read-only collaborators                                 │
│  ├─ ❌ Public users (no access)                                │
│  └─ ❌ Forks (cannot trigger on upstream)                      │
│                                                                 │
│  Additional authorization check (implemented in workflow):      │
│  └─ First job checks github.actor has 'admin' or 'maintain'    │
│     permission via GitHub API - fails fast if not authorized   │
│                                                                 │
│  What workflow code runs?                                       │
│  └─ Workflow YAML always read from DEFAULT BRANCH (main)       │
│      ├─ PR changes to workflow don't affect dispatch           │
│      └─ Must be merged to main before taking effect            │
│      NOTE: You CAN specify a different ref to run against,     │
│            but the workflow DEFINITION is always from main     │
│                                                                 │
│  Fork behavior:                                                 │
│  ├─ Cannot trigger upstream repo's workflow from a fork        │
│  ├─ Fork has no access to upstream's GITHUB_TOKEN              │
│  └─ Fork's workflow only affects the fork itself               │
│                                                                 │
│  What's logged publicly?                                        │
│  ├─ Workflow inputs (version, SHA, branch)                     │
│  ├─ Step outputs and timing                                    │
│  ├─ Who triggered (GitHub username)                            │
│  ├─ Authorization check result                                 │
│  └─ Success/failure status                                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
NuGet Publishing Security Layers
┌─────────────────────────────────────────────────────────────────┐
│                  NUGET PUBLISHING DEFENSE IN DEPTH              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Layer 1: Access Control                                        │
│  └─ Only authorized users can trigger AzDO pipeline            │
│                                                                 │
│  Layer 2: Source Verification                                   │
│  └─ Packages come from specific build ID (not "latest")        │
│                                                                 │
│  Layer 3: Package Integrity                                     │
│  └─ `dotnet nuget verify` validates signatures before push     │
│     (pipeline fails if any package fails verification)         │
│                                                                 │
│  Layer 4: Key Scoping                                           │
│  └─ API key can only publish to dotnet-aspire namespace        │
│                                                                 │
│  Layer 5: Idempotency                                           │
│  └─ --skip-duplicate prevents version republishing             │
│                                                                 │
│  Layer 6: Audit Trail                                           │
│  └─ All publishes logged in AzDO and NuGet.org                 │
│                                                                 │
│  Layer 7: Reversibility                                         │
│  └─ Packages can be unlisted (not deleted) if compromised      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
Git Tag Integrity: Signed Tags vs. Tag Protection Rules

Background: Git supports cryptographically signed tags using GPG or SSH keys. Signed tags display a "Verified" badge on GitHub and provide cryptographic proof of who created the tag. This is a recognized security best practice for release integrity.

Our Decision: We opted to use GitHub Tag Protection Rules instead of signed tags.

Rationale:

Consideration Signed Tags Tag Protection Rules
Complexity Requires GPG/SSH key management, key rotation, secure key storage as GitHub secrets Configuration in repository settings only
Automation Workflow needs access to signing key, adds secret management burden No additional secrets required
Protection Proves who created tag Prevents unauthorized tag creation, deletion, or modification
Scope Per-tag verification Pattern-based rules (e.g., v*)
Recovery If key is compromised, past signatures may be questioned Protection is administrative, no cryptographic key to compromise

Implemented Mitigation:

GitHub Tag Protection Rules are configured for the v* pattern with the following restrictions:

  • Only users with admin or maintain permission can create matching tags
  • Tags cannot be deleted once created
  • Tags cannot be force-pushed (modified to point to a different commit)

Configuration Location: Repository Settings → Tags → Tag protection rules

Rule: v*
Restrictions:
  ├─ Only admins/maintainers can create
  ├─ Prevent tag deletion
  └─ Prevent force-push to tags

Threat Coverage:

Threat Signed Tags Tag Protection Rules
Unauthorized tag creation ✅ Unsigned tags visible ✅ Blocked at creation
Tag tampering (point to different commit) ✅ Signature would be invalid ✅ Force-push blocked
Tag deletion ❌ Still possible ✅ Blocked
Retroactive verification ✅ Can verify signature ❌ No cryptographic proof

Acceptable Trade-off: We accept that tag protection rules do not provide cryptographic proof of authorship (which signed tags would provide). However, combined with GitHub's audit log of who created each tag and the workflow authorization check requiring admin/maintain permission, we have sufficient accountability for our threat model. The operational simplicity of not managing signing keys outweighs the additional assurance signed tags would provide.

T6: Risk Summary Matrix

Risk Area Residual Risk Justification
Unauthorized package publishing Low Multiple auth layers, signed packages, scoped keys
Credential exposure Low No secrets in GH workflow, AzDO logs are private
Information disclosure Very Low Only non-sensitive process info is public
Tag/release tampering Low Requires write access, visible audit trail
Supply chain attack Very Low Pinned SHAs, built-in tasks only
Insider threat Low Audit trails, limited access, reversible actions

T7: Incident Response

If a security incident is suspected:

  1. Immediate Actions:

    • Revoke NuGet API key (generate new one)
    • Review AzDO pipeline audit logs
    • Review GitHub workflow run history
    • Check NuGet.org for unexpected publishes
  2. For Compromised Packages:

    • Unlist affected package versions on NuGet.org
    • Publish advisory/announcement
    • Release patched versions with incremented version numbers
  3. For Compromised Tags/Releases:

    • Delete malicious GitHub release
    • Delete malicious tag: git push --delete origin v<version>
    • Recreate with correct commit
  4. For Compromised PRs:

    • Close malicious PR without merging
    • Review branch protection settings
    • Audit recent merges to main

Implementation Plan

Phase 1: Foundation (Week 1)

Task Owner Est. Hours
Create AzDO variable group Aspire-Release-Secrets Release Manager 1
Generate and store long-lived NuGet API key Release Manager 1
Create release-publish-nuget.yml pipeline skeleton Dev 4
Implement package download and listing Dev 2

Phase 2: AzDO Pipeline (Week 2)

Task Owner Est. Hours
Implement NuGet push with retry logic Dev 4
Implement darc channel promotion Dev 3
Add dry-run mode Dev 2
Testing with test packages/channel Dev 4

Phase 3: GitHub Actions (Week 3)

Task Owner Est. Hours
Create release-github-tasks.yml workflow Dev 4
Implement tag and release creation Dev 3
Implement merge PR creation Dev 3
Implement baseline version PR Dev 3

Phase 4: Documentation and Testing (Week 4)

Task Owner Est. Hours
Create docs/release-process.md documentation Dev 4
End-to-end testing with real release Dev + RM 8
Security review of public artifacts Dev + Security 2
Knowledge transfer to additional maintainers RM 4

Testing Strategy

T1: AzDO Pipeline Testing

  1. Dry Run Testing: Use dry-run mode to validate all steps without publishing
  2. Test Package Testing: Create test packages with -test suffix to validate push logic
  3. Channel Testing: Test with a non-production channel first

T2: GitHub Actions Testing

  1. Fork Testing: Test workflow in a fork before merging
  2. Draft Release: Test release creation in draft mode first
  3. Branch Protection: Ensure PR creation respects branch protection rules

T3: Integration Testing

  1. Full Release Simulation: Execute complete process with test artifacts
  2. Failure Recovery: Test error scenarios and recovery procedures

Rollback Plan

If NuGet Packages are Published Incorrectly

  1. Unlist packages via NuGet.org UI (cannot delete)
  2. Ship corrected packages with incremented patch version
  3. Update release notes to reflect the issue

If Incorrect Tag/Release Created

  1. Delete the release via GitHub UI or API
  2. Delete the tag: git push --delete origin v{version}
  3. Re-run workflow with correct parameters

If Incorrect PR Created

  1. Close the PR without merging
  2. Delete the branch if applicable
  3. Re-run workflow or create manually

Success Metrics

Metric Target Measurement
Release time < 30 minutes From pipeline start to release completion
Error rate < 5% Releases requiring manual intervention
Adoption 100% All releases using automation within 2 releases
Documentation coverage 100% All steps documented in runbook

Open Questions

  1. Q: Should we support preview/RC releases differently?

    • Proposed: Use is_prerelease flag for GitHub releases; same pipeline for NuGet
    • Status: Open
  2. Q: Should the baseline version PR target main or the next release branch?

    • Proposed: Target main since baseline validation is for breaking changes detection
    • Status: Open
  3. Q: Do we need approval gates in the AzDO pipeline?

    • Proposed: No automated approval gates, but consider adding manual approval stage
    • Status: Open
  4. Q: Should we automatically assign reviewers to the merge PR?

    • Proposed: Assign to dotnet/aspire-maintainers team if available
    • Status: Open
  5. Q: What happens if packages are already published to NuGet.org?

    • Resolved: Use --skip-duplicate flag to handle gracefully (idempotent)
  6. Q: Should we validate the release version format?

    • Proposed: Yes, validate SemVer format (major.minor.patch with optional prerelease)
    • Status: Open
  7. Q: Which GA channel name should be used?

    • Resolved: Default to Aspire 9.x GA but make it a configurable parameter
  8. Q: How do we get the BAR Build ID?

    • Resolved: Automatically extract from AzDO build tags (format: BAR ID - NNNNNN)
  9. Q: What approved actions can we use for PR creation?

    • Resolved: Use dotnet/actions-create-pull-request@e8d799aa1f8b17f324f9513832811b0a62f1e0b1 (already vetted)
  10. Q: What permissions are needed for darc channel promotion?

    • Resolved: Requires AzureCLI@2 with azureSubscription: "Darc: Maestro Production" service connection

Appendix

A1: File Paths Reference

Purpose Path
Release Process Documentation (new) docs/release-process.md
AzDO Pipeline (new) eng/pipelines/release-publish-nuget.yml
GitHub Workflow (new) .github/workflows/release-github-tasks.yml
Baseline Version src/Directory.Build.props
darc init script eng/common/darc-init.ps1
Existing main pipeline eng/pipelines/azure-pipelines.yml
Common variables eng/pipelines/common-variables.yml
This PRD docs/specs/release-automation-prd.md

A2: Existing Variable Groups

Group Contains Usage
Publish-Build-Assets MaestroAccessToken darc operations
DotNet-HelixApi-Access HelixApiAccessToken Test infrastructure
SDL_Settings Security settings Build security

A3: Sample Pipeline Invocation

AzDO Pipeline - Normal Run:

Pipeline: release-publish-nuget
Parameters:
  AzdoBuildId: 20260109.1
  ReleaseVersion: 13.2.0
  GaChannelName: Aspire 9.x GA  # Optional, this is the default
  DryRun: false
  SkipNuGetPublish: false
  SkipChannelPromotion: false

AzDO Pipeline - Re-run after NuGet success but channel promotion failure:

Pipeline: release-publish-nuget
Parameters:
  AzdoBuildId: 20260109.1
  ReleaseVersion: 13.2.0
  SkipNuGetPublish: true        # Skip - already completed
  SkipChannelPromotion: false   # Retry this step

GitHub Actions - Normal Run:

Workflow: release-github-tasks
Inputs:
  release_version: 13.2.0
  commit_sha: abc123def456789
  release_branch: release/13.2
  is_prerelease: false
  skip_tag_and_release: false
  skip_merge_pr: false
  skip_baseline_pr: false

GitHub Actions - Re-run after tag/release success but PR creation failure:

Workflow: release-github-tasks
Inputs:
  release_version: 13.2.0
  commit_sha: abc123def456789
  release_branch: release/13.2
  skip_tag_and_release: true   # Skip - already completed
  skip_merge_pr: false         # Retry this step
  skip_baseline_pr: false      # Retry this step

A4: References


Approval

Role Name Date Status
Release Manager Pending
Engineering Lead Pending
Security Review Pending

This document is a living specification and will be updated as requirements evolve.

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