diff --git a/.vsts-ci.yml b/.vsts-ci.yml index cbf834db..b06e930c 100644 --- a/.vsts-ci.yml +++ b/.vsts-ci.yml @@ -21,7 +21,12 @@ stages: parameters: nuspecProperties: 'VersionSuffix=CI-$(Build.BuildNumber)' -- stage: Validate +- stage: ValidateInstall dependsOn: [] jobs: - template: build/validate-install-script.yml + +- stage: ValidateInstallRelease + dependsOn: [] + jobs: + - template: build/validate-install-release-script.yml diff --git a/.vsts-pr.yml b/.vsts-pr.yml index c290d3c9..d1681d5e 100644 --- a/.vsts-pr.yml +++ b/.vsts-pr.yml @@ -4,8 +4,9 @@ resources: pool: vmImage: windows-latest -trigger: +pr: - master +- releases/* variables: BuildConfiguration: 'Debug' @@ -21,7 +22,12 @@ stages: parameters: nuspecProperties: 'VersionSuffix=CI-$(Build.BuildNumber)' -- stage: Validate +- stage: ValidateInstall dependsOn: [] jobs: - template: build/validate-install-script.yml + +- stage: ValidateInstallRelease + dependsOn: [] + jobs: + - template: build/validate-install-release-script.yml diff --git a/Build.props b/Build.props index df2097f1..3a671f29 100644 --- a/Build.props +++ b/Build.props @@ -1,9 +1,9 @@ - 1.4.1 + 2.0.0 - netcoreapp3.1;net461;net481;net6.0;net8.0 + net481;net6.0;net8.0 diff --git a/CredentialProvider.Microsoft.VSIX/Microsoft.CredentialProvider.swixproj b/CredentialProvider.Microsoft.VSIX/Microsoft.CredentialProvider.swixproj index 9c7dc798..0943ea39 100644 --- a/CredentialProvider.Microsoft.VSIX/Microsoft.CredentialProvider.swixproj +++ b/CredentialProvider.Microsoft.VSIX/Microsoft.CredentialProvider.swixproj @@ -19,7 +19,7 @@ .\bin\$(Configuration)\ $(OutputPath) - ..\CredentialProvider.Microsoft\bin\$(Configuration)\net461\ + ..\CredentialProvider.Microsoft\bin\$(Configuration)\net481\ diff --git a/CredentialProvider.Microsoft/CredentialProvider.Microsoft.nuspec b/CredentialProvider.Microsoft/CredentialProvider.Microsoft.nuspec index c761df78..2654af30 100644 --- a/CredentialProvider.Microsoft/CredentialProvider.Microsoft.nuspec +++ b/CredentialProvider.Microsoft/CredentialProvider.Microsoft.nuspec @@ -17,9 +17,7 @@ - - diff --git a/build/build.yml b/build/build.yml index d515be32..01c8fa8f 100644 --- a/build/build.yml +++ b/build/build.yml @@ -3,12 +3,6 @@ parameters: nuspecProperties: '' steps: -- task: UseDotNet@2 - displayName: Install .NET Core 3.1 runtime - inputs: - packageType: runtime - version: 3.1.x - - task: UseDotNet@2 displayName: Use .NET 6 runtime inputs: @@ -143,74 +137,8 @@ steps: archiveFile: '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\Microsoft.Net8.NuGet.CredentialProvider.zip' replaceExistingArchive: true -# Clean target folder and create netcore 3.1 and netfx releases -- script: dotnet publish CredentialProvider.Microsoft/CredentialProvider.Microsoft.csproj --no-build --framework netcoreapp3.1 --configuration $(BuildConfiguration) -p:${{ parameters.nuspecProperties }} - displayName: dotnet publish netcoreapp3.1 - -- task: CopyFiles@2 - displayName: Copy netcore 3.1 files into tarball - inputs: - sourceFolder: '$(Build.SourcesDirectory)\CredentialProvider.Microsoft\bin\$(BuildConfiguration)\netcoreapp3.1\publish\' - contents: '**\*' - targetFolder: '$(Build.ArtifactStagingDirectory)\tarball\plugins\netcore\CredentialProvider.Microsoft\' - cleanTargetFolder: true - -- task: CopyFiles@2 - displayName: Copy license files into tarball - inputs: - contents: | - LICENSE - CredentialProvider.Microsoft\EULA_Microsoft Visual Studio Team Services Credential Provider.docx - CredentialProvider.Microsoft\ThirdPartyNotices.txt - targetFolder: '$(Build.ArtifactStagingDirectory)\tarball\' - flattenFolders: true - -- task: ArchiveFiles@2 - displayName: Create netcore 3.1 tarball - inputs: - rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\tarball\' - includeRootFolder: false - archiveType: 'tar' - tarCompression: 'gz' - archiveFile: '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\Microsoft.NetCore3.NuGet.CredentialProvider.tar.gz' - replaceExistingArchive: true - -# NOTE: Changing the name of the zip will break things. Please don't do it. -- task: ArchiveFiles@2 - displayName: Create netcore 3.1 zip - inputs: - rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\tarball\' - includeRootFolder: false - archiveType: 'zip' - archiveFile: '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\Microsoft.NetCore3.NuGet.CredentialProvider.zip' - replaceExistingArchive: true - -- task: CopyFiles@2 - displayName: Copy netfx files into tarball - inputs: - sourceFolder: '$(Build.SourcesDirectory)\CredentialProvider.Microsoft\bin\$(BuildConfiguration)\net461\' - contents: '**\*' - targetFolder: '$(Build.ArtifactStagingDirectory)\tarball\plugins\netfx\CredentialProvider.Microsoft\' - -- task: ArchiveFiles@2 - displayName: Create netfx tarball - inputs: - rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\tarball\' - includeRootFolder: false - archiveType: 'tar' - tarCompression: 'gz' - archiveFile: '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\Microsoft.NuGet.CredentialProvider.tar.gz' - replaceExistingArchive: true - +# Clean target folder and create netfx releases # NOTE: Changing the name of the zip will break things. Please don't do it. -- task: ArchiveFiles@2 - displayName: Create zip - inputs: - rootFolderOrFile: '$(Build.ArtifactStagingDirectory)\tarball\' - includeRootFolder: false - archiveType: 'zip' - archiveFile: '$(Build.ArtifactStagingDirectory)\$(BuildConfiguration)\Microsoft.NuGet.CredentialProvider.zip' - replaceExistingArchive: true - task: CopyFiles@2 displayName: Copy netfx 4.8.1 files into tarball diff --git a/build/validate-install-release-script-bash.yml b/build/validate-install-release-script-bash.yml new file mode 100644 index 00000000..bc0ead9b --- /dev/null +++ b/build/validate-install-release-script-bash.yml @@ -0,0 +1,48 @@ +parameters: +- name: repo + type: string +- name: scriptEnvVariables + type: string +- name: expectedCredentialProviderVersion + type: string +- name: releaseVersion + type: string + default: 'latest' + +steps: +- checkout: ${{ parameters.repo }} +- bash: | + ${{ parameters.scriptEnvVariables }} + + RELEASE_VERSION="${{ parameters.releaseVersion }}" + if [ "$RELEASE_VERSION" = "latest" ]; then + ./helpers/installcredproviderrelease.sh -Force >> ./output.log 2>&1 + else + export AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION="$RELEASE_VERSION" + ./helpers/installcredproviderrelease.sh -Force >> ./output.log 2>&1 + fi + + cat ./output.log + + # Check if expected credential provider version was found in output + if ! grep "${{ parameters.expectedCredentialProviderVersion }}" ./output.log; then + echo "Expected credential provider not found in output" + exit 1 + fi + + # Verify the credential provider directory was created + if [ ! -d "$HOME/.nuget/plugins/netcore/CredentialProvider.Microsoft" ]; then + echo "Credential provider plugin directory not found at: $HOME/.nuget/plugins/netcore/CredentialProvider.Microsoft" + exit 1 + fi + + echo "Credential provider installed successfully via release script" + workingDirectory: $(Build.SourcesDirectory) + displayName: Validate Install Release Script +- bash: | + if grep $'\r' ./helpers/installcredproviderrelease.sh; then + echo "CRLF line ending found" + exit 1 + fi + workingDirectory: $(Build.SourcesDirectory) + displayName: Check Line Endings diff --git a/build/validate-install-release-script-powershell.yml b/build/validate-install-release-script-powershell.yml new file mode 100644 index 00000000..526b2d6d --- /dev/null +++ b/build/validate-install-release-script-powershell.yml @@ -0,0 +1,43 @@ +parameters: +- name: repo + type: string +- name: scriptInputs + type: string +- name: expectedCredentialProviderVersion + type: string +- name: releaseVersion + type: string + default: 'latest' + +steps: +- checkout: ${{ parameters.repo }} +- task: PowerShell@2 + displayName: Validate Install Release Script + inputs: + targetType: 'inline' + script: | + $releaseVersion = "${{ parameters.releaseVersion }}" + if ($releaseVersion -eq "latest") { + ./helpers/installcredproviderrelease.ps1 ${{ parameters.scriptInputs }} -Force 6>> ./output.log + } else { + ./helpers/installcredproviderrelease.ps1 -Version $releaseVersion ${{ parameters.scriptInputs }} -Force 6>> ./output.log + } + + cat ./output.log + + # Check if expected credential provider version was installed + if( (Select-String -Path .\output.log -Pattern ${{ parameters.expectedCredentialProviderVersion }}) -eq $null) { + echo "Expected credential provider file not found in output." + exit 1 + } + + # Verify the credential provider was actually installed + $pluginPath = "$env:USERPROFILE\.nuget\plugins\netcore\CredentialProvider.Microsoft" + if (!(Test-Path $pluginPath)) { + echo "Credential provider plugin directory not found at: $pluginPath" + exit 1 + } + + echo "Credential provider installed successfully via release script" + workingDirectory: $(Build.SourcesDirectory) + failOnStderr: false diff --git a/build/validate-install-release-script.yml b/build/validate-install-release-script.yml new file mode 100644 index 00000000..d862cc35 --- /dev/null +++ b/build/validate-install-release-script.yml @@ -0,0 +1,236 @@ +jobs: +- job: WindowsReleaseInstallDefault + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '' + expectedCredentialProviderVersion: 'Microsoft.Net6.NuGet.CredentialProvider' # Temporary, will be updated to Net8 once the 2.x release is available + releaseVersion: 'latest' + +- job: WindowsReleaseInstallNet8 + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet8' + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: WindowsReleaseInstallNet8winx64 + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet8 -RuntimeIdentifier win-x64' + expectedCredentialProviderVersion: 'Microsoft.Net8.win-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: WindowsReleaseInstallNet8winx64NoParams + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-RuntimeIdentifier win-x64' + expectedCredentialProviderVersion: 'Microsoft.Net8.win-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: WindowsReleaseInstallNetfxDefault + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-AddNetfx' + expectedCredentialProviderVersion: 'Microsoft.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallDefault + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: '' + expectedCredentialProviderVersion: 'Microsoft.Net6.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallNet8 + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallNet8Net6Param + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=true + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallNetFx + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=false + expectedCredentialProviderVersion: 'Microsoft.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallNet8linuxx64 + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=linux-x64 + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: LinuxReleaseInstallNet8linuxarm64 + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=linux-arm64 + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-arm64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: macOSReleaseInstallNet8osxarm64 + pool: + vmImage: macOS-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=osx-arm64 + expectedCredentialProviderVersion: 'Microsoft.Net8.osx-arm64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: macOSReleaseInstallNet8osxx64 + pool: + vmImage: macOS-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=osx-x64 + expectedCredentialProviderVersion: 'Microsoft.Net8.osx-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: macOSReleaseInstallNet8osxx64NoParams + pool: + vmImage: macOS-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=osx-x64 + expectedCredentialProviderVersion: 'Microsoft.Net8.osx-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +- job: macOSReleaseInstallNet8osxx64Net6Params + pool: + vmImage: macOS-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=true + export ARTIFACTS_CREDENTIAL_PROVIDER_RID=osx-x64 + expectedCredentialProviderVersion: 'Microsoft.Net8.osx-x64.NuGet.CredentialProvider' + releaseVersion: 'latest' + +# Test with specific release version (using a common stable version 1.4.0) +- job: WindowsReleaseInstallVersionNoPrefix + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet8' + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: '1.4.0' + +# TODO: enable the below job when a 2.x release is available, prior to 2.x version must have the v prefix +# - job: LinuxReleaseInstallVersionNoPrefix +# pool: +# vmImage: ubuntu-latest +# steps: +# - template: validate-install-release-script-bash.yml@self +# parameters: +# repo: self +# scriptEnvVariables: | +# export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false +# export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true +# expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' +# releaseVersion: '1.4.0' + +- job: WindowsReleaseInstallVersion + pool: + vmImage: windows-latest + steps: + - template: validate-install-release-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet8' + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: 'v1.4.0' + +- job: LinuxReleaseInstallVersion + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-release-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + releaseVersion: 'v1.4.0' diff --git a/build/validate-install-script.yml b/build/validate-install-script.yml index 88a9ab90..66da2071 100644 --- a/build/validate-install-script.yml +++ b/build/validate-install-script.yml @@ -7,7 +7,25 @@ jobs: parameters: repo: self scriptInputs: '' + expectedCredentialProviderVersion: 'Microsoft.Net8.win-x64.NuGet.CredentialProvider' +- job: WindowsInstallNet6 + pool: + vmImage: windows-latest + steps: + - template: validate-install-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet6 -InstallNet8:$False' expectedCredentialProviderVersion: 'Microsoft.Net6.NuGet.CredentialProvider' +- job: WindowsInstallNet8NonSC + pool: + vmImage: windows-latest + steps: + - template: validate-install-script-powershell.yml@self + parameters: + repo: self + scriptInputs: '-InstallNet8 -NonSelfContained' + expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' - job: WindowsInstallNet8 pool: vmImage: windows-latest @@ -16,7 +34,7 @@ jobs: parameters: repo: self scriptInputs: '-InstallNet8' - expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + expectedCredentialProviderVersion: 'Microsoft.Net8.win-x64.NuGet.CredentialProvider' - job: WindowsInstallNet8winx64 pool: vmImage: windows-latest @@ -52,7 +70,7 @@ jobs: parameters: repo: self scriptInputs: '-AddNetfx' - expectedCredentialProviderVersion: 'Microsoft.NuGet.CredentialProvider' + expectedCredentialProviderVersion: 'Microsoft.NetFx48.NuGet.CredentialProvider' - job: WindowsInstallNetfx48 pool: vmImage: windows-latest @@ -60,7 +78,7 @@ jobs: - template: validate-install-script-powershell.yml@self parameters: repo: self - scriptInputs: '-AddNetFx48' + scriptInputs: '-AddNetfx48' expectedCredentialProviderVersion: 'Microsoft.NetFx48.NuGet.CredentialProvider' - job: LinuxInstallDefault pool: @@ -70,7 +88,7 @@ jobs: parameters: repo: self scriptEnvVariables: '' - expectedCredentialProviderVersion: 'Microsoft.Net6.NuGet.CredentialProvider' + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' - job: LinuxInstallNet8 pool: vmImage: ubuntu-latest @@ -81,7 +99,28 @@ jobs: scriptEnvVariables: | export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' +- job: LinuxInstallNet8NonSC + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export ARTIFACTS_CREDENTIAL_PROVIDER_NON_SC=true expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' +- job: LinuxInstallNet6 + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: | + export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=true + export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=false + expectedCredentialProviderVersion: 'Microsoft.Net6.NuGet.CredentialProvider' - job: LinuxInstallNet8Net6Param pool: vmImage: ubuntu-latest @@ -92,7 +131,7 @@ jobs: scriptEnvVariables: | export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=true export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true - expectedCredentialProviderVersion: 'Microsoft.Net8.NuGet.CredentialProvider' + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' - job: LinuxInstallNetFx pool: vmImage: ubuntu-latest @@ -103,7 +142,7 @@ jobs: scriptEnvVariables: | export USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=false export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=false - expectedCredentialProviderVersion: 'Microsoft.NuGet.CredentialProvider' + expectedCredentialProviderVersion: 'Microsoft.NetFx48.NuGet.CredentialProvider' - job: LinuxInstallNet8linuxx64 pool: vmImage: ubuntu-latest @@ -116,6 +155,15 @@ jobs: export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true export ARTIFACTS_CREDENTIAL_PROVIDER_RID=linux-x64 expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' +- job: LinuxInstallNet8Auto + pool: + vmImage: ubuntu-latest + steps: + - template: validate-install-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: '' + expectedCredentialProviderVersion: 'Microsoft.Net8.linux-x64.NuGet.CredentialProvider' - job: LinuxInstallNet8linuxarm64 pool: vmImage: ubuntu-latest @@ -152,6 +200,15 @@ jobs: export USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true export ARTIFACTS_CREDENTIAL_PROVIDER_RID=osx-x64 expectedCredentialProviderVersion: 'Microsoft.Net8.osx-x64.NuGet.CredentialProvider' +- job: macOSInstallNet8Auto + pool: + vmImage: macOS-latest + steps: + - template: validate-install-script-bash.yml@self + parameters: + repo: self + scriptEnvVariables: '' + expectedCredentialProviderVersion: 'Microsoft.Net8.osx-x64.NuGet.CredentialProvider' - job: macOSInstallNet8osxx64NoParams pool: vmImage: macOS-latest diff --git a/helpers/installcredprovider.ps1 b/helpers/installcredprovider.ps1 index 28678c54..7980eae9 100644 --- a/helpers/installcredprovider.ps1 +++ b/helpers/installcredprovider.ps1 @@ -7,7 +7,8 @@ for DotNet and/or NuGet to the ~/.nuget/plugins directory. .PARAMETER AddNetfx - Installs the .NET Framework 4.6.1 Credential Provider. + Installs the .NET Framework 4.8.1 Credential Provider. + For backwards compatability, this is equivalent to -AddNetfx48. .PARAMETER AddNetfx48 Installs the .NET Framework 4.8.1 Credential Provider. @@ -19,17 +20,18 @@ Specifies the GitHub release version of the Credential Provider to install. .PARAMETER InstallNet6 - Installs the .NET 6 Credential Provider (default). + Installs the .NET 6 Credential Provider. .PARAMETER InstallNet8 - Installs the .NET 8 Credential Provider. + Installs the .NET 8 Credential Provider (default). .PARAMETER RuntimeIdentifier Installs the self-contained Credential Provider for the specified Runtime Identifier. .EXAMPLE - .\installcredprovider.ps1 -InstallNet8 - .\installcredprovider.ps1 -Version "1.0.1" -Force + .\installcredprovider.ps1 -InstallNet8 -AddNetfx + .\installcredprovider.ps1 -Version "2.0.1" -Force + .\installcredprovider.ps1 -RuntimeIdentifier "osx-x64" -Force #> [CmdletBinding(HelpUri = "https://github.com/microsoft/artifacts-credprovider/blob/master/README.md#setup")] @@ -38,135 +40,106 @@ param( [switch]$AddNetfx48, [switch]$Force, [string]$Version, - [switch]$InstallNet6 = $true, - [switch]$InstallNet8, + [switch]$InstallNet6, + [switch]$InstallNet8 = $true, + [switch]$NonSelfContained, [string]$RuntimeIdentifier ) $script:ErrorActionPreference = 'Stop' -# Without this, System.Net.WebClient.DownloadFile will fail on a client with TLS 1.0/1.1 disabled -if ([Net.ServicePointManager]::SecurityProtocol.ToString().Split(',').Trim() -notcontains 'Tls12') { - [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 -} - -if ($Version.StartsWith("0.") -and $InstallNet6 -eq $True) { - Write-Error "You cannot install the .Net 6 version with versions lower than 1.0.0" - return -} -if (($Version.StartsWith("0.") -or $Version.StartsWith("1.0") -or $Version.StartsWith("1.1") -or $Version.StartsWith("1.2")) -and - ($InstallNet8 -eq $True -or $AddNetfx48 -eq $True)) { - Write-Error "You cannot install the .Net 8 or NetFX 4.8.1 version or with versions lower than 1.3.0" - return -} -if ($AddNetfx -eq $True -and $AddNetfx48 -eq $True) { - Write-Error "Please select a single .Net framework version to install" - return -} -if (![string]::IsNullOrEmpty($RuntimeIdentifier)) { - if (($Version.StartsWith("0.") -or $Version.StartsWith("1.0") -or $Version.StartsWith("1.1") -or $Version.StartsWith("1.2") -or $Version.StartsWith("1.3"))) { - Write-Error "You cannot install the .Net 8 self-contained version or with versions lower than 1.4.0" +function Initialize-InstallParameters { + # Start with invalid parameter checks + if (![string]::IsNullOrEmpty($Version)) { + if ($Version -notmatch '^\d+\.\d+\.\d+') { + Write-Error "Invalid version format specified. Please use the format #.#.# to override the release version." + return + } + } + # Check if the version is valid given the install options + if (![string]::IsNullOrEmpty($RuntimeIdentifier)) { + Write-Host "RuntimeIdentifier parameter is specified, the $RuntimeIdentifier self-contained version will be installed" + $InstallNet6 = $False + $InstallNet8 = $True + } + # If .NET 6 and 8 are specified, .NET 8 will be installed + if ($InstallNet6 -eq $True -and $InstallNet8 -eq $True) { + $InstallNet6 = $False + } + # Don't allow a no-op installation + if ($AddNetfx -eq $False -and $InstallNet6 -eq $False -and $InstallNet8 -eq $False) { + Write-Error "At least one of the runtime parameters -AddNetfx, -InstallNet6, or -InstallNet8 must be true." return } - - Write-Host "RuntimeIdentifier parameter is specified, the .Net 8 self-contained version will be installed" - $InstallNet6 = $False - $InstallNet8 = $True -} -if ($InstallNet6 -eq $True -and $InstallNet8 -eq $True) { - # InstallNet6 defaults to true, in the case of .Net 8 install, overwrite - $InstallNet6 = $False -} - -$userProfilePath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::UserProfile); -if ($userProfilePath -ne '') { - $profilePath = $userProfilePath } -else { - $profilePath = $env:UserProfile -} - -$tempPath = [System.IO.Path]::GetTempPath() - -$pluginLocation = [System.IO.Path]::Combine($profilePath, ".nuget", "plugins"); -$tempZipLocation = [System.IO.Path]::Combine($tempPath, "CredProviderZip"); -$localNetcoreCredProviderPath = [System.IO.Path]::Combine("netcore", "CredentialProvider.Microsoft"); -$localNetfxCredProviderPath = [System.IO.Path]::Combine("netfx", "CredentialProvider.Microsoft"); - -$fullNetfxCredProviderPath = [System.IO.Path]::Combine($pluginLocation, $localNetfxCredProviderPath) -$fullNetcoreCredProviderPath = [System.IO.Path]::Combine($pluginLocation, $localNetcoreCredProviderPath) - -$netfxExists = Test-Path -Path ($fullNetfxCredProviderPath) -$netcoreExists = Test-Path -Path ($fullNetcoreCredProviderPath) +function Get-RuntimeIdentifier { + $osName = Get-ComputerInfo -Property *OSName* | Select OSName + if ($osName -like "*linux*") { + $runtimeId = "linux" + } + elseif ($osName -like "*macos*" -or $osName -like "*darwin*") { + $runtimeId = "osx" + } + elseif ($osName -like "*windows*") { + $runtimeId = "win" + } + else { + Write-Warning "Unable to automatically detect a supported OS from '$osName'. The .NET 8 version will be installed by default. Please set the RuntimeIdentifier parameter to specify a runtime version." + return "" + } -# Check if plugin already exists if -Force swich is not set -if (!$Force) { - if ($AddNetfx -eq $True -and $netfxExists -eq $True -and $netcoreExists -eq $True) { - Write-Host "The netcore and netfx Credential Providers are already in $pluginLocation" - return + $osArch = (Get-CimInstance Win32_Processor).Architecture + switch ($osArch) { + 9 { $osArch = "-x64" } + 12 { $osArch = "-arm64" } + default { + Write-Warning "Unable to automatically detect a supported CPU architecture. The .NET 8 version will be installed by default. Please set the RuntimeIdentifier parameter to specify a runtime version." + return "" + } } - if ($AddNetfx -eq $False -and $netcoreExists -eq $True) { - Write-Host "The netcore Credential Provider is already in $pluginLocation" - return + # Windows on ARM64 runs x64 binaries + if ($osArch -eq "-arm64" -and $IsWindows) { + $runtimeId += "-x64" + } + else { + $runtimeId += $osArch } + + Write-Host "Calculated artifacts-credprovider RuntimeIdentifier: $runtimeId" + return $runtimeId } -# Get the zip file from the GitHub release -$releaseUrlBase = "https://api.github.com/repos/Microsoft/artifacts-credprovider/releases" -$versionError = "Unable to find the release version $Version from $releaseUrlBase" -$releaseId = "latest" -if (![string]::IsNullOrEmpty($Version)) { - try { - $releases = Invoke-WebRequest -UseBasicParsing $releaseUrlBase - $releaseJson = $releases | ConvertFrom-Json - $correctReleaseVersion = $releaseJson | ? { $_.name -eq $Version } - $releaseId = $correctReleaseVersion.id +function Get-ReleaseUrl { + # Get the file base URL from the GitHub release + $releaseUrlBase = "https://api.github.com/repos/Microsoft/artifacts-credprovider/releases" + $versionError = "Unable to find the release version $Version from $releaseUrlBase" + $releaseId = "latest" + if (![string]::IsNullOrEmpty($Version)) { + try { + $releases = Invoke-WebRequest -UseBasicParsing $releaseUrlBase + $releaseJson = $releases | ConvertFrom-Json + $correctReleaseVersion = $releaseJson | ? { $_.name -eq $Version } + $releaseId = $correctReleaseVersion.id + } + catch { + Write-Error $versionError + return + } } - catch { + + if (!$releaseId) { Write-Error $versionError return } -} -if (!$releaseId) { - Write-Error $versionError - return + $releaseUrlId = [System.IO.Path]::Combine($releaseUrlBase, $releaseId) + return $releaseUrlId.Replace("\", "/") } -$releaseUrl = [System.IO.Path]::Combine($releaseUrlBase, $releaseId) -$releaseUrl = $releaseUrl.Replace("\", "/") - -$releaseRidPart = "" -if (![string]::IsNullOrEmpty($RuntimeIdentifier)) { - $releaseRIdPart = $RuntimeIdentifier + "." -} - -if ($Version.StartsWith("0.")) { - # versions lower than 1.0.0 installed NetCore2 zip - $zipFile = "Microsoft.NetCore2.NuGet.CredentialProvider.zip" -} -if ($InstallNet6 -eq $True) { - $zipFile = "Microsoft.Net6.NuGet.CredentialProvider.zip" -} -if ($InstallNet8 -eq $True) { - $zipFile = "Microsoft.Net8.${releaseRidPart}NuGet.CredentialProvider.zip" -} -if ($AddNetfx -eq $True) { - Write-Warning "The .Net Framework 4.6.1 version of the Credential Provider is deprecated and will be removed in the next major release. Please migrate to the .Net Framework 4.8 or .Net Core versions." - $zipFile = "Microsoft.NuGet.CredentialProvider.zip" -} -if ($AddNetfx48 -eq $True) { - $zipFile = "Microsoft.NetFx48.NuGet.CredentialProvider.zip" -} -if (-not $zipFile) { - Write-Warning "The .Net Core 3.1 version of the Credential Provider is deprecated and will be removed in the next major release. Please migrate to the .Net 8 version." - $zipFile = "Microsoft.NetCore3.NuGet.CredentialProvider.zip" -} - -function InstallZip { - Write-Verbose "Using $zipFile" +function Install-CredProvider { + Write-Verbose "Using $archiveFile" try { Write-Host "Fetching release $releaseUrl" @@ -178,13 +151,13 @@ function InstallZip { if (!$releaseJson) { throw ("Unable to get content from JSON") } - $zipAsset = $releaseJson.assets | ? { $_.name -eq $zipFile } - if (!$zipAsset) { - throw ("Unable to find asset $zipFile from release json object") + $archiveAsset = $releaseJson.assets | ? { $_.name -eq $archiveFile } + if (!$archiveAsset) { + throw ("Unable to find asset $archiveFile from release json object") } - $packageSourceUrl = $zipAsset.browser_download_url + $packageSourceUrl = $archiveAsset.browser_download_url if (!$packageSourceUrl) { - throw ("Unable to find download url from asset $zipAsset") + throw ("Unable to find download url from asset $archiveAsset") } } catch { @@ -200,7 +173,7 @@ function InstallZip { New-Item -ItemType Directory -Force -Path $tempZipLocation # Download credential provider zip to the temp location - $pluginZip = ([System.IO.Path]::Combine($tempZipLocation, $zipFile)) + $pluginZip = ([System.IO.Path]::Combine($tempZipLocation, $archiveFile)) Write-Host "Downloading $packageSourceUrl to $pluginZip" try { $client = New-Object System.Net.WebClient @@ -212,15 +185,97 @@ function InstallZip { # Extract zip to temp directory Write-Host "Extracting zip to the Credential Provider temp directory $tempZipLocation" - Add-Type -AssemblyName System.IO.Compression.FileSystem - [System.IO.Compression.ZipFile]::ExtractToDirectory($pluginZip, $tempZipLocation) + # Add-Type -AssemblyName System.IO.Compression.FileSystem + if ($archiveFile -like "*.tar.gz") { + # Extract .tar.gz using tar, available on Windows 10 and later + Write-Host "Extracting tar.gz archive $pluginZip to $tempZipLocation" + tar -xzf $pluginZip -C $tempZipLocation + } + else { + # Extract .zip using Expand-Archive + Expand-Archive -Path $pluginZip -DestinationPath $tempZipLocation -Force + } +} + +# Without this, System.Net.WebClient.DownloadFile will fail on a client with TLS 1.0/1.1 disabled +if ([Net.ServicePointManager]::SecurityProtocol.ToString().Split(',').Trim() -notcontains 'Tls12') { + [Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12 +} + +# Run script parameter validation +# For backward compatibility, AddNetfx and AddNetfx48 are equivalent +if ($AddNetfx48 -eq $True) { + $AddNetfx = $True +} +Initialize-InstallParameters + +$userProfilePath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::UserProfile); +if ($userProfilePath -ne '') { + $profilePath = $userProfilePath +} +else { + $profilePath = $env:UserProfile +} + +$tempPath = [System.IO.Path]::GetTempPath() + +$pluginLocation = [System.IO.Path]::Combine($profilePath, ".nuget", "plugins"); +$tempZipLocation = [System.IO.Path]::Combine($tempPath, "CredProviderZip"); + +$localNetcoreCredProviderPath = [System.IO.Path]::Combine("netcore", "CredentialProvider.Microsoft"); +$localNetfxCredProviderPath = [System.IO.Path]::Combine("netfx", "CredentialProvider.Microsoft"); + +$fullNetfxCredProviderPath = [System.IO.Path]::Combine($pluginLocation, $localNetfxCredProviderPath) +$fullNetcoreCredProviderPath = [System.IO.Path]::Combine($pluginLocation, $localNetcoreCredProviderPath) + +$netfxExists = Test-Path -Path ($fullNetfxCredProviderPath) +$netcoreExists = Test-Path -Path ($fullNetcoreCredProviderPath) + +# Check if plugin already exists if -Force swich is not set +if (!$Force) { + if ($AddNetfx -eq $True -and $netfxExists -eq $True) { + Write-Host "The netfx Credential Providers are already in $pluginLocation. Please use -Force to overwrite." + return + } + + if (($InstallNet6 -eq $True -or $InstallNet8 -eq $True) -and $netcoreExists -eq $True) { + Write-Host "The netcore Credential Provider is already in $pluginLocation. Please use -Force to overwrite." + return + } } -# Call InstallZip function -InstallZip +$releaseUrl = Get-ReleaseUrl +if ($NonSelfContained -eq $True) { + $releaseRidPart = "" +} +elseif ([string]::IsNullOrEmpty($RuntimeIdentifier)) { + $releaseRidPart = "$(Get-RuntimeIdentifier)." +} +else { + $releaseRidPart = "$RuntimeIdentifier." +} + +if ($InstallNet6 -eq $True) { + $archiveFile = "Microsoft.Net6.NuGet.CredentialProvider.zip" +} +if ($InstallNet8 -eq $True) { + if ($releaseRidPart -like 'linux*') { + # For linux runtimes, only .tar.gz is available + $archiveFile = "Microsoft.Net8.${releaseRidPart}NuGet.CredentialProvider.tar.gz" + } + else { + $archiveFile = "Microsoft.Net8.${releaseRidPart}NuGet.CredentialProvider.zip" + } +} +if ($AddNetfx -eq $True) { + # This conditional must come last as two downloads occur when NetFx/Core are installed + $archiveFile = "Microsoft.NetFx48.NuGet.CredentialProvider.zip" +} + +Install-CredProvider # Remove existing content and copy netfx directories to plugins directory -if ($AddNetfx -eq $True -or $AddNetfx48 -eq $True) { +if ($AddNetfx -eq $True) { if ($netfxExists) { Write-Verbose "Removing existing content from $fullNetfxCredProviderPath" Remove-Item $fullNetfxCredProviderPath -Force -Recurse @@ -231,16 +286,20 @@ if ($AddNetfx -eq $True -or $AddNetfx48 -eq $True) { } # Microsoft.NuGet.CredentialProvider.zip that installs netfx provider installs .netcore3.1 version -# If InstallNet6 is also true we need to replace netcore cred provider with net6 +# Also install NET6/NET8 provider if requested if ($AddNetfx -eq $True -and $InstallNet6 -eq $True) { - $zipFile = "Microsoft.Net6.NuGet.CredentialProvider.zip" - Write-Verbose "Installing Net6" - InstallZip + $archiveFile = "Microsoft.Net6.NuGet.CredentialProvider.zip" + Install-CredProvider } if ($AddNetfx -eq $True -and $InstallNet8 -eq $True) { - $zipFile = "Microsoft.Net8.NuGet.CredentialProvider.zip" - Write-Verbose "Installing Net8" - InstallZip + if ($releaseRidPart -like 'linux*') { + # For linux runtimes, only .tar.gz is available + $archiveFile = "Microsoft.Net8.${releaseRidPart}NuGet.CredentialProvider.tar.gz" + } + else { + $archiveFile = "Microsoft.Net8.${releaseRidPart}NuGet.CredentialProvider.zip" + } + Install-CredProvider } # Remove existing content and copy netcore directories to plugins directory diff --git a/helpers/installcredprovider.sh b/helpers/installcredprovider.sh index c53505e6..dca29f9c 100755 --- a/helpers/installcredprovider.sh +++ b/helpers/installcredprovider.sh @@ -10,69 +10,113 @@ REPO="Microsoft/artifacts-credprovider" NUGET_PLUGIN_DIR="$HOME/.nuget/plugins" +VERSION_NORMALIZED=$(echo "${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION}" | sed 's/^v//') + +set_runtime_identifier() { + if [[ "$OSTYPE" == "linux-gnu"* ]]; then + RUNTIME_ID="linux" + elif [[ "$OSTYPE" == "darwin"* ]]; then + RUNTIME_ID="osx" + elif [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then + RUNTIME_ID="win" + else + echo "WARNING: Unable to automatically detect a supported OS from '$OSTYPE'. The .NET 8 version will be installed by default. Please set the ARTIFACTS_CREDENTIAL_PROVIDER_RID environment variable to specify a runtime version." >&2 + return "" + fi + + local arch=$(uname -m) + case "$arch" in + x86_64 | amd64) + OS_ARCH="-x64" + ;; + aarch64 | arm64) + OS_ARCH="-arm64" + ;; + *) + echo "WARNING: Unable to automatically detect a supported CPU architecture from '$arch'. The .NET 8 version will be installed by default. Please set the ARTIFACTS_CREDENTIAL_PROVIDER_RID environment variable to specify a runtime version." >&2 + return "" + ;; + esac + + # Windows on ARM64 runs x64 binaries (similar to PowerShell logic) + if [[ "$OS_ARCH" == "-arm64" && "$RUNTIME_ID" == "win" ]]; then + RUNTIME_ID="${RUNTIME_ID}-x64" + else + RUNTIME_ID="${RUNTIME_ID}${OS_ARCH}" + fi + + echo "INFO: Calculated artifacts-credprovider RuntimeIdentifier: $RUNTIME_ID" +} # If a RuntimeID (RID) is set, install the self-contained version of the .NET 8 credential provider. # To install a release with a specific runtime version set the `ARTIFACTS_CREDENTIAL_PROVIDER_RID` enviornment variable. if [ ! -z ${ARTIFACTS_CREDENTIAL_PROVIDER_RID} ]; then - echo "INFO: ARTIFACTS_CREDENTIAL_PROVIDER_RID variable set, defaulting to NET8 installation." + echo "INFO: ARTIFACTS_CREDENTIAL_PROVIDER_RID variable set, defaulting to self-contained installation." # If the RID is osx-*, use the zip file otherwise use the tar.gz file. - case ${ARTIFACTS_CREDENTIAL_PROVIDER_RID} in osx-* ) + case ${ARTIFACTS_CREDENTIAL_PROVIDER_RID} in osx-*) FILE="Microsoft.Net8.${ARTIFACTS_CREDENTIAL_PROVIDER_RID}.NuGet.CredentialProvider.zip" ;; - *) + *) FILE="Microsoft.Net8.${ARTIFACTS_CREDENTIAL_PROVIDER_RID}.NuGet.CredentialProvider.tar.gz" ;; esac if [ -z ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} ]; then - echo "WARNING: The USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER variable is set, but ARTIFACTS_CREDENTIAL_PROVIDER_RID variable is defined. The NET8 version of the credential provider will be installed." + echo "WARNING: The USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER variable is set, but ARTIFACTS_CREDENTIAL_PROVIDER_RID variable is defined. The self-contained version of the credential provider will be installed." fi - + # throw if version starts < 1.4.0. (self-contained not supported) - case ${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION} in - 0.*|v0.*|1.0.*|v1.0.*|1.1.*|v1.1.*|1.2.*|v1.2.*|1.3.*|v1.3.*) + case ${VERSION_NORMALIZED} in + 0.* | 1.0.* | 1.1.* | 1.2.* | 1.3.*) echo "ERROR: To install NET8 cred provider using the ARTIFACTS_CREDENTIAL_PROVIDER_RID variable, version to be installed must be 1.4.0 or greater. Check your AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION variable." exit 1 ;; esac +# .NET 6 is the legacy installation, attempt to install only when explicitly set. +elif [ ! -z ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} ] && [ ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} != "false" ] && [ ${USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER} != "true" ]; then + FILE="Microsoft.Net6.NuGet.CredentialProvider.tar.gz" + + # throw if version starts with 0. (net6 not supported) + case ${VERSION_NORMALIZED} in + 0.*) + echo "ERROR: To install .NET 6 cred provider using the USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER variable, version to be installed must be 1.0.0 or greater. Check your AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION variable." + exit 1 + ;; + esac +# The .NET 8 install is the default installation, attempt to install unless set to false. # If .NET 8 variable is set, install the .NET 8 version of the credential provider even if USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER is true. -elif [ ! -z ${USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER} ] && [ ${USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER} != "false" ]; then - # Default to the full zip file since ARTIFACTS_CREDENTIAL_PROVIDER_RID is not specified. - FILE="Microsoft.Net8.NuGet.CredentialProvider.tar.gz" +elif [ -z ${USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER} ] || [ ${USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER} != "false" ]; then + if [ ! -z ${ARTIFACTS_CREDENTIAL_PROVIDER_NON_SC} ] && [ ${ARTIFACTS_CREDENTIAL_PROVIDER_NON_SC} != "false" ]; then + # Default to the full zip file if ARTIFACTS_CREDENTIAL_PROVIDER_NON_SC is specified. + FILE="Microsoft.Net8.NuGet.CredentialProvider.tar.gz" + else + # Get the correct runtime identifier for the self-contained version. + set_runtime_identifier - if [ -z ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} ]; then - echo "WARNING: The USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER variable is set, but USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER variable is true. The NET8 version of the credential provider will be installed." + if [ ${RUNTIME_ID} == "osx-x64" ] || [ ${RUNTIME_ID} == "osx-arm64" ]; then + FILE="Microsoft.Net8.${RUNTIME_ID}.NuGet.CredentialProvider.zip" + else + FILE="Microsoft.Net8.${RUNTIME_ID}.NuGet.CredentialProvider.tar.gz" + fi fi # throw if version starts < 1.3.0. (net8 not supported) - case ${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION} in - 0.*|v0.*|1.0.*|v1.0.*|1.1.*|v1.1.*|1.2.*|v1.2.*) + case ${VERSION_NORMALIZED} in + 0.* | 1.0.* | 1.1.* | 1.2.*) echo "ERROR: To install NET8 cred provider using the USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER variable, version to be installed must be 1.3.0 or greater. Check your AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION variable." exit 1 ;; esac -# .NET 6 is the default installation, attempt to install unless set to false. -elif [ -z ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} ] || [ ${USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER} != "false" ]; then - FILE="Microsoft.Net6.NuGet.CredentialProvider.tar.gz" - - # throw if version starts with 0. (net6 not supported) - case ${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION} in - 0.*|v0.*) - echo "ERROR: To install NET6 cred provider using the USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER variable, version to be installed must be 1.0.0 or greater. Check your AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION variable." - exit 1 - ;; - esac -# If .NET 6 is disabled and .NET 8 isn't explicitly enabled, fall back to the legacy .NET Framework. +# If .NET 6 or .NET 8 isn't being downloaded, fall back to the .NET Framework 4.8.1 version. else - echo "WARNING: The .Net Framework 3.1 version of the Credential Provider is deprecated and will be removed in the next major release. Please migrate to the .Net Framework 4.8 or .Net Core versions." - FILE="Microsoft.NuGet.CredentialProvider.tar.gz" + FILE="Microsoft.NetFx48.NuGet.CredentialProvider.tar.gz" fi # If AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION is set, install the version specified, otherwise install latest -if [ ! -z ${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION} ] && [ ${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION} != "latest" ]; then +if [ ! -z ${VERSION_NORMALIZED} ] && [ ${VERSION_NORMALIZED} != "latest" ]; then # browser_download_url from https://api.github.com/repos/Microsoft/artifacts-credprovider/releases/latest - URI="https://github.com/$REPO/releases/download/${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION}/$FILE" + URI="https://github.com/$REPO/releases/download/v${VERSION_NORMALIZED}/$FILE" else # URL pattern to get latest documented at https://help.github.com/en/articles/linking-to-releases as of 2019-03-29 URI="https://github.com/$REPO/releases/latest/download/$FILE" @@ -82,21 +126,21 @@ fi if [ ! -d "${NUGET_PLUGIN_DIR}" ]; then echo "INFO: Creating the nuget plugin directory (i.e. ${NUGET_PLUGIN_DIR}). " if ! mkdir -p "${NUGET_PLUGIN_DIR}"; then - echo "ERROR: Unable to create nuget plugins directory (i.e. ${NUGET_PLUGIN_DIR})." - exit 1 + echo "ERROR: Unable to create nuget plugins directory (i.e. ${NUGET_PLUGIN_DIR})." + exit 1 fi fi -echo "Downloading from $URI" +echo "INFO: Downloading from $URI" # Extract netcore from the .tar.gz into the plugin directory -#Fetch the file +# Fetch the file if ! curl -H "Accept: application/octet-stream" \ - -s \ - -S \ - -L \ - "$URI" | tar xz -C "$HOME/.nuget/" "plugins/netcore"; then - exit 1 + -s \ + -S \ + -L \ + "$URI" | tar xz -C "$HOME/.nuget/" "plugins/netcore"; then + exit 1 fi -echo "INFO: credential provider netcore plugin extracted to $HOME/.nuget/" \ No newline at end of file +echo "INFO: credential provider netcore plugin extracted to $HOME/.nuget/" diff --git a/helpers/installcredproviderrelease.ps1 b/helpers/installcredproviderrelease.ps1 new file mode 100644 index 00000000..b94d081a --- /dev/null +++ b/helpers/installcredproviderrelease.ps1 @@ -0,0 +1,165 @@ +<# +.SYNOPSIS + Executes a versioned installation script of artifacts-credprovider from a GitHub release artifact. + +.DESCRIPTION + This script downloads a file from a GitHub artifacts-credprovider release artifact using the provided + version string and executes the downloaded script, allowing the install script parameters to be passed. + +.PARAMETER Version + The version string of the release (e.g., "1.4.1"). + +.EXAMPLE + .\installcredproviderrelease.ps1 -Version 1.3.0 -AddNetFx -Force" +#> + +[CmdletBinding(HelpUri = "https://github.com/microsoft/artifacts-credprovider/blob/master/README.md#setup")] +param( + [Parameter(Mandatory = $false)] + [string]$Version, + + [Parameter(Mandatory = $false, ValueFromRemainingArguments = $true)] + [string]$AdditionalParams +) + +$ErrorActionPreference = 'Stop' + +function Get-ReleaseUrl { + # Get the file base URL from the GitHub release + $releaseUrlBase = "https://api.github.com/repos/microsoft/artifacts-credprovider/releases" + $versionError = "Unable to find the release version $ReleaseVersion from $releaseUrlBase" + $releaseId = "latest" + if (![string]::IsNullOrEmpty($ReleaseVersion)) { + try { + $releases = Invoke-WebRequest -UseBasicParsing $releaseUrlBase + $releaseJson = $releases | ConvertFrom-Json + $correctReleaseVersion = $releaseJson | ? { $_.name -eq $ReleaseVersion } + $releaseId = $correctReleaseVersion.id + } + catch { + Write-Error $versionError + return + } + } + + if (!$releaseId) { + Write-Error $versionError + return + } + + $releaseUrl = [System.IO.Path]::Combine($releaseUrlBase, $releaseId) + return $releaseUrl.Replace("\", "/") +} + +# Version parameter validation +if ($Version) { + if ($Version -match '^[vV]') { + $Version = $Version.Substring(1) # Remove leading 'v' or 'V' + } + + if ($Version -notmatch '^\d+\.\d+\.\d+') { + Write-Error "Invalid version. Please use the format #.#.# to override the release version." + return + } +} + +# Construct the GitHub release URL +if ($Version -and ($Version.StartsWith("0.") -or $Version.StartsWith("1."))) { + # For versions 0.x and 1.0.x, use the last 1.x release URL without sha256 validation + # for backward compatibility + $ReleaseVersion = "1.4.1" + $releaseUrl = Get-ReleaseUrl +} +else { + $ReleaseVersion = $Version + $releaseUrl = Get-ReleaseUrl + $checksumUrl = "$releaseUrl/artifacts-credprovider-sha256.txt" +} + +$installScriptName = "installcredprovider.ps1" +try { + Write-Host "Fetching release $releaseUrl" + $release = Invoke-WebRequest -UseBasicParsing $releaseUrl + if (!$release) { + throw ("Unable to make Web Request to $releaseUrl") + } + $releaseJson = $release.Content | ConvertFrom-Json + if (!$releaseJson) { + throw ("Unable to get content from JSON") + } + $installAsset = $releaseJson.assets | ? { $_.name -eq $installScriptName } + if (!$installAsset) { + throw ("Unable to find asset $installScriptName from release JSON object") + } + $installUrl = $installAsset.browser_download_url + if (!$installUrl) { + throw ("Unable to find download url from asset $installAsset") + } +} +catch { + Write-Error ("Unable to resolve the browser download url from $releaseUrl `nError: " + $_.Exception.Message) + return +} + +# Build the parameters for the executed install script +$paramString = "" +if ($Version) { + $paramString += "-Version $Version " +} +if ($AdditionalParams) { + $paramString += $AdditionalParams +} + +# Fetch the checksum file and validate the hash +try { + if ($null -ne $checksumUrl) { + Write-Host "Fetching checksum file from $checksumUrl..." + $response = Invoke-WebRequest -Uri $checksumUrl -UseBasicParsing + $checksumContent = $response.Content + + # Extract the expected hash from the checksum content by splitting by newline and finding the entry for installcredprovider.ps1 + $checksumLines = $checksumContent -split '\r?\n' + $matchingLine = $checksumLines | Where-Object { $_ -match $installScriptName } + + if ($matchingLine) { + # Extract the hash from the matching line which are formatted as "filename hash" + $parts = $matchingLine -split '\s+' + $expectedHash = $parts[1] + } + else { + Write-Warning "Could not find hash for $installScriptName in artifacts-credprovider-sha256.txt. Proceeding without SHA256 validation." + } + } +} +catch { + Write-Warning "Failed to fetch or parse checksum file from $checksumUrl. Proceeding without SHA256 validation." + $expectedHash = $null +} + +try { + # Fetch the install file content + Write-Host "Fetching $installScriptName from $installUrl..." + $tempScriptLocation = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), $installScriptName); + try { + $client = New-Object System.Net.WebClient + $client.DownloadFile($installUrl, $tempScriptLocation) + } + catch { + Write-Error "Unable to download $packageSourceUrl to the location $pluginZip" + } + + if ($null -ne $expectedHash) { + $actualHash = (Get-FileHash -Path $tempScriptLocation -Algorithm SHA256).Hash + if ($actualHash.ToLower() -ne $expectedHash.ToLower()) { + throw "The downloaded $installScriptName hash does not match. `nExpected: $expectedHash, Actual: $actualHash" + } + } + + # Execute the script directly from the URL with additional parameters + Write-Host "Executing $installScriptName..." + $execCmd = "& { $($tempScriptLocation) $paramString }" + Invoke-Expression -Command $execCmd +} +catch { + Write-Error "Failed to fetch, validate, or execute artifacts-credprovider install. Error message: $_" +} diff --git a/helpers/installcredproviderrelease.sh b/helpers/installcredproviderrelease.sh new file mode 100755 index 00000000..184865cd --- /dev/null +++ b/helpers/installcredproviderrelease.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# DESCRIPTION: This script downloads a specific version of the installcredprovider.sh script +# from a GitHub release and executes it, handling validation of the script via checksum. +# Readme: https://github.com/Microsoft/artifacts-credprovider/blob/master/README.md + +# Use environment variables: +# To specify a version, set the AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION environment variable +# For runtime identifier, set ARTIFACTS_CREDENTIAL_PROVIDER_RID environment variable +# To use .NET 6, set USE_NET6_ARTIFACTS_CREDENTIAL_PROVIDER=true +# To use .NET 8, set USE_NET8_ARTIFACTS_CREDENTIAL_PROVIDER=true + +set -e + +# URL pattern to get latest documented at https://help.github.com/en/articles/linking-to-releases as of 2019-03-29 +INSTALL_SCRIPT="installcredprovider.sh" +RELEASE_BASE_URL="https://github.com/microsoft/artifacts-credprovider/releases" +RELEASE_LATEST_DOWNLOAD_URL="https://github.com/microsoft/artifacts-credprovider/releases/latest/download" + +# Process version - if not set, use latest +VERSION=$(echo "${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION}" | sed 's/^v//') +if [ -z "${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION}" ] || [ "${AZURE_ARTIFACTS_CREDENTIAL_PROVIDER_VERSION}" = "latest" ]; then + DOWNLOAD_URL="${RELEASE_LATEST_DOWNLOAD_URL}" + INSTALL_URL="${DOWNLOAD_URL}/${INSTALL_SCRIPT}" + echo "No version specified, using latest release." +else + # Validate version format + if ! [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*)?$ ]]; then + echo "ERROR: Invalid version format. Please use format #.#.# (e.g., 1.4.1)" + exit 1 + fi + + # For versions 0.x and 1.x, use the last published 1.x version for backward compatibility + if [[ "${VERSION}" == 0.* ]] || [[ "${VERSION}" == 1.* ]]; then + echo "INFO: Using version 1.4.1 for installation script as the minimum supported version" + VERSION="1.4.1" + fi + + # Attach 'v' prefix since it was removed during normalization + TAG_VERSION="v${VERSION}" + + echo "Fetching tagged release: ${TAG_VERSION}" + DOWNLOAD_URL="${RELEASE_BASE_URL}/download/${TAG_VERSION}" + INSTALL_URL="${DOWNLOAD_URL}/${INSTALL_SCRIPT}" +fi + +echo "Fetching versioned release install script at: ${INSTALL_URL}" + +# Download and validate the script content +echo "Fetching install script from ${INSTALL_URL}" + +# Get the script content without writing to disk +SCRIPT_CONTENT=$(curl -s -S -L "${INSTALL_URL}") +if [ -z "${SCRIPT_CONTENT}" ]; then + echo "ERROR: Failed to download install script content" + exit 1 +fi + +# Check if we need to validate with checksum +SHOULD_VALIDATE=true +if [[ "${VERSION}" == 0.* ]] || [[ "${VERSION}" == 1.* ]]; then + SHOULD_VALIDATE=false + echo "Skipping checksum validation for version ${VERSION} as it is not available for 0.x and 1.x versions." +else + CHECKSUM_URL="${DOWNLOAD_URL}/artifacts-credprovider-sha256.txt" +fi + +# Validate the script if checksum is available +if [ "${SHOULD_VALIDATE}" = true ] && [ ! -z "${CHECKSUM_URL}" ]; then + echo "Validating script content with SHA256 checksum" + + # Download the checksum file content directly into memory + echo "Fetching checksum file from ${CHECKSUM_URL}..." + CHECKSUM_CONTENT=$(curl -s -S -L "${CHECKSUM_URL}") + if [ -z "${CHECKSUM_CONTENT}" ]; then + echo "ERROR: Failed to download checksum file" + exit 1 + fi + + # Extract expected hash for the install script + # Normalize the content to handle different formats + NORMALIZED_CHECKSUM_CONTENT=$(echo "${CHECKSUM_CONTENT}" | tr -d '\r') + EXPECTED_HASH=$(echo "${NORMALIZED_CHECKSUM_CONTENT}" | grep "${INSTALL_SCRIPT}" | awk '{print $1}') + if [ -z "${EXPECTED_HASH}" ]; then + echo "WARNING: Could not find hash for ${INSTALL_SCRIPT} in checksum file, proceeding without validation" + else + # Calculate actual hash from the script content + if command -v shasum >/dev/null 2>&1; then + ACTUAL_HASH=$(echo "${SCRIPT_CONTENT}" | shasum -a 256 | awk '{print $1}') + elif command -v sha256sum >/dev/null 2>&1; then + ACTUAL_HASH=$(echo "${SCRIPT_CONTENT}" | sha256sum | awk '{print $1}') + else + echo "WARNING: No SHA256 utility available, skipping validation" + ACTUAL_HASH="" + fi + + # Compare hashes + if [ ! -z "${ACTUAL_HASH}" ] && [ "${ACTUAL_HASH}" != "${EXPECTED_HASH}" ]; then + echo "ERROR: SHA256 checksum validation failed!" + echo "Expected: ${EXPECTED_HASH}" + echo "Actual: ${ACTUAL_HASH}" + exit 1 + fi + fi +fi + +# Execute the script content directly +echo "Executing install script..." + +RESULT=0 +eval "${SCRIPT_CONTENT}" +RESULT=$? + +echo "Installation completed with exit code: ${RESULT}" +exit ${RESULT} diff --git a/test.bat b/test.bat index ef18b830..ae4bd460 100644 --- a/test.bat +++ b/test.bat @@ -61,7 +61,7 @@ exit /b 0 :TEST_FRAMEWORKS REM %1 = envtype (legacy/new), %2 = broker (true/false) -for %%I in ("netcoreapp3.1","net461","net481","net6.0","net8.0") DO ( +for %%I in ("net481","net6.0","net8.0") DO ( del /q "!UserProfile!\AppData\Local\MicrosoftCredentialProvider\*.dat" 2>NUL if "%1"=="legacy" del /q "%NUGET_CREDENTIALPROVIDER_MSAL_FILECACHE_LOCATION%" 2>NUL if "%1"=="new" del /q "%ARTIFACTS_CREDENTIALPROVIDER_MSAL_FILECACHE_LOCATION%" 2>NUL