Sunday, March 24, 2024

Azure DevOps: Requiring Pull Requests to be Associated with a Work Item

Whether following Git Flow, GitHub Flow, GitLab Flow or Trunk-based Development certain policies are standard to source code best practices. For example. each Pull Request (PR) must be associated with a single task/story/epic (a linked work item). This post discusses Azure DevOps support for this feature.

For a given ADO Git repo, branch policies (such a requiring a PR to be linked to a work item) are set per-branch. There is no way to assign such policies to multiple branches. In order to set a branch's policies, navigate to a Repo's branches tab:


For a branch whose policy is to be set, click on the three dots to show the context menu shown below: 


From the context menu, select Branch policies. From the Branch Policies tab click on Check for linked work items:


Under Check for linked work items, insure the Required radio button is selected:

Git Branch Strategies

Requiring "check for linked work items" is set per-branch. Which branches this will be set for depends on the git branch strategy adopted.

Git Branch Strategy: Git Flow

For the Git Flow branching strategy the following branches would require a linked work item:
  • Main/Master
  • Develop
  • Feature
  • Release
  • Hotfix

Git Branch Strategy: GitHub Flow

For the GitHub Flow branching strategy the following branches would require a linked work item:
  • Main/Master
  • Feature

Git Branch Strategy: GitLab Flow

For the GitLab Flow branching strategy the following branches would require a linked work item:
  • Main/Master
  • Feature
  • Pre-Production
  • Production

Git Branch Strategy: Trunk-based Development

For the Trunk-based Development branching strategy the following branches would require a linked work item:
  • Main/Master
  • Trunk
  • Feature

Friday, March 22, 2024

Azure/PowerShell: Geolocating Storage Account White Listed IP Addresses

On a project, we had provided access to to an Azure Storage account by adding permitted IP addresses to the firewall (white listed IPs). These settings can be found via https://portal.azure.com/ by navigating to the storage account and selecting Network under "Security + networking":



I was tasked with writing a script to list all the white listed IP addresses and display there geographic location. The http://ip-api.com returns (for free) the geo data associated with an IP address. This service is free for no-commercial use:


The PowerShell script to return this information takes two required parameters:

  • $resourceGroupName: resource group name associated with storage account
  • $storageAccountName: storage account name whose white listed IPs will be returned


The script in its entirety is as follows:

param(
    [Parameter(Mandatory=$true)]
    [string] $resourceGroupName,
    [Parameter(Mandatory=$true)]
    [string] $storageAccountName
)

Set-StrictMode -Version 3.0
$ErrorActionPreference = 'Stop'
Set-PSDebug -Off
#Set-PSDebug -Trace 1

# FYI: Import-Module Az.Storage -ErrorAction Stop

[int] $exitCodeSuccess = 0

[int] $exitCodeError = 1

[int] $exitCode = $exitCodeSuccess

try {
    Connect-AzAccount -ErrorAction Stop | Out-Null

    [Microsoft.Azure.Commands.Management.Storage.Models.PSNetworkRuleSet] $networkRuleSet = 
        Get-AzStorageAccountNetworkRuleSet `
            -ResourceGroupName $resourceGroupName `
            -Name $storageAccountName `
            -ErrorAction Stop
    [Microsoft.Azure.Commands.Management.Storage.Models.PSIpRule[]] $ipRules = 
        $networkRuleSet.IpRules

    $ipRules | ForEach-Object { 
        [string] $ip = $_.IPAddressOrRange
        [PSCustomObject] $response = Invoke-RestMethod `
                        -Uri "http://ip-api.com/json/$ip" `
                        -ErrorAction Stop

        Write-Output ( `
            "$ip, $($response.isp), $($response.city), " +
            "$($response.regionName), $($response.zip), " +
            "$($response.country)")
    } -ErrorAction Stop
}

catch {
  [System.Management.Automation.ErrorRecord] $errorRecord = $PSItem

  $exitCode = $exitCodeError
  Write-Host $errorRecord
  Write-Host "Exception Message: " + ` 
    $($errorRecord.Exception.Message)," +` 
    Stacktrace: $($errorRecord.Exception.StackTrace)"
}

return $exitCode

The Get-AzStorageAccountNetworkRuleSet cmdlet is described as follows (see Get-AzStorageAccountNetworkRuleSet):


IP Ranges versus Individual IP Addresses

The following $ipRules variable returns IP addresses and range of IP address:

[Microsoft.Azure.Commands.Management.Storage.Models.PSNetworkRuleSet] $networkRuleSet = 
        Get-AzStorageAccountNetworkRuleSet `
            -ResourceGroupName $resourceGroupName `
            -Name $storageAccountName `
            -ErrorAction Stop
    [Microsoft.Azure.Commands.Management.Storage.Models.PSIpRule[]] $ipRules = 
        $networkRuleSet.IpRules


In the code sample above it is assumed $ipRules contains only IP addresses otherwise the following code where the http://ip-api.com/json service is invoked would not work as the expected parameter is an IP address not an IP address range:

        [string] $ip = $_.IPAddressOrRange
        [PSCustomObject] $response = Invoke-RestMethod `
                        -Uri "http://ip-api.com/json/$ip" `
                        -ErrorAction Stop