From a92181ef63cfb86953382c93cf9662ed1823fd21 Mon Sep 17 00:00:00 2001 From: Missy Messa Date: Fri, 21 Aug 2026 13:28:33 -0700 Subject: [PATCH 1/2] Improve inter-branch merge configuration errors Separate download, JSON parsing, and schema validation failures so malformed merge-flow configuration fails with an actionable error while an unconfigured branch remains a successful no-op. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 040f9d82-5d74-492a-a03d-71f0143afb36 --- .github/workflows/inter-branch-merge-base.yml | 2 +- .../workflows/scripts/read-configuration.ps1 | 62 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/.github/workflows/inter-branch-merge-base.yml b/.github/workflows/inter-branch-merge-base.yml index 77b7e9a5d52..59c3780f50d 100644 --- a/.github/workflows/inter-branch-merge-base.yml +++ b/.github/workflows/inter-branch-merge-base.yml @@ -67,7 +67,7 @@ jobs: env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - run: Write-Host "Configuration required for running merge flow was not found or was not valid." + - run: Write-Host "No merge configuration was found for branch '$env:GITHUB_REF_NAME'." if: steps.extract-configuration-values.outputs.configurationFound != 'true' name: Read configuration status diff --git a/.github/workflows/scripts/read-configuration.ps1 b/.github/workflows/scripts/read-configuration.ps1 index 73e72d7c37b..5aee5c96db8 100644 --- a/.github/workflows/scripts/read-configuration.ps1 +++ b/.github/workflows/scripts/read-configuration.ps1 @@ -52,33 +52,43 @@ function GetConfiguration { $urlToConfigurationFile = "https://raw.githubusercontent.com/$RepoOwner/$RepoName/$ConfigurationFileBranch/$ConfigurationFilePath" Write-Host "Fetching configuration file from $urlToConfigurationFile" - try{ + try { $response = Invoke-WebRequest -UseBasicParsing -Method GET -MaximumRetryCount 3 -Headers $headers ` $urlToConfigurationFile - - $mergeFlowConfig = ConvertFrom-Json -InputObject $response.Content -AsHashTable - if ($mergeFlowConfig -eq $null) { - Write-Warning "Failed to read configuration file" - return $null + } catch { + $statusCode = if ($null -ne $_.Exception.Response) { + " HTTP status $([int]$_.Exception.Response.StatusCode)." + } else { + "" } - if (!$mergeFlowConfig.ContainsKey('merge-flow-configurations')) { - Write-Host "No merge-flow-configurations found in configuration file" - return $null - } + throw "Failed to fetch configuration file '$urlToConfigurationFile'.$statusCode $($_.Exception.Message)" + } + + try { + $mergeFlowConfig = ConvertFrom-Json -InputObject $response.Content -AsHashTable -ErrorAction Stop + } catch { + throw "Invalid JSON in configuration file '$urlToConfigurationFile'. $($_.Exception.Message)" + } - if($mergeFlowConfig['merge-flow-configurations'].ContainsKey($MergeFromBranch)){ - $config = $mergeFlowConfig['merge-flow-configurations'][$MergeFromBranch] - Write-Host "Found Configuration" - Write-Host $config - return $config - }else{ - Write-Host "There was no configuration found for $MergeFromBranch" + if ($null -eq $mergeFlowConfig -or + !$mergeFlowConfig.ContainsKey('merge-flow-configurations') -or + $mergeFlowConfig['merge-flow-configurations'] -isnot [System.Collections.IDictionary]) { + throw "Configuration file '$urlToConfigurationFile' must contain a 'merge-flow-configurations' object." + } + + if ($mergeFlowConfig['merge-flow-configurations'].ContainsKey($MergeFromBranch)) { + $config = $mergeFlowConfig['merge-flow-configurations'][$MergeFromBranch] + if ($config -isnot [System.Collections.IDictionary]) { + throw "Configuration for branch '$MergeFromBranch' in '$urlToConfigurationFile' must be an object." } - }catch{ - Write-Warning "Failed to fetch and process configuration file" + + Write-Host "Found Configuration" + Write-Host $config + return $config } + Write-Host "There was no configuration found for $MergeFromBranch" return $null } @@ -86,20 +96,20 @@ function GetConfiguration { $configuration = GetConfiguration if ($configuration -ne $null) { - if($configuration.ContainsKey('MergeToBranch')){ + if ($configuration.ContainsKey('MergeToBranch') -and + ![string]::IsNullOrWhiteSpace([string]$configuration['MergeToBranch'])) { $MergeToBranch = $configuration['MergeToBranch'] - }else{ - Write-Warning "Configuration provided is incorrect and does not contain the required parameter: MergeToBranch" - exit 0 + } else { + throw "Configuration for branch '$MergeFromBranch' must contain a non-empty 'MergeToBranch' value." } $ExtraSwitches = ""; - if($configuration.ContainsKey('ExtraSwitches')){ + if ($configuration.ContainsKey('ExtraSwitches')) { $ExtraSwitches = $configuration['ExtraSwitches'] } $ResetToTargetPaths = ""; - if($configuration.ContainsKey('ResetToTargetPaths')){ + if ($configuration.ContainsKey('ResetToTargetPaths')) { # Convert array to semicolon-separated string for output $ResetToTargetPaths = $configuration['ResetToTargetPaths'] -join ";" } @@ -109,5 +119,3 @@ if ($configuration -ne $null) { "resetToTargetPaths=$ResetToTargetPaths" | Out-File -FilePath $env:GITHUB_OUTPUT -Append "configurationFound=$true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append } - -exit 0 \ No newline at end of file From 74abdb6ff80df8c3a324148a2509e90137e31161 Mon Sep 17 00:00:00 2001 From: Missy Messa Date: Fri, 21 Aug 2026 13:37:18 -0700 Subject: [PATCH 2/2] Validate merge configuration value types Ensure non-object JSON roots receive the targeted schema error and reject non-string MergeToBranch values before producing workflow outputs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 040f9d82-5d74-492a-a03d-71f0143afb36 --- .github/workflows/scripts/read-configuration.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/scripts/read-configuration.ps1 b/.github/workflows/scripts/read-configuration.ps1 index 5aee5c96db8..52e5967a2f6 100644 --- a/.github/workflows/scripts/read-configuration.ps1 +++ b/.github/workflows/scripts/read-configuration.ps1 @@ -71,7 +71,7 @@ function GetConfiguration { throw "Invalid JSON in configuration file '$urlToConfigurationFile'. $($_.Exception.Message)" } - if ($null -eq $mergeFlowConfig -or + if ($mergeFlowConfig -isnot [System.Collections.IDictionary] -or !$mergeFlowConfig.ContainsKey('merge-flow-configurations') -or $mergeFlowConfig['merge-flow-configurations'] -isnot [System.Collections.IDictionary]) { throw "Configuration file '$urlToConfigurationFile' must contain a 'merge-flow-configurations' object." @@ -96,11 +96,12 @@ function GetConfiguration { $configuration = GetConfiguration if ($configuration -ne $null) { - if ($configuration.ContainsKey('MergeToBranch') -and - ![string]::IsNullOrWhiteSpace([string]$configuration['MergeToBranch'])) { - $MergeToBranch = $configuration['MergeToBranch'] + $configuredMergeToBranch = $configuration['MergeToBranch'] + if ($configuredMergeToBranch -is [string] -and + ![string]::IsNullOrWhiteSpace($configuredMergeToBranch)) { + $MergeToBranch = $configuredMergeToBranch } else { - throw "Configuration for branch '$MergeFromBranch' must contain a non-empty 'MergeToBranch' value." + throw "Configuration for branch '$MergeFromBranch' must contain a non-empty string 'MergeToBranch' value." } $ExtraSwitches = "";