diff --git a/eng/ManualVersions.props b/eng/ManualVersions.props index fb41f0bad..57a4b6415 100644 --- a/eng/ManualVersions.props +++ b/eng/ManualVersions.props @@ -9,11 +9,11 @@ Basically: In this file, choose the highest version when resolving merge conflicts. --> - 10.0.17763.29 - 10.0.18362.29 - 10.0.19041.29 - 10.0.20348.29 - 10.0.22000.29 - 10.0.22621.29 + 10.0.17763.31 + 10.0.18362.31 + 10.0.19041.31 + 10.0.20348.31 + 10.0.22000.31 + 10.0.22621.31 diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 6c4ac6fec..91f8196cc 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -64,7 +64,7 @@ try { $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty } if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { - $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.6.0-2" -MemberType NoteProperty + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "17.7.2-1" -MemberType NoteProperty } if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") { $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index aa74ab4a8..84cfe7cd9 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -379,13 +379,13 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = } # Minimum VS version to require. - $vsMinVersionReqdStr = '17.6' + $vsMinVersionReqdStr = '17.7' $vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr) # If the version of msbuild is going to be xcopied, # use this version. Version matches a package here: - # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/RoslynTools.MSBuild/versions/17.6.0-2 - $defaultXCopyMSBuildVersion = '17.6.0-2' + # https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-eng/NuGet/RoslynTools.MSBuild/versions/17.7.2-1 + $defaultXCopyMSBuildVersion = '17.7.2-1' if (!$vsRequirements) { if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') { diff --git a/eng/install-scancode.sh b/eng/install-scancode.sh new file mode 100755 index 000000000..9b705f624 --- /dev/null +++ b/eng/install-scancode.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -euo pipefail + +# https://scancode-toolkit.readthedocs.io/en/latest/getting-started/install.html#installation-as-a-library-via-pip + +pyEnvPath="/tmp/scancode-env" +python3 -m venv $pyEnvPath +source $pyEnvPath/bin/activate +pip install scancode-toolkit +deactivate + +# Setup a script which executes scancode in the virtual environment +cat > /usr/local/bin/scancode << EOF +#!/bin/bash +set -euo pipefail +source $pyEnvPath/bin/activate +scancode "\$@" +deactivate +EOF + +chmod +x /usr/local/bin/scancode diff --git a/eng/pipelines/source-build-license-scan.yml b/eng/pipelines/source-build-license-scan.yml new file mode 100644 index 000000000..bcf7e84f1 --- /dev/null +++ b/eng/pipelines/source-build-license-scan.yml @@ -0,0 +1,137 @@ +# Pipeline documentation at https://github.com/dotnet/dotnet/blob/main/docs/license-scanning.md + +schedules: +- cron: "0 7 * * 1-5" + displayName: Run on weekdays at 7am UTC + branches: + include: + - main + - release/* + +pr: none +trigger: none + +parameters: +# Provides a way to scan a specific repo. If not provided, all repos of the VMR will be scanned. +- name: specificRepoName + type: string + displayName: "Specific repo name to scan (e.g. runtime, sdk). If empty, scans all repos of the VMR." + default: " " # Set it to an empty string to allow it be an optional parameter + +variables: + installerRoot: '$(Build.SourcesDirectory)/src/installer' + +jobs: +- job: Setup + pool: + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals 1es-ubuntu-2004 + steps: + - script: | + vmrSrcDir="$(Build.SourcesDirectory)/src" + + # Builds an Azure DevOps matrix definition. Each entry in the matrix is a path, + # allowing a job to be run for each src repo. + matrix="" + + # Trim leading/trailing spaces from the repo name + specificRepoName=$(echo "${{ parameters.specificRepoName }}" | awk '{$1=$1};1') + + # If the repo name is provided, only scan that repo. + if [ ! -z "$specificRepoName" ]; then + matrix="\"$specificRepoName\": { \"repoPath\": \"$vmrSrcDir/$specificRepoName\" }" + else + for dir in $vmrSrcDir/*/ + do + if [ ! -z "$matrix" ]; then + matrix="$matrix," + fi + repoName=$(basename $dir) + matrix="$matrix \"$repoName\": { \"repoPath\": \"$dir\" }" + done + fi + + matrix="{ $matrix }" + + echo "##vso[task.setvariable variable=matrix;isOutput=true]$matrix" + name: GetMatrix + displayName: Get Matrix + +- job: LicenseScan + dependsOn: Setup + pool: + name: NetCore1ESPool-Svc-Internal + demands: ImageOverride -equals 1es-ubuntu-2004 + timeoutInMinutes: 420 + strategy: + matrix: $[ dependencies.Setup.outputs['GetMatrix.matrix'] ] + steps: + + - script: $(Build.SourcesDirectory)/prep.sh --no-artifacts --no-bootstrap --no-prebuilts + displayName: 'Install .NET SDK' + + - task: PipAuthenticate@1 + displayName: 'Pip Authenticate' + inputs: + artifactFeeds: public/dotnet-public-pypi + onlyAddExtraIndex: false + + - script: $(installerRoot)/eng/install-scancode.sh + displayName: Install Scancode + + - script: > + $(Build.SourcesDirectory)/.dotnet/dotnet test + $(Build.SourcesDirectory)/test/Microsoft.DotNet.SourceBuild.SmokeTests/Microsoft.DotNet.SourceBuild.SmokeTests.csproj + --filter "FullyQualifiedName=Microsoft.DotNet.SourceBuild.SmokeTests.LicenseScanTests.ScanForLicenses" + --logger:'trx;LogFileName=$(Agent.JobName)_LicenseScan.trx' + --logger:'console;verbosity=detailed' + -c Release + -bl:$(Build.SourcesDirectory)/artifacts/log/Debug/BuildTests_$(date +"%m%d%H%M%S").binlog + -flp:LogFile=$(Build.SourcesDirectory)/artifacts/logs/BuildTests_$(date +"%m%d%H%M%S").log + -clp:v=m + -e SMOKE_TESTS_LICENSE_SCAN_PATH=$(repoPath) + -e SMOKE_TESTS_RUNNING_IN_CI=true + -e SMOKE_TESTS_WARN_LICENSE_SCAN_DIFFS=false + -e SMOKE_TESTS_TARGET_RID=linux-x64 + -e SMOKE_TESTS_PORTABLE_RID=linux-x64 + displayName: Run Tests + workingDirectory: $(Build.SourcesDirectory) + + - script: | + set -x + targetFolder=$(Build.StagingDirectory)/BuildLogs/ + mkdir -p ${targetFolder} + cd "$(Build.SourcesDirectory)" + find artifacts/ -type f -name "BuildTests*.binlog" -exec cp {} --parents -t ${targetFolder} \; + find artifacts/ -type f -name "BuildTests*.log" -exec cp {} --parents -t ${targetFolder} \; + echo "Updated:" + find test/ -type f -name "Updated*.json" + find test/ -type f -name "Updated*.json" -exec cp {} --parents -t ${targetFolder} \; + echo "Results:" + find test/ -type f -name "scancode-results*.json" + find test/ -type f -name "scancode-results*.json" -exec cp {} --parents -t ${targetFolder} \; + echo "All:" + ls -R test/ + echo "BuildLogs:" + ls -R ${targetFolder} + displayName: Prepare BuildLogs staging directory + continueOnError: true + condition: succeededOrFailed() + + - publish: '$(Build.StagingDirectory)/BuildLogs' + artifact: $(Agent.JobName)_BuildLogs_Attempt$(System.JobAttempt) + displayName: Publish BuildLogs + continueOnError: true + condition: succeededOrFailed() + + - task: PublishTestResults@2 + displayName: Publish Test Results + condition: succeededOrFailed() + continueOnError: true + inputs: + testRunner: vSTest + testResultsFiles: '*.trx' + searchFolder: $(Build.SourcesDirectory)/test/Microsoft.DotNet.SourceBuild.SmokeTests/TestResults + mergeTestResults: true + publishRunAttachments: true + testRunTitle: $(Agent.JobName) diff --git a/eng/pipelines/templates/jobs/vmr-build.yml b/eng/pipelines/templates/jobs/vmr-build.yml index f11af8c4b..041a47580 100644 --- a/eng/pipelines/templates/jobs/vmr-build.yml +++ b/eng/pipelines/templates/jobs/vmr-build.yml @@ -127,7 +127,7 @@ jobs: artifact: ${{ parameters.reuseBuildArtifactsFrom }}_${{ parameters.architecture }}_Artifacts patterns: | **/Private.SourceBuilt.Artifacts.*.tar.gz - **/dotnet-sdk-+([0-9]).+([0-9]).+([0-9])*.tar.gz + **/dotnet-sdk-*.tar.gz displayName: Download Previous Build - task: CopyFiles@2 diff --git a/eng/pipelines/vmr-sync-internal.yml b/eng/pipelines/vmr-sync-internal.yml index 176f98910..0a10a518e 100644 --- a/eng/pipelines/vmr-sync-internal.yml +++ b/eng/pipelines/vmr-sync-internal.yml @@ -5,6 +5,10 @@ trigger: branches: include: - internal/release/* + exclude: + - internal/release/*.0.2xx + - internal/release/*.0.3xx + - internal/release/*.0.4xx resources: repositories: diff --git a/eng/pipelines/vmr-sync.yml b/eng/pipelines/vmr-sync.yml index aa12adcbe..6659887f1 100644 --- a/eng/pipelines/vmr-sync.yml +++ b/eng/pipelines/vmr-sync.yml @@ -6,6 +6,10 @@ trigger: include: - main - release/* + exclude: + - release/*.0.2xx + - release/*.0.3xx + - release/*.0.4xx resources: repositories: diff --git a/src/SourceBuild/content/build.proj b/src/SourceBuild/content/build.proj index 6b67024d0..193bbd6f0 100644 --- a/src/SourceBuild/content/build.proj +++ b/src/SourceBuild/content/build.proj @@ -92,7 +92,7 @@ DiscoverSymbolsTarballs; ExtractSymbolsTarballs"> - $(OutputPath)dotnet-symbols-$(MicrosoftSourceBuildIntermediateInstallerVersion)-$(TargetRid).tar.gz + $(OutputPath)dotnet-symbols-all-$(MicrosoftSourceBuildIntermediateInstallerVersion)-$(TargetRid).tar.gz - + $(ArtifactsTmpDir)SdkSymbols - $(OutputPath)dotnet-sdk-symbols-$(MicrosoftSourceBuildIntermediateInstallerVersion)-$(TargetRid).tar.gz + $(OutputPath)dotnet-symbols-sdk-$(MicrosoftSourceBuildIntermediateInstallerVersion)-$(TargetRid).tar.gz $(ArtifactsTmpDir)Sdk %(SdkTarballItem.Identity) @@ -183,8 +182,7 @@ - + diff --git a/src/SourceBuild/content/docs/license-scanning.md b/src/SourceBuild/content/docs/license-scanning.md new file mode 100644 index 000000000..6007776ab --- /dev/null +++ b/src/SourceBuild/content/docs/license-scanning.md @@ -0,0 +1,24 @@ +# License Scanning + +The VMR is regularly scanned for license references to ensure that only open-source license are used where relevant. + +License scanning pipline: https://dev.azure.com/dnceng/internal/_build?definitionId=1301 (internal only) + +License scanning test: https://github.com/dotnet/dotnet/blob/main/test/Microsoft.DotNet.SourceBuild.SmokeTests/LicenseScanTests.cs + +By default, running the pipeline will scan all repos within the VMR which takes several hours to run. +The pipeline can be triggered manually to target a specific repo within the VMR by setting the `specificRepoName` parameter. +This value should be the name of the repo within the VMR (i.e. a name of a directory within https://github.com/dotnet/dotnet/tree/main/src). +To test source modifications intended to resolve a license issue, apply the change in an internal branch of the VMR. +Run this pipeline, targeting your branch, and set the `specificRepoName` parameter to the name of the repo containing the change. + +The output of the pipeline is a set of test results and logs. +The logs are published as an artifact and can be found at test/Microsoft.DotNet/SourceBuild.SmokeTests/bin/Release/netX.0/logs. +It consists of the following: + * `UpdatedLicenses..json`: This is the output of that gets compared to the stored baseline. + If they're the same, the test passes; if not, it fails. By comparing this file to the baseline, one can determine which new license + references have been introduced. + If everything is deemed to be acceptable, the developer can either update the allowed licenses, update the exclusions file, update the + baseline, or any combination. + * `scancode-results.json`: This is the raw output that comes from scancode. This file is useful for diagnostic purposes because it tells you + the exact line number of where a license has been detected in a file. diff --git a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs index 270fb11f9..32abcae71 100644 --- a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs +++ b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs @@ -155,6 +155,7 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection } File.Delete(p.ItemSpec); File.Move(poisonedPackagePath, p.ItemSpec); + Directory.Delete(packageTempPath, true); } } diff --git a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/CreateSdkSymbolsLayout.cs b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/CreateSdkSymbolsLayout.cs index 8802dd543..7e00bbf30 100644 --- a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/CreateSdkSymbolsLayout.cs +++ b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.XPlat/CreateSdkSymbolsLayout.cs @@ -57,7 +57,7 @@ namespace Microsoft.DotNet.Build.Tasks private void LogErrorOrWarning(bool isError, string message) { - if (FailOnMissingPDBs) + if (isError) { Log.LogError(message); } @@ -104,14 +104,15 @@ namespace Microsoft.DotNet.Build.Tasks if (guid != string.Empty) { - if (!allPdbGuids.ContainsKey(guid)) + string debugId = GetDebugId(guid, file); + if (!allPdbGuids.ContainsKey(debugId)) { filesWithoutPDBs.Add(file.Substring(SdkLayoutPath.Length + 1)); } else { // Copy matching pdb to symbols path, preserving sdk binary's hierarchy - string sourcePath = (string)allPdbGuids[guid]!; + string sourcePath = (string)allPdbGuids[debugId]!; string destinationPath = file.Replace(SdkLayoutPath, SdkSymbolsLayoutPath) .Replace(Path.GetFileName(file), Path.GetFileName(sourcePath)); @@ -142,13 +143,21 @@ namespace Microsoft.DotNet.Build.Tasks var id = new BlobContentId(metadataReader.DebugMetadataHeader.Id); string guid = $"{id.Guid:N}"; - if (!string.IsNullOrEmpty(guid) && !allPdbGuids.ContainsKey(guid)) + string debugId = GetDebugId(guid, file); + if (!string.IsNullOrEmpty(guid) && !allPdbGuids.ContainsKey(debugId)) { - allPdbGuids.Add(guid, file); + allPdbGuids.Add(debugId, file); } } return allPdbGuids; } + + /// + /// Calculates a debug Id from debug guid and filename. We use this as a key + /// in PDB hashtable. Guid is not enough due to collisions in several PDBs. + /// + private string GetDebugId(string guid, string file) => + $"{guid}.{Path.GetFileNameWithoutExtension(file)}".ToLower(); } } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BaselineHelper.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BaselineHelper.cs index b8426c2a3..49ee98d73 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BaselineHelper.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BaselineHelper.cs @@ -41,12 +41,12 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests Assert.Null(message); } - public static void CompareBaselineContents(string baselineFileName, string actualContents, ITestOutputHelper outputHelper, bool warnOnDiffs = false) + public static void CompareBaselineContents(string baselineFileName, string actualContents, ITestOutputHelper outputHelper, bool warnOnDiffs = false, string baselineSubDir = "") { - string actualFilePath = Path.Combine(DotNetHelper.LogsDirectory, $"Updated{baselineFileName}"); + string actualFilePath = Path.Combine(TestBase.LogsDirectory, $"Updated{baselineFileName}"); File.WriteAllText(actualFilePath, actualContents); - CompareFiles(GetBaselineFilePath(baselineFileName), actualFilePath, outputHelper, warnOnDiffs); + CompareFiles(GetBaselineFilePath(baselineFileName, baselineSubDir), actualFilePath, outputHelper, warnOnDiffs); } public static void CompareFiles(string expectedFilePath, string actualFilePath, ITestOutputHelper outputHelper, bool warnOnDiffs = false) @@ -87,7 +87,8 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests public static string GetAssetsDirectory() => Path.Combine(Directory.GetCurrentDirectory(), "assets"); - public static string GetBaselineFilePath(string baselineFileName) => Path.Combine(GetAssetsDirectory(), "baselines", baselineFileName); + public static string GetBaselineFilePath(string baselineFileName, string baselineSubDir = "") => + Path.Combine(GetAssetsDirectory(), "baselines", baselineSubDir, baselineFileName); public static string RemoveNetTfmPaths(string source) { diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BasicScenarioTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BasicScenarioTests.cs index 4f1aafc68..d2280add4 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BasicScenarioTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/BasicScenarioTests.cs @@ -15,7 +15,7 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests; /// for related web scenarios. /// They are encapsulated in a separate testclass so that they can be run in parallel. /// -public class BasicScenarioTests : SmokeTests +public class BasicScenarioTests : SdkTests { public BasicScenarioTests(ITestOutputHelper outputHelper) : base(outputHelper) { } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Config.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Config.cs index 85dd0eae3..8a3c6ce73 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Config.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Config.cs @@ -20,7 +20,9 @@ internal static class Config public const string SourceBuiltArtifactsPathEnv = "SMOKE_TESTS_SOURCEBUILT_ARTIFACTS_PATH"; public const string TargetRidEnv = "SMOKE_TESTS_TARGET_RID"; public const string WarnSdkContentDiffsEnv = "SMOKE_TESTS_WARN_SDK_CONTENT_DIFFS"; + public const string WarnLicenseScanDiffsEnv = "SMOKE_TESTS_WARN_LICENSE_SCAN_DIFFS"; public const string RunningInCIEnv = "SMOKE_TESTS_RUNNING_IN_CI"; + public const string LicenseScanPathEnv = "SMOKE_TESTS_LICENSE_SCAN_PATH"; public static string DotNetDirectory { get; } = Environment.GetEnvironmentVariable(DotNetDirectoryEnv) ?? Path.Combine(Directory.GetCurrentDirectory(), ".dotnet"); @@ -31,15 +33,18 @@ internal static class Config public static string? PrereqsPath { get; } = Environment.GetEnvironmentVariable(PrereqsPathEnv); public static string? CustomPackagesPath { get; } = Environment.GetEnvironmentVariable(CustomPackagesPathEnv); public static string? SdkTarballPath { get; } = Environment.GetEnvironmentVariable(SdkTarballPathEnv); - public static string SourceBuiltArtifactsPath { get; } = Environment.GetEnvironmentVariable(SourceBuiltArtifactsPathEnv) ?? - throw new InvalidOperationException($"'{Config.SourceBuiltArtifactsPathEnv}' must be specified"); + public static string? SourceBuiltArtifactsPath { get; } = Environment.GetEnvironmentVariable(SourceBuiltArtifactsPathEnv); public static string TargetRid { get; } = Environment.GetEnvironmentVariable(TargetRidEnv) ?? throw new InvalidOperationException($"'{Config.TargetRidEnv}' must be specified"); public static string TargetArchitecture { get; } = TargetRid.Split('-')[1]; public static bool WarnOnSdkContentDiffs { get; } = bool.TryParse(Environment.GetEnvironmentVariable(WarnSdkContentDiffsEnv), out bool warnOnSdkContentDiffs) && warnOnSdkContentDiffs; + public static bool WarnOnLicenseScanDiffs { get; } = + bool.TryParse(Environment.GetEnvironmentVariable(WarnLicenseScanDiffsEnv), out bool warnOnLicenseScanDiffs) && warnOnLicenseScanDiffs; // Indicates whether the tests are being run in the context of a CI pipeline public static bool RunningInCI { get; } = bool.TryParse(Environment.GetEnvironmentVariable(RunningInCIEnv), out bool runningInCI) && runningInCI; + + public static string? LicenseScanPath { get; } = Environment.GetEnvironmentVariable(LicenseScanPathEnv); } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DebugTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DebugTests.cs index 939339207..c556b0e90 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DebugTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DebugTests.cs @@ -12,7 +12,7 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; -public class DebugTests : SmokeTests +public class DebugTests : SdkTests { private record ScanResult(string FileName, bool HasDebugInfo, bool HasDebugAbbrevs, bool HasFileSymbols, bool HasGnuDebugLink); diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetFormatTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetFormatTests.cs index 86c6f2650..4ec0ad325 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetFormatTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetFormatTests.cs @@ -8,7 +8,7 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; -public class DotNetFormatTests : SmokeTests +public class DotNetFormatTests : SdkTests { private const string TestFileName = "FormatTest.cs"; private const string UnformattedFileName = "FormatTestUnformatted.cs"; diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs index 7c1a8673c..f35440d4c 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetHelper.cs @@ -3,14 +3,12 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; -using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; @@ -21,7 +19,6 @@ internal class DotNetHelper private static readonly object s_lockObj = new(); public static string DotNetPath { get; } = Path.Combine(Config.DotNetDirectory, "dotnet"); - public static string LogsDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "logs"); public static string PackagesDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "packages"); public static string ProjectsDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), $"projects-{DateTime.Now:yyyyMMddHHmmssffff}"); @@ -56,11 +53,6 @@ internal class DotNetHelper { Directory.CreateDirectory(PackagesDirectory); } - - if (!Directory.Exists(LogsDirectory)) - { - Directory.CreateDirectory(LogsDirectory); - } } } @@ -261,7 +253,7 @@ internal class DotNetHelper fileName += $"-{differentiator}"; } - return $"/bl:{Path.Combine(LogsDirectory, $"{fileName}.binlog")}"; + return $"/bl:{Path.Combine(TestBase.LogsDirectory, $"{fileName}.binlog")}"; } private static bool DetermineIsMonoRuntime(string dotnetRoot) diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs index a65f6d7e0..e30909a9b 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/DotNetWatchTests.cs @@ -9,7 +9,7 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; -public class DotNetWatchTests : SmokeTests +public class DotNetWatchTests : SdkTests { public DotNetWatchTests(ITestOutputHelper outputHelper) : base(outputHelper) { } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/LicenseScanTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/LicenseScanTests.cs new file mode 100644 index 000000000..6ddf668c5 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/LicenseScanTests.cs @@ -0,0 +1,291 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Text.RegularExpressions; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.SourceBuild.SmokeTests; + +/// +/// Scans the VMR for licenses and compares them to a baseline. This ensures that only open-source licenses are used for relevant files. +/// +/// +/// Each sub-repo of the VMR is scanned separately because of the amount of time it takes. +/// When scanning is run, the test provides a list of files for the scanner to ignore. These include binary file types. It also includes +/// .il/.ildump file types which are massive, causing the scanner to choke and don't include license references anyway. +/// Once the scanner returns the results, a filtering process occurs. First, any detected license that is in the allowed list of licenses +/// is filtered out. The test defines a list of such licenses that all represent open-source licenses. Next, a license exclusions file is +/// applied to the filtering. This file contains a set of paths for which certain detected licenses are to be ignored. Such a path can be +/// defined to ignore all detected licenses or specific ones. These exclusions are useful for ignoring false positives where the scanning +/// tool has detected something in the file that makes it think it's a license reference when that's not actually the intent. Other cases +/// that are excluded are when the license is meant as configuration or test data and not actually applying to the code. These exclusions +/// further filter down the set of the detected licenses for each file. Everything that's left at this point is reported. It gets compared +/// to a baseline file (which is defined for each sub-repo). If the filtered results differ from what's defined in the baseline, the test fails. +/// +/// Rules for determining how to resolve a detected license: +/// 1. If it's an allowed open-source license, add it to the list of allowed licenses in LicenseScanTests.cs. +/// 2. If the file shouldn't be scanned as a general rule because of its file type (e.g. image file), add it to the list of excluded file types in LicenseScanTests.cs. +/// 3. Add it to LicenseExclusions.txt if the referenced license is one of the following: +/// a. Not applicable (e.g. test data) +/// b. False positive +/// 4. If the license is not allowed for open-souce, the license needs to be fixed. Everything else should go in the baseline file. +/// +public class LicenseScanTests : TestBase +{ + private const string BaselineSubDir = "licenses"; + + private static readonly string[] s_allowedLicenseExpressions = new string[] + { + "apache-1.1", // https://opensource.org/license/apache-1-1/ + "apache-2.0", // https://opensource.org/license/apache-2-0/ + "apache-2.0 WITH apple-runtime-library-exception", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/apple-runtime-library-exception.LICENSE + "apache-2.0 WITH llvm-exception", // https://foundation.llvm.org/relicensing/LICENSE.txt + "apsl-2.0", // https://opensource.org/license/apsl-2-0-php/ + "boost-1.0", // https://opensource.org/license/bsl-1-0/ + "bsd-new", // https://opensource.org/license/BSD-3-clause/ + "bsd-original", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/bsd-original.LICENSE + "bsd-original-uc", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/bsd-original-uc.LICENSE + "bsd-simplified", // https://opensource.org/license/bsd-2-clause/ + "bytemark", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/bytemark.LICENSE + "bzip2-libbzip-2010", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/bzip2-libbzip-2010.LICENSE + "cc0-1.0", // https://creativecommons.org/publicdomain/zero/1.0/legalcode + "cc-by-3.0", // https://creativecommons.org/licenses/by/3.0/legalcode + "cc-by-sa-3.0", // https://creativecommons.org/licenses/by-sa/3.0/legalcode + "cc-by-sa-4.0", // https://creativecommons.org/licenses/by-sa/4.0/legalcode + "cc-pd", // https://creativecommons.org/publicdomain/mark/1.0/ + "epl-1.0", // https://opensource.org/license/epl-1-0/ + "generic-cla", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/generic-cla.LICENSE + "gpl-1.0-plus", // https://opensource.org/license/gpl-1-0/ + "gpl-2.0", // https://opensource.org/license/gpl-2-0/ + "ietf", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/ietf.LICENSE + "gpl-2.0-plus WITH autoconf-simple-exception-2.0", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/rules/gpl-2.0-plus_with_autoconf-simple-exception-2.0_8.RULE + "gpl-2.0 WITH gcc-linking-exception-2.0", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/rules/gpl-2.0_with_gcc-linking-exception-2.0_6.RULE + "isc", // https://opensource.org/license/isc-license-txt/ + "iso-8879", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/iso-8879.LICENSE + "lgpl-2.0-plus", // https://opensource.org/license/lgpl-2-0/ + "lgpl-2.1", // https://opensource.org/license/lgpl-2-1/ + "lgpl-2.1-plus", // https://opensource.org/license/lgpl-2-1/ + "mit", // https://opensource.org/license/mit/ + "mit-addition", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/mit-addition.LICENSE + "ms-patent-promise", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/ms-patent-promise.LICENSE + "ms-lpl", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/ms-lpl.LICENSE + "ms-pl", // https://opensource.org/license/ms-pl-html/ + "ms-rl", // https://opensource.org/license/ms-rl-html/ + "newton-king-cla", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/newton-king-cla.LICENSE + "ngpl", // https://opensource.org/license/nethack-php/ + "object-form-exception-to-mit", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/object-form-exception-to-mit.LICENSE + "ofl-1.1", // https://opensource.org/license/ofl-1-1/ + "osf-1990", // https://fedoraproject.org/wiki/Licensing:MIT?rd=Licensing/MIT#HP_Variant + "public-domain", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/public-domain.LICENSE + "public-domain-disclaimer", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/public-domain-disclaimer.LICENSE + "python", // https://opensource.org/license/python-2-0/ + "rpl-1.5", // https://opensource.org/license/rpl-1-5/ + "sax-pd", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/sax-pd.LICENSE + "unicode", // https://opensource.org/license/unicode-inc-license-agreement-data-files-and-software/ + "unicode-mappings", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/unicode-mappings.LICENSE + "uoi-ncsa", // https://opensource.org/license/uoi-ncsa-php/ + "w3c-software-19980720", // https://opensource.org/license/w3c/ + "w3c-software-doc-20150513", // https://opensource.org/license/w3c/ + "warranty-disclaimer", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/warranty-disclaimer.LICENSE + "x11", // https://github.com/nexB/scancode-toolkit/blob/develop/src/licensedcode/data/licenses/x11.LICENSE + "zlib" // https://opensource.org/license/zlib/ + }; + + private static readonly string[] s_ignoredFilePatterns = new string[] + { + "*.bin", + "*.bmp", + "*.bson", + "*.db", + "*.dic", + "*.eot", + "*.gif", + "*.ico", + "*.jpg", + "*.il", + "*.ildump", + "*.lss", + "*.nlp", + "*.otf", + "*.pdf", + "*.pfx", + "*.png", + "*.snk", + "*.ttf", + "*.vsd", + "*.vsdx", + "*.winmd", + "*.woff", + "*.woff2", + "*.xlsx", + }; + + private readonly string _targetRepo; + + public LicenseScanTests(ITestOutputHelper outputHelper) : base(outputHelper) + { + Assert.NotNull(Config.LicenseScanPath); + _targetRepo = new DirectoryInfo(Config.LicenseScanPath).Name; + } + + [SkippableFact(Config.LicenseScanPathEnv, skipOnNullOrWhiteSpaceEnv: true)] + public void ScanForLicenses() + { + Assert.NotNull(Config.LicenseScanPath); + + string OriginalScancodeResultsPath = Path.Combine(LogsDirectory, "scancode-results-original.json"); + string FilteredScancodeResultsPath = Path.Combine(LogsDirectory, "scancode-results-filtered.json"); + + // Scancode Doc: https://scancode-toolkit.readthedocs.io/en/latest/index.html + string ignoreOptions = string.Join(" ", s_ignoredFilePatterns.Select(pattern => $"--ignore {pattern}")); + ExecuteHelper.ExecuteProcessValidateExitCode( + "scancode", + $"--license --strip-root --only-findings {ignoreOptions} --json-pp {OriginalScancodeResultsPath} {Config.LicenseScanPath}", + OutputHelper); + + JsonDocument doc = JsonDocument.Parse(File.ReadAllText(OriginalScancodeResultsPath)); + ScancodeResults? scancodeResults = doc.Deserialize(); + Assert.NotNull(scancodeResults); + + FilterFiles(scancodeResults); + + JsonSerializerOptions options = new() + { + WriteIndented = true + }; + string json = JsonSerializer.Serialize(scancodeResults, options); + File.WriteAllText(FilteredScancodeResultsPath, json); + + string baselineName = $"Licenses.{_targetRepo}.json"; + + string baselinePath = BaselineHelper.GetBaselineFilePath(baselineName, BaselineSubDir); + if (!File.Exists(baselinePath)) + { + Assert.Fail($"No license baseline file exists for repo '{_targetRepo}'. Expected file: {baselinePath}"); + } + + BaselineHelper.CompareBaselineContents(baselineName, json, OutputHelper, Config.WarnOnLicenseScanDiffs, BaselineSubDir); + } + + private LicenseExclusion ParseLicenseExclusion(string rawExclusion) + { + string[] parts = rawExclusion.Split('|', StringSplitOptions.RemoveEmptyEntries); + + Match repoNameMatch = Regex.Match(parts[0], @"(?<=src/)[^/]+"); + + Assert.True(repoNameMatch.Success); + + // The path in the exclusion file is rooted from the VMR. But the path in the scancode results is rooted from the + // target repo within the VMR. So we need to strip off the beginning part of the path. + Match restOfPathMatch = Regex.Match(parts[0], @"(?<=src/[^/]+/).*"); + string path = restOfPathMatch.Value; + + if (parts.Length == 0 || parts.Length > 2) + { + throw new Exception($"Invalid license exclusion: '{rawExclusion}'"); + } + + if (parts.Length > 1) + { + string[] licenseExpressions = parts[1].Split(',', StringSplitOptions.RemoveEmptyEntries); + return new LicenseExclusion(repoNameMatch.Value, path, licenseExpressions); + } + else + { + return new LicenseExclusion(repoNameMatch.Value, path, Enumerable.Empty()); + } + } + + private void FilterFiles(ScancodeResults scancodeResults) + { + IEnumerable rawExclusions = Utilities.ParseExclusionsFile("LicenseExclusions.txt"); + IEnumerable exclusions = rawExclusions + .Select(exclusion => ParseLicenseExclusion(exclusion)) + .Where(exclusion => exclusion.Repo == _targetRepo) + .ToList(); + + // This will filter out files that we don't want to include in the baseline. + // Filtering can happen in two ways: + // 1. There are a set of allowed license expressions that apply to all files. If a file has a match on one of those licenses, + // that license will not be considered. + // 2. The LicenseExclusions.txt file contains a list of files and the licenses that should be excluded from those files. + // Once the license expression filtering has been applied, if a file has any licenses left, it will be included in the baseline. + // In that case, the baseline will list all of the licenses for that file, even if some were originally excluded during this processing. + // In other words, the baseline will be fully representative of the licenses that apply to the files that are listed there. + + for (int i = scancodeResults.Files.Count - 1; i >= 0; i--) + { + ScancodeFileResult file = scancodeResults.Files[i]; + + // A license expression can be a logical expression, e.g. "(MIT OR Apache-2.0)" + // For our purposes, we just care about the license involved, not the semantics of the expression. + // Parse out all the expression syntax to just get the license names. + string[] licenses = file.LicenseExpression? + .Replace("(", string.Empty) + .Replace(")", string.Empty) + .Replace(" AND ", ",") + .Replace(" OR ", ",") + .Split(",", StringSplitOptions.RemoveEmptyEntries) + .Select(license => license.Trim()) + .ToArray() + ?? Array.Empty(); + + // First check whether the file's licenses can all be matched with allowed expressions + IEnumerable disallowedLicenses = licenses + .Where(license => !s_allowedLicenseExpressions.Contains(license, StringComparer.OrdinalIgnoreCase)); + + if (!disallowedLicenses.Any()) + { + scancodeResults.Files.Remove(file); + } + else + { + // There are some licenses that are not allowed. Now check whether the file is excluded. + + IEnumerable matchingExclusions = + Utilities.GetMatchingFileExclusions(file.Path, exclusions, exclusion => exclusion.Path); + + IEnumerable excludedLicenses = matchingExclusions.SelectMany(exclusion => exclusion.LicenseExpressions); + // If no licenses are explicitly specified, it means they're all excluded. + if (matchingExclusions.Any() && !excludedLicenses.Any()) + { + scancodeResults.Files.Remove(file); + } + else + { + IEnumerable remainingLicenses = disallowedLicenses.Except(excludedLicenses); + + if (!remainingLicenses.Any()) + { + scancodeResults.Files.Remove(file); + } + } + } + } + } + + private record LicenseExclusion(string Repo, string Path, IEnumerable LicenseExpressions); + + private class ScancodeResults + { + [JsonPropertyName("files")] + public List Files { get; set; } = new(); + } + + private class ScancodeFileResult + { + [JsonPropertyName("path")] + public string Path { get; set; } = string.Empty; + + [JsonPropertyName("detected_license_expression")] + public string? LicenseExpression { get; set; } + } +} diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/OmniSharpTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/OmniSharpTests.cs index 48cdb1d50..416a1e1ca 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/OmniSharpTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/OmniSharpTests.cs @@ -16,10 +16,10 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests; /// /// OmniSharp tests to ensure it works with a source-built sdk. /// -public class OmniSharpTests : SmokeTests +public class OmniSharpTests : SdkTests { // Update version as new releases become available: https://github.com/OmniSharp/omnisharp-roslyn/releases - private const string OmniSharpReleaseVersion = "1.39.8"; + private const string OmniSharpReleaseVersion = "1.39.10"; private string OmniSharpDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), nameof(OmniSharpTests)); diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/PoisonTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/PoisonTests.cs index 6eb8203f5..cf2e1182b 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/PoisonTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/PoisonTests.cs @@ -9,7 +9,7 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests { - public class PoisonTests : SmokeTests + public class PoisonTests : SdkTests { public PoisonTests(ITestOutputHelper outputHelper) : base(outputHelper) { } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkContentTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkContentTests.cs index d3b0c8a26..29bb7dbc5 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkContentTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkContentTests.cs @@ -17,7 +17,7 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; [Trait("Category", "SdkContent")] -public class SdkContentTests : SmokeTests +public class SdkContentTests : SdkTests { private const string MsftSdkType = "msft"; private const string SourceBuildSdkType = "sb"; @@ -98,7 +98,7 @@ public class SdkContentTests : SmokeTests if (sbVersion is not null && msftVersion is not null && sbVersion >= msftVersion && - IsFileExcluded(assemblyPath, assemblyVersionDiffFilters)) + Utilities.IsFileExcluded(assemblyPath, assemblyVersionDiffFilters)) { sbSdkAssemblyVersions.Remove(assemblyPath); msftSdkAssemblyVersions.Remove(assemblyPath); @@ -182,7 +182,7 @@ public class SdkContentTests : SmokeTests string relativePath = Path.GetRelativePath(sbSdkPath, file); string normalizedPath = BaselineHelper.RemoveVersions(relativePath); - if (!IsFileExcluded(normalizedPath, exclusionFilters)) + if (!Utilities.IsFileExcluded(normalizedPath, exclusionFilters)) { sbSdkAssemblyVersions.Add(normalizedPath, GetVersion(assemblyName)); } @@ -208,32 +208,13 @@ public class SdkContentTests : SmokeTests } private static IEnumerable RemoveExclusions(IEnumerable files, IEnumerable exclusions) => - files.Where(item => !IsFileExcluded(item, exclusions)); - - private static bool IsFileExcluded(string filePath, IEnumerable exclusions) => - exclusions.Any(p => FileSystemName.MatchesSimpleExpression(p, filePath)); + files.Where(item => !Utilities.IsFileExcluded(item, exclusions)); private static IEnumerable GetSdkDiffExclusionFilters(string sdkType) => - ParseExclusionsFile("SdkFileDiffExclusions.txt", sdkType); + Utilities.ParseExclusionsFile("SdkFileDiffExclusions.txt", sdkType); private static IEnumerable GetSdkAssemblyVersionDiffExclusionFilters() => - ParseExclusionsFile("SdkAssemblyVersionDiffExclusions.txt"); - - private static IEnumerable ParseExclusionsFile(string exclusionsFileName, string? prefix = null) - { - string exclusionsFilePath = Path.Combine(BaselineHelper.GetAssetsDirectory(), exclusionsFileName); - int prefixSkip = prefix?.Length + 1 ?? 0; - return File.ReadAllLines(exclusionsFilePath) - // process only specific sdk exclusions if a prefix is provided - .Where(line => prefix is null || line.StartsWith(prefix + ",")) - .Select(line => - { - // Ignore comments - var index = line.IndexOf('#'); - return index >= 0 ? line[prefixSkip..index].TrimEnd() : line[prefixSkip..]; - }) - .ToList(); - } + Utilities.ParseExclusionsFile("SdkAssemblyVersionDiffExclusions.txt"); private static string RemoveDiffMarkers(string source) { diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SmokeTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkTests.cs similarity index 66% rename from src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SmokeTests.cs rename to src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkTests.cs index 3c197262b..ba3381360 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SmokeTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SdkTests.cs @@ -7,16 +7,14 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; /// -/// Shared base class for all smoke tests. +/// Shared base class for all SDK-based smoke tests. /// -public abstract class SmokeTests +public abstract class SdkTests : TestBase { internal DotNetHelper DotNetHelper { get; } - internal ITestOutputHelper OutputHelper { get; } - protected SmokeTests(ITestOutputHelper outputHelper) + protected SdkTests(ITestOutputHelper outputHelper) : base(outputHelper) { DotNetHelper = new DotNetHelper(outputHelper); - OutputHelper = outputHelper; } } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourceBuiltArtifactsTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourceBuiltArtifactsTests.cs index 9fbbbc781..8ab1a9600 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourceBuiltArtifactsTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourceBuiltArtifactsTests.cs @@ -13,13 +13,14 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; -public class SourceBuiltArtifactsTests : SmokeTests +public class SourceBuiltArtifactsTests : SdkTests { public SourceBuiltArtifactsTests(ITestOutputHelper outputHelper) : base(outputHelper) { } - [Fact] + [SkippableFact(Config.SourceBuiltArtifactsPathEnv, skipOnNullOrWhiteSpaceEnv: true)] public void VerifyVersionFile() { + Assert.NotNull(Config.SourceBuiltArtifactsPath); string outputDir = Path.Combine(Directory.GetCurrentDirectory(), "sourcebuilt-artifacts"); Directory.CreateDirectory(outputDir); try diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourcelinkTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourcelinkTests.cs index f3a39242b..0fc8735d9 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourcelinkTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/SourcelinkTests.cs @@ -14,7 +14,16 @@ using Xunit.Abstractions; namespace Microsoft.DotNet.SourceBuild.SmokeTests; -public class SourcelinkTests : SmokeTests +/// +/// Separate test collection for Sourcelink tests. This is needed due to intra-test parallelization, +/// which can cause less CPU time to be allocated to other tests. +/// This would make other tests run too long and fail due to timeouts. +/// +[CollectionDefinition(nameof(SourcelinkTestCollection), DisableParallelization = true)] +public class SourcelinkTestCollection { } + +[Collection(nameof(SourcelinkTestCollection))] +public class SourcelinkTests : SdkTests { private static string SourcelinkRoot { get; } = Path.Combine(Directory.GetCurrentDirectory(), nameof(SourcelinkTests)); @@ -23,27 +32,43 @@ public class SourcelinkTests : SmokeTests /// /// Verifies that all symbols have valid sourcelinks. /// - [Fact] + [SkippableFact(Config.SourceBuiltArtifactsPathEnv, skipOnNullOrWhiteSpaceEnv: true)] public void VerifySourcelinks() { - if (Directory.Exists(SourcelinkRoot)) + try + { + if (Directory.Exists(SourcelinkRoot)) + { + Directory.Delete(SourcelinkRoot, true); + } + Directory.CreateDirectory(SourcelinkRoot); + + string symbolsRoot = Directory.CreateDirectory(Path.Combine(SourcelinkRoot, "symbols")).FullName; + + // We are validating dotnet-symbols-all-*.tar.gz which contains all source-built symbols, including + // SDK-specific symbols that are also packaged in dotnet-symbols-sdk-*.tar.gz. + Utilities.ExtractTarball( + Utilities.GetFile(Path.GetDirectoryName(Config.SourceBuiltArtifactsPath), "dotnet-symbols-all-*.tar.gz"), + symbolsRoot, + OutputHelper); + + IList failedFiles = ValidateSymbols(symbolsRoot, InitializeSourcelinkTool()); + + if (failedFiles.Count > 0) + { + OutputHelper.WriteLine($"Sourcelink verification failed for the following files:"); + foreach (string file in failedFiles) + { + OutputHelper.WriteLine(file); + } + } + + Assert.True(failedFiles.Count == 0); + } + finally { Directory.Delete(SourcelinkRoot, true); } - Directory.CreateDirectory(SourcelinkRoot); - - IList failedFiles = ValidateSymbols(ExtractSymbolsPackages(GetAllSymbolsPackages()), InitializeSourcelinkTool()); - - if (failedFiles.Count > 0) - { - OutputHelper.WriteLine($"Sourcelink verification failed for the following files:"); - foreach (string file in failedFiles) - { - OutputHelper.WriteLine(file); - } - } - - Assert.True(failedFiles.Count == 0); } /// @@ -53,6 +78,8 @@ public class SourcelinkTests : SmokeTests /// Path to sourcelink tool binary. private string InitializeSourcelinkTool() { + Assert.NotNull(Config.SourceBuiltArtifactsPath); + const string SourcelinkToolPackageNamePattern = "dotnet-sourcelink*nupkg"; const string SourcelinkToolBinaryFilename = "dotnet-sourcelink.dll"; @@ -65,38 +92,6 @@ public class SourcelinkTests : SmokeTests return Utilities.GetFile(extractedToolPath, SourcelinkToolBinaryFilename); } - private IEnumerable GetAllSymbolsPackages() - { - /* - At the moment we validate sourcelinks from runtime symbols package. - The plan is to make symbols, from all repos, available in source-build artifacts. - Once that's available, this code will be modified to validate all available symbols. - Tracking issue: https://github.com/dotnet/source-build/issues/3612 - */ - - // Runtime symbols package lives in the same directory as PSB artifacts. - // i.e. /artifacts/x64/Release/runtime/dotnet-runtime-symbols-fedora.36-x64-8.0.0-preview.7.23355.7.tar.gz - yield return Utilities.GetFile(Path.GetDirectoryName(Config.SourceBuiltArtifactsPath), "dotnet-runtime-symbols-*.tar.gz"); - } - - /// - /// Extracts symbols packages to subdirectories of the common symbols root directory. - /// - /// Path to common symbols root directory. - private string ExtractSymbolsPackages(IEnumerable packages) - { - string symbolsRoot = Directory.CreateDirectory(Path.Combine(SourcelinkRoot, "symbols")).FullName; - - foreach (string package in packages) - { - Assert.True(package.EndsWith(".tar.gz"), $"Package extension is not supported: {package}"); - DirectoryInfo targetDirInfo = Directory.CreateDirectory(Path.Combine(symbolsRoot, Path.GetFileNameWithoutExtension(package))); - Utilities.ExtractTarball(package, targetDirInfo.FullName, OutputHelper); - } - - return symbolsRoot; - } - private IList ValidateSymbols(string path, string sourcelinkToolPath) { Assert.True(Directory.Exists(path), $"Path, with symbol files to validate, does not exist: {path}"); @@ -112,7 +107,7 @@ public class SourcelinkTests : SmokeTests OutputHelper, logOutput: false, excludeInfo: true, // Exclude info messages, as there can be 1,000+ processes - millisecondTimeout: 5000, + millisecondTimeout: 60000, configureCallback: (process) => DotNetHelper.ConfigureProcess(process, null)); if (executeResult.Process.ExitCode != 0) diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/TestBase.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/TestBase.cs new file mode 100644 index 000000000..963f07109 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/TestBase.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using Xunit.Abstractions; + +namespace Microsoft.DotNet.SourceBuild.SmokeTests; + +public abstract class TestBase +{ + public static string LogsDirectory { get; } = Path.Combine(Directory.GetCurrentDirectory(), "logs"); + + public ITestOutputHelper OutputHelper { get; } + + public TestBase(ITestOutputHelper outputHelper) + { + OutputHelper = outputHelper; + + if (!Directory.Exists(LogsDirectory)) + { + Directory.CreateDirectory(LogsDirectory); + } + } +} diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Utilities.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Utilities.cs index a701e730f..53efa2655 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Utilities.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/Utilities.cs @@ -8,6 +8,8 @@ using System.Collections.Generic; using System.Formats.Tar; using System.IO; using System.IO.Compression; +using System.IO.Enumeration; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Xunit; @@ -17,6 +19,37 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests; public static class Utilities { + /// + /// Returns whether the given file path is excluded by the given exclusions using glob file matching. + /// + public static bool IsFileExcluded(string filePath, IEnumerable exclusions) => + GetMatchingFileExclusions(filePath, exclusions, exclusion => exclusion).Any(); + + public static IEnumerable GetMatchingFileExclusions(string filePath, IEnumerable exclusions, Func getExclusionExpression) => + exclusions.Where(exclusion => FileSystemName.MatchesSimpleExpression(getExclusionExpression(exclusion), filePath)); + + /// + /// Parses a common file format in the test suite for listing file exclusions. + /// + /// Name of the exclusions file. + /// When specified, filters the exclusions to those that begin with the prefix value. + public static IEnumerable ParseExclusionsFile(string exclusionsFileName, string? prefix = null) + { + string exclusionsFilePath = Path.Combine(BaselineHelper.GetAssetsDirectory(), exclusionsFileName); + int prefixSkip = prefix?.Length + 1 ?? 0; + return File.ReadAllLines(exclusionsFilePath) + // process only specific exclusions if a prefix is provided + .Where(line => prefix is null || line.StartsWith(prefix + ",")) + .Select(line => + { + // Ignore comments + var index = line.IndexOf('#'); + return index >= 0 ? line[prefixSkip..index].TrimEnd() : line[prefixSkip..]; + }) + .Where(line => !string.IsNullOrEmpty(line)) + .ToList(); + } + public static void ExtractTarball(string tarballPath, string outputDir, ITestOutputHelper outputHelper) { // TarFile doesn't properly handle hard links (https://github.com/dotnet/runtime/pull/85378#discussion_r1221817490), diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/WebScenarioTests.cs b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/WebScenarioTests.cs index 654fe9552..3d6e9b23c 100644 --- a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/WebScenarioTests.cs +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/WebScenarioTests.cs @@ -16,7 +16,7 @@ namespace Microsoft.DotNet.SourceBuild.SmokeTests; /// for related basic scenarios. /// They are encapsulated in a separate testclass so that they can be run in parallel. /// -public class WebScenarioTests : SmokeTests +public class WebScenarioTests : SdkTests { public WebScenarioTests(ITestOutputHelper outputHelper) : base(outputHelper) { } diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/LicenseExclusions.txt b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/LicenseExclusions.txt new file mode 100644 index 000000000..e0efc77dd --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/LicenseExclusions.txt @@ -0,0 +1,257 @@ +# Contains the list of files to be excluded from license scanning. +# +# This list is processed using FileSystemName.MatchesSimpleExpression +# +# Format: +# Exclude the file entirely from license scanning: +# +# Exclude a specific detected license expression from the scan results for the file: +# |[,...] + +# +# arcade +# + +# False positive +src/arcade/Documentation/UnifiedBuild/Foundational-Concepts.md +src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/src/BuildFPMToolPreReqs.cs|json +src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/rpm_templates/copyright|cecill-c +src/arcade/src/SignCheck/SignCheck/THIRD-PARTY-NOTICES.TXT + +# Doesn't apply to code +src/arcade/src/Microsoft.DotNet.Arcade.Sdk/tools/Licenses/* + +# Applies to installer, not source +src/arcade/src/Microsoft.DotNet.Build.Tasks.Installers/build/wix/eula.rtf + +# +# aspnetcore +# + +# Line 1 is a generic statement about license applicability that is being detected as "unknown" +src/aspnetcore/src/Components/THIRD-PARTY-NOTICES.txt|unknown + +# Windows installer files that have a reference to a URL for license +src/aspnetcore/src/Installers/Windows/**/*.wxl|unknown-license-reference +src/aspnetcore/src/Installers/Windows/**/*.wxs|unknown-license-reference + +# License reference used in configuration, but not applying to code +src/aspnetcore/src/Mvc/Settings.StyleCop|unknown-license-reference +src/aspnetcore/src/submodules/MessagePack-CSharp/stylecop.json|unknown + +# +# command-line-api +# + +# False positive +src/command-line-api/System.CommandLine.sln|json + +# +# deployment-tools +# + +# False positive +src/deployment-tools/THIRD-PARTY-NOTICES.TXT|unknown-license-reference + +# +# diagnostics +# + +# False positive +src/diagnostics/THIRD-PARTY-NOTICES.TXT|codesourcery-2004 + +# +# format +# + +# False positive +src/format/THIRD-PARTY-NOTICES.TXT|unknown-license-reference + +# +# fsharp +# + +# False positive +src/fsharp/tests/EndToEndBuildTests/ProvidedTypes/ProvidedTypes.fs|unknown-license-reference +src/fsharp/tests/service/data/TestTP/ProvidedTypes.fs|unknown-license-reference +src/fsharp/vsintegration/tests/MockTypeProviders/DummyProviderForLanguageServiceTesting/ProvidedTypes.fs|unknown-license-reference + +# Applies to installer, not source +src/fsharp/setup/resources/eula/*.rtf + +# +# installer +# + +# False positive +src/installer/src/core-sdk-tasks/BuildFPMToolPreReqs.cs|json +src/installer/src/redist/targets/packaging/osx/clisdk/resources/en.lproj/welcome.html|cecill-c +src/installer/THIRD-PARTY-NOTICES|proprietary-license + +# Configuration, doesn't apply to source directly +src/installer/src/VirtualMonoRepo/THIRD-PARTY-NOTICES.template.txt +src/installer/src/redist/targets/packaging/**/*.json + +# +# msbuild +# + +# License reference used in build configuration, but not applying to code +src/msbuild/src/Directory.Build.props|ms-net-library-2018-11 + +# False positive +src/msbuild/src/Build/Instance/ProjectItemInstance.cs|generic-exception + +# +# nuget-client +# + +# False positive +src/nuget-client/build/NOTICES.txt|other-copyleft +src/nuget-client/README.md|unknown-license-reference +src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.UI/Resources.Designer.cs|unknown-license-reference +src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.UI/Actions/UIActionEngine.cs|unknown-license-reference +src/nuget-client/src/NuGet.Clients/NuGet.PackageManagement.VisualStudio/Services/NuGetPackageFileService.cs|proprietary-license +src/nuget-client/src/NuGet.Clients/NuGet.VisualStudio.Internal.Contracts/Formatters/LicenseMetadataFormatter.cs|proprietary-license +src/nuget-client/src/NuGet.Core/NuGet.Packaging/PackageCreation/Authoring/LicenseMetadata.cs|unknown-license-reference +src/nuget-client/src/NuGet.Core/NuGet.Packaging/Rules/DefaultManifestValuesRule.cs|unknown-license-reference +src/nuget-client/test/TestExtensions/GenerateLicenseList/Program.cs|json + +# Test data +src/nuget-client/test/**/resources/*.json +src/nuget-client/test/**/resources/*.xml +src/nuget-client/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/PackageLicenseUtilitiesTests.cs +src/nuget-client/test/NuGet.Core.Tests/NuGet.Packaging.Test/DefaultManifestValuesRuleTests.cs +src/nuget-client/test/NuGet.Core.Tests/NuGet.Packaging.Test/LicensesTests/LicenseExpressionTokenizerTests.cs +src/nuget-client/test/NuGet.Core.Tests/NuGet.Packaging.Test/LicensesTests/NuGetLicenseExpressionParserTests.cs +src/nuget-client/test/NuGet.Core.Tests/NuGet.Packaging.Test/LicensesTests/NuGetLicenseTests.cs +src/nuget-client/test/TestUtilities/Test.Utility/JsonData.cs + +# +# roslyn-analyzers +# + +# Build asset, not applicable to source +src/roslyn-analyzers/assets/EULA.txt|ms-net-library + +# +# roslyn +# + +# Test data +src/roslyn/src/Analyzers/VisualBasic/Tests/FileHeaders/FileHeaderTests.vb|unknown-license-reference +src/roslyn/src/EditorFeatures/CSharpTest2/EmbeddedLanguages/RegularExpressions/Regex_RealWorldPatterns.json + +# False positive +src/roslyn/src/Compilers/**/Portable/Symbols/NonMissingModuleSymbol.*|proprietary-license +src/roslyn/src/NuGet/ThirdPartyNotices.rtf|json + +# Applicable to installer, not source +src/roslyn/src/Setup/Roslyn.ThirdPartyNotices/ThirdPartyNotices.rtf +src/roslyn/src/Setup/Roslyn.VsixLicense/EULA.rtf + +# +# runtime +# + +# Doc describing licenses, not applicable to source +src/runtime/docs/project/copyright.md +src/runtime/docs/project/glossary.md + +# Doc that references a license, not applicable to source +src/runtime/src/coreclr/nativeaot/docs/compiling.md|openssl-ssleay + +# Installer asset, not applicable to source +src/runtime/src/installer/pkg/LICENSE-MSFT.TXT +src/runtime/src/installer/pkg/THIRD-PARTY-NOTICES.TXT + +# False positive +src/runtime/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/LicFileLicenseProvider.cs|proprietary-license +src/runtime/src/libraries/System.Configuration.ConfigurationManager/tests/Mono/LongValidatorTest.cs|json +src/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs|other-permissive +src/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs|other-permissive +src/runtime/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceive.cs|other-permissive +src/runtime/src/libraries/System.Reflection.Metadata/tests/Resources/README.md|unknown-license-reference +src/runtime/src/libraries/System.Runtime/tests/TestModule/README.md|unknown-license-reference +src/runtime/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs|proprietary-license +src/runtime/src/libraries/System.ServiceModel.Syndication/tests/BasicScenarioTests.cs|unknown-license-reference +src/runtime/src/mono/mono/mini/mini-posix.c|unknown-license-reference +src/runtime/src/mono/mono/mini/mini-windows.c|unknown-license-reference +src/runtime/src/native/external/libunwind/doc/libunwind-ia64.*|generic-exception +src/runtime/src/tests/JIT/Performance/CodeQuality/V8/Crypto/Crypto.cs|unknown-license-reference + +# Test data +src/runtime/src/libraries/System.Private.Xml.Linq/tests/XDocument.Common/InputSpace.cs|other-permissive +src/runtime/src/libraries/System.Private.Xml.Linq/tests/XDocument.Common/THIRD-PARTY-NOTICE|other-permissive +src/runtime/src/libraries/System.ServiceModel.Syndication/tests/TestFeeds/AtomFeeds/*.xml +src/runtime/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/AttRegexTests.cs|other-permissive + +# Reference to a license, not applicable to source +src/runtime/src/libraries/System.Text.Json/roadmap/images/core-components.txt|unknown-license-reference +src/runtime/src/libraries/System.Text.Json/roadmap/images/higher-level-components.txt + +# Sample data +src/runtime/src/mono/sample/wasm/browser-webpack/package-lock.json + +# +# source-build-externals +# + +# False positive +src/source-build-externals/src/abstractions-xunit/README.md|free-unknown +src/source-build-externals/src/application-insights/NETCORE/ThirdPartyNotices.txt|unknown +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/benchmark/Microsoft.IdentityModel.Benchmarks/CreateTokenTests.cs|proprietary-license +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/src/Microsoft.IdentityModel.JsonWebTokens/JsonClaimValueTypes.cs|proprietary-license +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/src/Microsoft.IdentityModel.Tokens.Saml/Saml/ClaimProperties.cs|proprietary-license +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/src/Microsoft.IdentityModel.Tokens.Saml/Saml/SamlTokenUtilities.cs|proprietary-license +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/src/Microsoft.IdentityModel.Tokens.Saml/Saml2/ClaimProperties.cs|proprietary-license +src/source-build-externals/src/azure-activedirectory-identitymodel-extensions-for-dotnet/src/System.IdentityModel.Tokens.Jwt/JsonClaimValueTypes.cs|proprietary-license +src/source-build-externals/src/humanizer/readme.md|free-unknown +src/source-build-externals/src/humanizer/NuSpecs/*.nuspec* +src/source-build-externals/src/xunit/README.md|free-unknown +src/source-build-externals/src/xunit/src/xunit.assert/Asserts/README.md|free-unknown +src/source-build-externals/src/xunit/xunit.sln|json + +# A patch which removes the license usage but contains references to the removed license as part of the patch reference lines +src/source-build-externals/patches/application-insights/0002-Remove-WebGrease-from-TPN-2816.patch + +# +# source-build-reference-packages +# + +# False positive +src/source-build-reference-packages/src/targetPacks/ILsrc/microsoft.netcore.app.ref/3.*/THIRD-PARTY-NOTICES.TXT|codesourcery-2004 +src/source-build-reference-packages/src/targetPacks/ILsrc/netstandard.library/1.6.1/ThirdPartyNotices.txt|unknown +src/source-build-reference-packages/src/targetPacks/ILsrc/netstandard.library/2.0.*/THIRD-PARTY-NOTICES.TXT|unknown +src/source-build-reference-packages/src/targetPacks/ILsrc/netstandard.library.ref/2.1.0/THIRD-PARTY-NOTICES.TXT|codesourcery-2004 +src/source-build-reference-packages/src/textOnlyPackages/src/microsoft.codeanalysis.collections/4.2.0-1.22102.8/ThirdPartyNotices.rtf|json +src/source-build-reference-packages/src/textOnlyPackages/src/microsoft.netcore.*/1.*/ThirdPartyNotices.txt|unknown + +# Contains references to licenses which are not applicable to the source +src/source-build-reference-packages/src/packageSourceGenerator/PackageSourceGeneratorTask/RewriteNuspec.cs|unknown-license-reference,ms-net-library-2018-11 +src/source-build-reference-packages/src/textOnlyPackages/src/microsoft.private.intellisense/8.0.0-preview-20230918.1/IntellisenseFiles/windowsdesktop/1033/PresentationCore.xml|proprietary-license + +# +# sourcelink +# + +# False positive +src/sourcelink/docs/GitSpec/GitSpec.md|unknown-license-reference + +# +# test-templates +# + +# Not applicable to source +src/test-templates/Templates/**/*.vstemplate + +# +# vstest +# + +# False positive +src/vstest/src/Microsoft.TestPlatform.Extensions.BlameDataCollector/ProcDumpArgsBuilder.cs|proprietary-license + +# Build asset, but not applying to code +src/vstest/src/package/Microsoft.CodeCoverage/ThirdPartyNoticesCodeCoverage.txt +src/vstest/src/package/Microsoft.VisualStudio.TestTools.TestPlatform.V2.CLI/License.rtf diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.arcade.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.arcade.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.arcade.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.aspnetcore.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.aspnetcore.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.aspnetcore.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.cecil.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.cecil.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.cecil.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.command-line-api.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.command-line-api.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.command-line-api.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.deployment-tools.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.deployment-tools.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.deployment-tools.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.diagnostics.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.diagnostics.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.diagnostics.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.emsdk.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.emsdk.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.emsdk.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.format.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.format.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.format.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.fsharp.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.fsharp.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.fsharp.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.installer.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.installer.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.installer.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.msbuild.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.msbuild.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.msbuild.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.nuget-client.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.nuget-client.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.nuget-client.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.razor.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.razor.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.razor.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn-analyzers.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn-analyzers.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn-analyzers.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.roslyn.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.runtime.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.runtime.json new file mode 100644 index 000000000..472899b4c --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.runtime.json @@ -0,0 +1,20 @@ +{ + "files": [ + { + "path": "src/tests/GC/Scenarios/GCBench/THIRD-PARTY-NOTICES", + "detected_license_expression": "unknown-license-reference" + }, + { + "path": "src/tests/JIT/Performance/CodeQuality/Benchstones/BenchF/LLoops/THIRD-PARTY-NOTICES", + "detected_license_expression": "unknown-license-reference" + }, + { + "path": "src/tests/JIT/Performance/CodeQuality/Benchstones/MDBenchF/MDLLoops/THIRD-PARTY-NOTICES", + "detected_license_expression": "unknown-license-reference" + }, + { + "path": "src/tests/JIT/Performance/CodeQuality/V8/Richards/THIRD-PARTY-NOTICES", + "detected_license_expression": "unknown-license-reference" + } + ] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sdk.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sdk.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sdk.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-externals.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-externals.json new file mode 100644 index 000000000..42c3e6895 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-externals.json @@ -0,0 +1,12 @@ +{ + "files": [ + { + "path": "src/application-insights/LOGGING/ThirdPartyNotices.txt", + "detected_license_expression": "unknown AND apache-2.0 AND mit AND bsd-new" + }, + { + "path": "src/application-insights/WEB/ThirdPartyNotices.txt", + "detected_license_expression": "bsd-new AND mit AND ms-pl AND apache-2.0 AND (cc-by-3.0-us AND cc-by-3.0 AND mit) AND ms-net-library AND ms-rl" + } + ] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-reference-packages.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-reference-packages.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.source-build-reference-packages.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sourcelink.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sourcelink.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.sourcelink.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.symreader.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.symreader.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.symreader.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.templating.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.templating.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.templating.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.test-templates.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.test-templates.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.test-templates.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.vstest.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.vstest.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.vstest.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xdt.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xdt.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xdt.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xliff-tasks.json b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xliff-tasks.json new file mode 100644 index 000000000..6941fa698 --- /dev/null +++ b/src/SourceBuild/content/test/Microsoft.DotNet.SourceBuild.SmokeTests/assets/baselines/licenses/Licenses.xliff-tasks.json @@ -0,0 +1,3 @@ +{ + "files": [] +} \ No newline at end of file diff --git a/src/redist/targets/GeneratePKG.targets b/src/redist/targets/GeneratePKG.targets index 60336eb5f..9cab8a0a9 100644 --- a/src/redist/targets/GeneratePKG.targets +++ b/src/redist/targets/GeneratePKG.targets @@ -95,7 +95,8 @@ x86_64 - 10.13 + + 10.15 11.0