src/Connect-CciGet.ps1
|
function Connect-CciGet { <# .SYNOPSIS Register configured CCI feeds as PSResource repositories and prepare credentials. .DESCRIPTION For each enabled feed in Get-CciGetConfig, Connect-CciGet: - Ensures the Azure Artifacts Credential Provider is installed (one-time bootstrap on Windows; uses the Microsoft installer at https://github.com/microsoft/artifacts-credprovider). - Calls Register-PSResourceRepository for the feed (idempotent). After Connect-CciGet succeeds, Find-CciModule / Install-CciModule will transparently use the user's Entra identity (or, in CI, a workload identity) to authenticate to the feed. No PATs are required. .PARAMETER Tenant Optional. Limit registration to the named feed only. .PARAMETER SkipCredentialProvider Skip the credential-provider bootstrap (use when you have managed it centrally or are running in CI with a different auth strategy). #> [CmdletBinding()] param( [string]$Tenant, [switch]$SkipCredentialProvider ) if (-not (Get-Module -ListAvailable -Name Microsoft.PowerShell.PSResourceGet)) { throw "cciget: Microsoft.PowerShell.PSResourceGet is required but not installed. Run: Install-Module Microsoft.PowerShell.PSResourceGet -Scope CurrentUser" } Import-Module Microsoft.PowerShell.PSResourceGet -ErrorAction Stop if (-not $SkipCredentialProvider) { $pluginRoot = Join-Path $env:USERPROFILE '.nuget\plugins\netcore' if (-not (Test-Path $pluginRoot) -or -not (Get-ChildItem $pluginRoot -Filter 'CredentialProvider.Microsoft.dll' -Recurse -ErrorAction SilentlyContinue)) { Write-Host "cciget: installing Azure Artifacts Credential Provider..." try { $script = (New-Object System.Net.WebClient).DownloadString('https://aka.ms/install-artifacts-credprovider.ps1') Invoke-Expression $script } catch { Write-Warning "cciget: credential provider install failed: $_. You may need to install manually from https://github.com/microsoft/artifacts-credprovider." } } } $feeds = _Resolve-CciGetFeed -Tenant $Tenant $authFailed = @() # Configure credential provider env vars for the session. # These persist after Connect-CciGet returns so Find-CciModule benefits too. $env:NUGET_CREDENTIALPROVIDER_MSAL_ALLOW_DEVICECODEFLOW = 'true' $env:NUGET_CREDENTIALPROVIDER_MSAL_ALLOWBROKER = 'true' # If an Azure CLI session is active, pre-seed feed credentials so the # credential provider doesn't need to prompt interactively. This allows # non-interactive scenarios (remoting, CI, WAM-incompatible shells). $azdoToken = $null if (Get-Command az -ErrorAction SilentlyContinue) { try { $azdoToken = az account get-access-token --resource '499b84ac-1321-427f-aa17-267ca6975798' --query accessToken -o tsv 2>$null } catch { } } if ($azdoToken) { $endpoints = @{ endpointCredentials = @($feeds | ForEach-Object { @{ endpoint = $_.url; username = 'VssSessionToken'; password = $azdoToken } }) } $env:VSS_NUGET_EXTERNAL_FEED_ENDPOINTS = $endpoints | ConvertTo-Json -Compress -Depth 3 Write-Verbose "cciget: seeded feed credentials from Azure CLI session." } foreach ($feed in $feeds) { $repoName = _Get-CciGetRepositoryName -FeedName $feed.name # Set tenant-specific authority for this feed. if ($feed.tenantId) { $env:NUGET_CREDENTIALPROVIDER_MSAL_AUTHORITY = "https://login.microsoftonline.com/$($feed.tenantId)" } $existing = Get-PSResourceRepository -Name $repoName -ErrorAction SilentlyContinue if ($existing) { if ($existing.Uri -ne $feed.url) { Set-PSResourceRepository -Name $repoName -Uri $feed.url -Trusted Write-Verbose "cciget: updated $repoName URL." } } else { Register-PSResourceRepository -Name $repoName -Uri $feed.url -Trusted Write-Host "cciget: registered repository '$repoName' -> $($feed.url)" } # Verify auth by probing the feed. This triggers the credential provider # now (at connect time) so auth issues surface here, not in Find-CciModule. Write-Host "cciget: authenticating to '$repoName'..." $probeOk = $false try { # Use a wildcard probe — this hits the V2 search endpoint which # actually requires authentication, unlike specific-name lookups # which may return empty 200s without auth. $null = Find-PSResource -Name '*' -Repository $repoName -ErrorAction Stop # Got results — auth works and the feed has packages. $probeOk = $true } catch { $msg = $_.Exception.Message if ($msg -match 'No match was found|could not be found in repository') { # Auth succeeded — feed is simply empty. $probeOk = $true } elseif ($msg -match '\[Warning\].*CredentialProvider' -and $msg -notmatch '401|Unauthorized|forbidden') { Write-Verbose "cciget: credential provider warning (non-fatal): $msg" $probeOk = $true } else { Write-Warning "cciget: authentication failed for '$repoName'." Write-Warning " Error: $msg" if (-not $azdoToken) { Write-Warning " Hint: install Azure CLI and run 'az login' first, then retry Connect-CciGet." } $authFailed += $repoName } } if ($probeOk) { Write-Host "cciget: '$repoName' authenticated and ready." } } if ($authFailed.Count -gt 0) { Write-Warning "cciget: $($authFailed.Count) feed(s) failed authentication: $($authFailed -join ', ')" Write-Warning "cciget: You may need to run Connect-CciGet again. If prompted for a device code, complete the sign-in in your browser." } # Return a clean summary instead of the wide default table. Get-PSResourceRepository -Name (_Get-CciGetRepositoryName -FeedName '*') | Select-Object Name, Uri, Trusted } |