Skip to content

Commit 73e0b72

Browse files
fix: handle expired gh CLI tokens and macOS restricted file access (#533)
## Summary Fixes two classes of user-reported failures: 1. **GitHub API 403s when the `gh` CLI token is expired.** The module attaches the token from `gh auth token` to API requests; when that token is expired or has insufficient scopes, `api.github.com` returns 403 and the deployment fails with a misleading downstream error (`The release v does not exist...`). 2. **macOS file access errors** on protected paths when reading files without `-Force`. ## Changes ### GitHub auth resiliency - `Invoke-GitHubApiRequest`: when the attached `gh` token causes a 401/403, automatically retry once without auth (anonymous, subject to rate limits) and warn the user to run `gh auth login`. Applies to all three code paths (file download, `SkipHttpErrorCheck`, standard API call). Factored repeated logic into `Disable-AuthAndWarn` and `Get-StatusCodeFromError` helpers. - `Get-GithubReleaseTag`: on 401/403, throw an actionable error naming the likely cause (expired gh token or rate limiting) and the fix (`gh auth login`) instead of the generic "check your internet connection" message. - `Test-NetworkConnectivity`: inspect the status code from the `api.github.com` probe and record 401/403 as a Failure with the same guidance, so connectivity checks surface this issue up front. ### macOS file access - Added `-Force` to every `Get-Item`, `Get-ChildItem`, and `Get-Content` call across the module so reads succeed on macOS paths where hidden/protected attributes would otherwise block access. (`Test-Path` / `Resolve-Path` intentionally untouched — they do not support `-Force`.) ### UX - `Get-AzureContext`: clarified that "Querying Azure for management groups, subscriptions, and regions..." can take up to 30 seconds. ## Testing - `Invoke-Build -File .\src\ALZ.build.ps1` — passes locally. - Existing `Test-NetworkConnectivity.Tests.ps1` still covers the mocked success/failure paths.
1 parent 7832440 commit 73e0b72

21 files changed

Lines changed: 107 additions & 42 deletions

‎src/ALZ/ALZ.psm1‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Write-Verbose "Discovering Public & Private src."
44
$itemSplat = @{
55
Filter = '*.ps1'
66
Recurse = $true
7+
Force = $true
78
ErrorAction = 'Stop'
89
}
910
try {

‎src/ALZ/Private/Config-Helpers/Edit-ALZConfigurationFilesInPlace.ps1‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ function Edit-ALZConfigurationFilesInPlace {
1515

1616
foreach ($location in $locations) {
1717
$bicepModules = Join-Path $alzEnvironmentDestination $location
18-
$files += @(Get-ChildItem -Path $bicepModules -Recurse -Filter *.parameters.*.json)
18+
$files += @(Get-ChildItem -Path $bicepModules -Recurse -Filter *.parameters.*.json -Force)
1919
}
2020

2121
foreach ($file in $files) {
2222
Write-Verbose "Checking Bicep parameter file: $($file.Name)"
23-
$bicepConfiguration = Get-Content $file.FullName | ConvertFrom-Json -AsHashtable
23+
$bicepConfiguration = Get-Content $file.FullName -Force | ConvertFrom-Json -AsHashtable
2424
$modified = $false
2525

2626
foreach ($configKey in $configuration.PsObject.Properties) {

‎src/ALZ/Private/Config-Helpers/Get-ALZConfig.ps1‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ function Get-ALZConfig {
1818
}
1919

2020
# Import the config and transform it to a PowerShell object
21-
$extension = (Get-Item -Path $configFilePath).Extension.ToLower()
21+
$extension = (Get-Item -Path $configFilePath -Force).Extension.ToLower()
2222
$config = $null
2323
if ($extension -eq ".yml" -or $extension -eq ".yaml") {
2424
try {
25-
$config = [PSCustomObject](Get-Content -Path $configFilePath | ConvertFrom-Yaml -Ordered)
25+
$config = [PSCustomObject](Get-Content -Path $configFilePath -Force | ConvertFrom-Yaml -Ordered)
2626
} catch {
2727
$errorMessage = "Failed to parse YAML inputs. Please check the YAML file for errors and try again. $_"
2828
Write-ToConsoleLog $errorMessage -IsError
@@ -31,7 +31,7 @@ function Get-ALZConfig {
3131

3232
} elseif ($extension -eq ".json") {
3333
try {
34-
$config = [PSCustomObject](Get-Content -Path $configFilePath | ConvertFrom-Json)
34+
$config = [PSCustomObject](Get-Content -Path $configFilePath -Force | ConvertFrom-Json)
3535
} catch {
3636
$errorMessage = "Failed to parse JSON inputs. Please check the JSON file for errors and try again. $_"
3737
Write-ToConsoleLog $errorMessage -IsError

‎src/ALZ/Private/Config-Helpers/Get-AzureRegionData.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function Get-AzureRegionData {
4949

5050
Invoke-Terraform -moduleFolderPath $regionFolder -autoApprove -output "regions_and_zones" -outputFilePath $outputFilePath -silent
5151

52-
$json = Get-Content $outputFilePath
52+
$json = Get-Content $outputFilePath -Force
5353
$regionsAndZones = ConvertFrom-Json $json
5454

5555
$zonesSupport = @()

‎src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AcceleratorFolderConfiguration.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ function Get-AcceleratorFolderConfiguration {
6767

6868
# Try to read and validate inputs.yaml
6969
try {
70-
$inputsContent = Get-Content -Path $inputsYamlPath -Raw
70+
$inputsContent = Get-Content -Path $inputsYamlPath -Raw -Force
7171
$inputsYaml = $inputsContent | ConvertFrom-Yaml
7272

7373
$result.InputsContent = $inputsContent

‎src/ALZ/Private/Deploy-Accelerator-Helpers/Get-AzureContext.ps1‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,11 @@ function Get-AzureContext {
4040

4141
# Check if valid cache exists
4242
if (Test-Path $cacheFilePath) {
43-
$cacheFile = Get-Item $cacheFilePath
43+
$cacheFile = Get-Item $cacheFilePath -Force
4444
$cacheAge = (Get-Date) - $cacheFile.LastWriteTime
4545
if ($cacheAge.TotalHours -lt $cacheExpirationHours) {
4646
try {
47-
$cachedContext = Get-Content -Path $cacheFilePath -Raw | ConvertFrom-Json -AsHashtable
47+
$cachedContext = Get-Content -Path $cacheFilePath -Raw -Force | ConvertFrom-Json -AsHashtable
4848
Write-ToConsoleLog "Using cached Azure context (cached $([math]::Round($cacheAge.TotalMinutes)) minutes ago). Use -clearCache to refresh."
4949
Write-ToConsoleLog "Found $($cachedContext.ManagementGroups.Count) management groups, $($cachedContext.Subscriptions.Count) subscriptions, and $($cachedContext.Regions.Count) regions"
5050
return $cachedContext
@@ -60,7 +60,7 @@ function Get-AzureContext {
6060
Regions = @()
6161
}
6262

63-
Write-ToConsoleLog "Querying Azure for management groups, subscriptions, and regions..."
63+
Write-ToConsoleLog "Querying Azure for management groups, subscriptions, and regions... (this can take up to 30 seconds)"
6464

6565
try {
6666
# Get the current tenant ID

‎src/ALZ/Private/Deploy-Accelerator-Helpers/Get-ModuleVersionData.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function Get-ModuleVersionData {
1212
$dataFilePath = Join-Path $targetDirectory ".alz-version-data.json"
1313

1414
if (Test-Path $dataFilePath) {
15-
$data = Get-Content $dataFilePath | ConvertFrom-Json
15+
$data = Get-Content $dataFilePath -Force | ConvertFrom-Json
1616
$versionKey = "$($moduleType)Version"
1717
return $data.$versionKey
1818
}

‎src/ALZ/Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ function New-Bootstrap {
132132
$bootstrapParameters = [PSCustomObject]@{}
133133

134134
Write-Verbose "Getting the bootstrap configuration..."
135-
$terraformFiles = Get-ChildItem -Path $bootstrapModulePath -Filter "*.tf" -File
135+
$terraformFiles = Get-ChildItem -Path $bootstrapModulePath -Filter "*.tf" -File -Force
136136
foreach ($terraformFile in $terraformFiles) {
137137
$bootstrapParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $bootstrapParameters
138138
}
@@ -145,7 +145,7 @@ function New-Bootstrap {
145145
if ($hasStarter) {
146146
Write-Verbose "Getting the starter configuration..."
147147
if ($iac -eq "terraform") {
148-
$terraformFiles = Get-ChildItem -Path $starterRootModuleFolderPath -Filter "*.tf" -File
148+
$terraformFiles = Get-ChildItem -Path $starterRootModuleFolderPath -Filter "*.tf" -File -Force
149149
foreach ($terraformFile in $terraformFiles) {
150150
$starterParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $starterParameters
151151
}
@@ -215,7 +215,7 @@ function New-Bootstrap {
215215
if ($iac -eq "terraform") {
216216
if ($starterFoldersToRetain.Length -gt 0) {
217217
Write-Verbose "Removing unwanted folders from the starter module..."
218-
$folders = Get-ChildItem -Path $starterModulePath -Directory
218+
$folders = Get-ChildItem -Path $starterModulePath -Directory -Force
219219
foreach ($folder in $folders) {
220220
if ($starterFoldersToRetain -notcontains $folder.Name) {
221221
Write-Verbose "Removing folder: $($folder.FullName)"

‎src/ALZ/Private/Deploy-Accelerator-Helpers/New-ModuleSetup.ps1‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ function New-ModuleSetup {
177177

178178
if (!$firstRun) {
179179
Write-Verbose "Checking for state files at: $previousStatePath"
180-
$previousStateFiles = Get-ChildItem $previousVersionPath -Filter "terraform.tfstate" -Recurse | Select-Object -First 1 | ForEach-Object { $_.FullName }
180+
$previousStateFiles = Get-ChildItem $previousVersionPath -Filter "terraform.tfstate" -Recurse -Force | Select-Object -First 1 | ForEach-Object { $_.FullName }
181181

182182
if ($previousStateFiles.Count -gt 0) {
183183
foreach ($stateFile in $previousStateFiles) {

‎src/ALZ/Private/Deploy-Accelerator-Helpers/Request-ALZConfigurationValue.ps1‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ function Request-ALZConfigurationValue {
178178
Write-ToConsoleLog "Schema file not found at $schemaPath. Proceeding without descriptions." -IsWarning
179179
$schema = $null
180180
} else {
181-
$schema = Get-Content -Path $schemaPath -Raw | ConvertFrom-Json
181+
$schema = Get-Content -Path $schemaPath -Raw -Force | ConvertFrom-Json
182182
}
183183

184184
# Define the configuration files to process
@@ -192,7 +192,7 @@ function Request-ALZConfigurationValue {
192192
Write-ToConsoleLog "For more information, see: https://aka.ms/alz/acc/phase0"
193193

194194
# Read the raw content to preserve comments and ordering
195-
$inputsYamlContent = Get-Content -Path $inputsYamlPath -Raw
195+
$inputsYamlContent = Get-Content -Path $inputsYamlPath -Raw -Force
196196
$inputsConfig = $inputsYamlContent | ConvertFrom-Yaml -Ordered
197197
$inputsUpdated = $false
198198
$sensitiveEnvVars = @{}

0 commit comments

Comments
 (0)