diff --git a/eng/common/sdl/sdl.ps1 b/eng/common/sdl/sdl.ps1 new file mode 100644 index 00000000000..648c5068d7d --- /dev/null +++ b/eng/common/sdl/sdl.ps1 @@ -0,0 +1,38 @@ + +function Install-Gdn { + param( + [Parameter(Mandatory=$true)] + [string]$Path, + + # If omitted, install the latest version of Guardian, otherwise install that specific version. + [string]$Version + ) + + $ErrorActionPreference = 'Stop' + Set-StrictMode -Version 2.0 + $disableConfigureToolsetImport = $true + $global:LASTEXITCODE = 0 + + # `tools.ps1` checks $ci to perform some actions. Since the SDL + # scripts don't necessarily execute in the same agent that run the + # build.ps1/sh script this variable isn't automatically set. + $ci = $true + . $PSScriptRoot\..\tools.ps1 + + $argumentList = @("install", "Microsoft.Guardian.Cli", "-Source https://securitytools.pkgs.visualstudio.com/_packaging/Guardian/nuget/v3/index.json", "-OutputDirectory $Path", "-NonInteractive", "-NoCache") + + if ($Version) { + $argumentList += "-Version $Version" + } + + Start-Process nuget -Verbose -ArgumentList $argumentList -NoNewWindow -Wait + + $gdnCliPath = Get-ChildItem -Filter guardian.cmd -Recurse -Path $Path + + if (!$gdnCliPath) + { + Write-PipelineTelemetryError -Category 'Sdl' -Message 'Failure installing Guardian' + } + + return $gdnCliPath.FullName +} \ No newline at end of file diff --git a/eng/common/templates/steps/execute-sdl.yml b/eng/common/templates/steps/execute-sdl.yml index 7b8ee18a28d..9dd5709f66d 100644 --- a/eng/common/templates/steps/execute-sdl.yml +++ b/eng/common/templates/steps/execute-sdl.yml @@ -8,29 +8,28 @@ parameters: condition: '' steps: -- ${{ if ne(parameters.overrideGuardianVersion, '') }}: - - powershell: | - $content = Get-Content $(GuardianPackagesConfigFile) - - Write-Host "packages.config content was:`n$content" - - $content = $content.Replace('$(DefaultGuardianVersion)', '$(GuardianVersion)') - $content | Set-Content $(GuardianPackagesConfigFile) - - Write-Host "packages.config content updated to:`n$content" - displayName: Use overridden Guardian version ${{ parameters.overrideGuardianVersion }} +- task: NuGetAuthenticate@1 + inputs: + nuGetServiceConnections: GuardianConnect - task: NuGetToolInstaller@1 displayName: 'Install NuGet.exe' -- task: NuGetCommand@2 - displayName: 'Install Guardian' - inputs: - restoreSolution: $(Build.SourcesDirectory)\eng\common\sdl\packages.config - feedsToUse: config - nugetConfigPath: $(Build.SourcesDirectory)\eng\common\sdl\NuGet.config - externalFeedCredentials: GuardianConnect - restoreDirectory: $(Build.SourcesDirectory)\.packages +- ${{ if ne(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts -Version ${{ parameters.overrideGuardianVersion }} + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian (Overridden) + +- ${{ if eq(parameters.overrideGuardianVersion, '') }}: + - pwsh: | + Set-Location -Path $(Build.SourcesDirectory)\eng\common\sdl + . .\sdl.ps1 + $guardianCliLocation = Install-Gdn -Path $(Build.SourcesDirectory)\.artifacts + Write-Host "##vso[task.setvariable variable=GuardianCliLocation]$guardianCliLocation" + displayName: Install Guardian - ${{ if ne(parameters.overrideParameters, '') }}: - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} @@ -40,7 +39,7 @@ steps: - ${{ if eq(parameters.overrideParameters, '') }}: - powershell: ${{ parameters.executeAllSdlToolsScript }} - -GuardianPackageName Microsoft.Guardian.Cli.$(GuardianVersion) + -GuardianCliLocation $(GuardianCliLocation) -NugetPackageDirectory $(Build.SourcesDirectory)\.packages -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) ${{ parameters.additionalParameters }} @@ -62,7 +61,28 @@ steps: c i condition: succeededOrFailed() + - publish: $(Agent.BuildDirectory)/.gdn artifact: GuardianConfiguration displayName: Publish GuardianConfiguration + condition: succeededOrFailed() + + # Publish the SARIF files in a container named CodeAnalysisLogs to enable integration + # with the "SARIF SAST Scans Tab" Azure DevOps extension + - task: CopyFiles@2 + displayName: Copy SARIF files + inputs: + flattenFolders: true + sourceFolder: $(Agent.BuildDirectory)/.gdn/rc/ + contents: '**/*.sarif' + targetFolder: $(Build.SourcesDirectory)/CodeAnalysisLogs + condition: succeededOrFailed() + + # Use PublishBuildArtifacts because the SARIF extension only checks this case + # see microsoft/sarif-azuredevops-extension#4 + - task: PublishBuildArtifacts@1 + displayName: Publish SARIF files to CodeAnalysisLogs container + inputs: + pathToPublish: $(Build.SourcesDirectory)/CodeAnalysisLogs + artifactName: CodeAnalysisLogs condition: succeededOrFailed() \ No newline at end of file diff --git a/global.json b/global.json index ad8e2ac7b4d..483d0f8d032 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "6.0.110" + "dotnet": "6.0.111" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21620.3", diff --git a/src/Microsoft.DotNet.Arcade.Sdk/src/DownloadFile.cs b/src/Microsoft.DotNet.Arcade.Sdk/src/DownloadFile.cs index 3c8f19e9aca..ef697ada2e2 100644 --- a/src/Microsoft.DotNet.Arcade.Sdk/src/DownloadFile.cs +++ b/src/Microsoft.DotNet.Arcade.Sdk/src/DownloadFile.cs @@ -160,7 +160,13 @@ private async Tasks.Task DownloadWithRetriesAsync(HttpClient httpClient, s return true; } - catch (Exception e) when (e is HttpRequestException || e is IOException && !(e is DirectoryNotFoundException || e is PathTooLongException)) + // Retry cases: + // 1. Plain Http error + // 2. IOExceptions that aren't definitely deterministic (such as antivirus was scanning the file) + // 3. HttpClient Timeouts - these surface as TaskCanceledExceptions that don't match our cancellation token source + catch (Exception e) when (e is HttpRequestException || + e is IOException && !(e is DirectoryNotFoundException || e is PathTooLongException) || + e is Tasks.TaskCanceledException && ((Tasks.TaskCanceledException)e).CancellationToken != _cancellationSource.Token) { attempt++; diff --git a/src/Microsoft.DotNet.Build.Tasks.Workloads/src/Swix/MsiSwixProject.wix.cs b/src/Microsoft.DotNet.Build.Tasks.Workloads/src/Swix/MsiSwixProject.wix.cs index 02fae6cfcc0..fb0653c602c 100644 --- a/src/Microsoft.DotNet.Build.Tasks.Workloads/src/Swix/MsiSwixProject.wix.cs +++ b/src/Microsoft.DotNet.Build.Tasks.Workloads/src/Swix/MsiSwixProject.wix.cs @@ -87,7 +87,7 @@ public MsiSwixProject(ITaskItem msi, string baseIntermediateOutputPath, string b // For drop publishing all the JSON manifests and payloads must reside in the same folder so we shorten the project names // and use a hashed filename to avoid path too long errors. string hashInputs = $"{Id},{Version.ToString(3)},{sdkFeatureBand},{Platform},{Chip},{machineArch}"; - ProjectFile = $"{Utils.GetHash(hashInputs, HashAlgorithmName.MD5)}.swixproj"; + ProjectFile = $"{Utils.GetHash(hashInputs, HashAlgorithmName.MD5)}.swixproj"; // lgtm [cs/weak-crypto] Hash algorithm used only for determining file uniqueness ReplacementTokens[SwixTokens.__VS_PAYLOAD_SOURCE__] = msi.GetMetadata(Metadata.FullPath); } diff --git a/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs b/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs index 3d135e6c267..3c154714418 100644 --- a/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs +++ b/src/Microsoft.DotNet.Helix/Sdk/FindDotNetCliPackage.cs @@ -64,7 +64,7 @@ public override void ConfigureServices(IServiceCollection collection) public bool ExecuteTask(HttpMessageHandler httpMessageHandler) { _httpMessageHandler = httpMessageHandler; - _client = new HttpClient(_httpMessageHandler); + _client = new HttpClient(_httpMessageHandler); // lgtm [cs/httpclient-checkcertrevlist-disabled] False positive; see above in ConfigureServices(); this is always created with CheckCertificateRevocationList = true FindCliPackage().GetAwaiter().GetResult(); return !Log.HasLoggedErrors; }