diff --git a/policies/github-dsp.config.sarif-external-properties b/policies/github-dsp.config.sarif-external-properties new file mode 100644 index 000000000..c789a2783 --- /dev/null +++ b/policies/github-dsp.config.sarif-external-properties @@ -0,0 +1,67 @@ +{ + "$schema": "https://json.schemastore.org/sarif-external-property-file-2.1.0-rtm.5", + "version": "2.1.0", + "guid": "89072b7a-3d16-43f2-ac0b-3d9cffc814be", + "policies": [ + { + "name": "GitHub Developer Security Portal policy", + "version": "0.0.1", + "organization": "Microsoft", + "product": "Microsoft SARIF SDK", + "associatedComponent": { + "name": "Sarif.Multitool" + }, + "rules": [ + { + "id": "SARIF2017", + "name": "LocationsMustProvideRequiredProperties", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2018", + "name": "InlineThreadFlowLocations", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2019", + "name": "RegionsMustProvideRequiredProperties", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2020", + "name": "ReviewArraysThatExceedConfigurableDefaults", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2021", + "name": "LocationsMustBeRelativeUrisOrFilePaths", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2022", + "name": "ProvideCheckoutPath", + "defaultConfiguration": { + "enabled": true + } + }, + { + "id": "SARIF2023", + "name": "RelatedLocationMustProvideRequiredProperties", + "defaultConfiguration": { + "enabled": true + } + } + ] + } + ] +} \ No newline at end of file diff --git a/policies/github-dsp.config.xml b/policies/github-dsp.config.xml new file mode 100644 index 000000000..9d278fbdc --- /dev/null +++ b/policies/github-dsp.config.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ReleaseHistory.md b/src/ReleaseHistory.md index 3e5fc40df..8ced2b652 100644 --- a/src/ReleaseHistory.md +++ b/src/ReleaseHistory.md @@ -3,6 +3,10 @@ * BUGFIX: Various Fortify FPR converter improvements (such as improve variable expansion in result messages). * COMMAND-LINE BREAKING: Change `merge` command output directory argument name to `output-directory`. +## **v2.3.4** [Sdk](https://www.nuget.org/packages/Sarif.Sdk/2.3.4) | [Driver](https://www.nuget.org/packages/Sarif.Driver/2.3.4) | [Converters](https://www.nuget.org/packages/Sarif.Converters/2.3.4) | [Multitool](https://www.nuget.org/packages/Sarif.Multitool/2.3.4) +* FEATURE: Add analysis rules appropriate for SARIF files that are to be uploaded to the GitHub Developer Security Portal. +* BUGFIX: The validator no longer reports `SARIF2010.ProvideCodeSnippets` if embedded file content for the specified artifact is present. [#2003](https://github.com/microsoft/sarif-sdk/issues/2003) + ## **v2.3.3** [Sdk](https://www.nuget.org/packages/Sarif.Sdk/2.3.3) | [Driver](https://www.nuget.org/packages/Sarif.Driver/2.3.3) | [Converters](https://www.nuget.org/packages/Sarif.Converters/2.3.3) | [Multitool](https://www.nuget.org/packages/Sarif.Multitool/2.3.3) * FEATURE: Improve `SarifSdkSample` application: use `uriBaseIds`. * FEATURE: Add additional checks to SARIF analysis rule `SARIF2004.OptimizeFileSize`. diff --git a/src/Sarif.Driver/Sdk/AnalyzeCommandBase.cs b/src/Sarif.Driver/Sdk/AnalyzeCommandBase.cs index 00700272d..1b45d97b0 100644 --- a/src/Sarif.Driver/Sdk/AnalyzeCommandBase.cs +++ b/src/Sarif.Driver/Sdk/AnalyzeCommandBase.cs @@ -546,12 +546,12 @@ protected virtual void AnalyzeTargets( TContext rootContext, IEnumerable targets) { - SortedSet disabledSkimmers = new SortedSet(); + var disabledSkimmers = new SortedSet(); foreach (Skimmer skimmer in skimmers) { - PerLanguageOption ruleEnabledProperty; - ruleEnabledProperty = DefaultDriverOptions.CreateRuleSpecificOption(skimmer, DefaultDriverOptions.RuleEnabled); + PerLanguageOption ruleEnabledProperty = + DefaultDriverOptions.CreateRuleSpecificOption(skimmer, DefaultDriverOptions.RuleEnabled); RuleEnabledState ruleEnabled = rootContext.Policy.GetProperty(ruleEnabledProperty); @@ -561,6 +561,12 @@ protected virtual void AnalyzeTargets( Warnings.LogRuleExplicitlyDisabled(rootContext, skimmer.Id); RuntimeErrors |= RuntimeConditions.RuleWasExplicitlyDisabled; } + else if (!skimmer.DefaultConfiguration.Enabled && ruleEnabled == RuleEnabledState.Default) + { + // This skimmer is disabled by default, and the configuration file didn't mention it. + // So disable it, but don't complain that the rule was explicitly disabled. + disabledSkimmers.Add(skimmer.Id); + } } if (disabledSkimmers.Count == skimmers.Count()) diff --git a/src/Sarif.Driver/Sdk/RuleEnabledState.cs b/src/Sarif.Driver/Sdk/RuleEnabledState.cs index 59c0fd492..f84f248f6 100644 --- a/src/Sarif.Driver/Sdk/RuleEnabledState.cs +++ b/src/Sarif.Driver/Sdk/RuleEnabledState.cs @@ -22,7 +22,7 @@ public enum RuleEnabledState Disabled = 0x1, /// - /// User has reduced all signal from a rule to warning. Warnings + /// User has reduced all signal from a rule to warnings. Warnings /// should always be persisted to reports but may not block /// engineering processes. /// @@ -31,6 +31,11 @@ public enum RuleEnabledState /// /// User has elevated all failures from a check to errors. /// - Error = 0x4 + Error = 0x4, + + /// + /// User has reduced all signal from a rule to notes. + /// + Note = 0x8 } } diff --git a/src/Sarif.Driver/Sdk/Skimmer.cs b/src/Sarif.Driver/Sdk/Skimmer.cs index 4cf7e791c..e57abf9b5 100644 --- a/src/Sarif.Driver/Sdk/Skimmer.cs +++ b/src/Sarif.Driver/Sdk/Skimmer.cs @@ -12,6 +12,11 @@ public abstract class Skimmer : ReportingDescriptor public Skimmer() { this.Options = new Dictionary(); + this.DefaultConfiguration = new ReportingConfiguration + { + Level = this.DefaultLevel, + Enabled = this.EnabledByDefault + }; } private IDictionary multiformatMessageStrings; @@ -20,7 +25,9 @@ public Skimmer() protected virtual IEnumerable MessageResourceNames => throw new NotImplementedException(); - virtual public FailureLevel DefaultLevel { get { return FailureLevel.Warning; } } + virtual public FailureLevel DefaultLevel => FailureLevel.Warning; + + virtual public bool EnabledByDefault => true; public override IDictionary MessageStrings { diff --git a/src/Sarif.Multitool/Rules/RuleId.cs b/src/Sarif.Multitool/Rules/RuleId.cs index f3f6a8eb2..e8db7b70e 100644 --- a/src/Sarif.Multitool/Rules/RuleId.cs +++ b/src/Sarif.Multitool/Rules/RuleId.cs @@ -38,6 +38,17 @@ public static class RuleId public const string EnquoteDynamicMessageContent = "SARIF2015"; public const string FileUrisShouldBeRelative = "SARIF2016"; + // Rules required to upload SARIF files to the GitHub Developer Security Portal. + // These rules are disabled by default. The can be enabled by running the MultiTool + // with the configuration file policies/github-dsp.sarif-external-properties. + public const string LocationsMustProvideRequiredProperties = "SARIF2017"; + public const string InlineThreadFlowLocations = "SARIF2018"; + public const string RegionsMustProvideRequiredProperties = "SARIF2019"; + public const string ReviewArraysThatExceedConfigurableDefaults = "SARIF2020"; + public const string LocationsMustBeRelativeUrisOrFilePaths = "SARIF2021"; + public const string ProvideCheckoutPath = "SARIF2022"; + public const string RelatedLocationsMustProvideRequiredProperties = "SARIF2023"; + // TEMPLATE: // public const string RuleFriendlyName = "SARIFnnnn"; } diff --git a/src/Sarif.Multitool/Rules/RuleResources.Designer.cs b/src/Sarif.Multitool/Rules/RuleResources.Designer.cs index e687ec848..ce402a22b 100644 --- a/src/Sarif.Multitool/Rules/RuleResources.Designer.cs +++ b/src/Sarif.Multitool/Rules/RuleResources.Designer.cs @@ -760,5 +760,163 @@ internal static string SARIF2016_FileUrisShouldBeRelative_Note_Default_Text { return ResourceManager.GetString("SARIF2016_FileUrisShouldBeRelative_Note_Default_Text", resourceCulture); } } + + /// + /// Looks up a localized string similar to {0}: The 'locations' array is empty. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result.. + /// + internal static string SARIF2017_LocationsMustProvideRequiredProperties_Error_EmptyLocationsArray_Text { + get { + return ResourceManager.GetString("SARIF2017_LocationsMustProvideRequiredProperties_Error_EmptyLocationsArray_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: '{1}' is absent. The GitHub Developer Security Portal will not display a result location that does not provide the URI of the artifact that contains the result.. + /// + internal static string SARIF2017_LocationsMustProvideRequiredProperties_Error_MissingLocationProperty_Text { + get { + return ResourceManager.GetString("SARIF2017_LocationsMustProvideRequiredProperties_Error_MissingLocationProperty_Te" + + "xt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: The 'locations' property is absent. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result.. + /// + internal static string SARIF2017_LocationsMustProvideRequiredProperties_Error_NoLocationsArray_Text { + get { + return ResourceManager.GetString("SARIF2017_LocationsMustProvideRequiredProperties_Error_NoLocationsArray_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Each result location must provide the property 'physicalLocation.artifactLocation.uri'. The GitHub Developer Security Portal will not display a result whose location does not provide the URI of the artifact that contains the result.. + /// + internal static string SARIF2017_LocationsMustProvideRequiredProperties_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2017_LocationsMustProvideRequiredProperties_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: This 'threadFlowLocation' uses its 'index' property to refer to information in the 'run.threadFlowLocations' array. The GitHub Developer Security Portal will not display a result that includes such a 'threadFlowLocation'.. + /// + internal static string SARIF2018_InlineThreadFlowLocations_Error_Default_Text { + get { + return ResourceManager.GetString("SARIF2018_InlineThreadFlowLocations_Error_Default_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Results that include codeFlows must specify each threadFlowLocation directly within the codeFlow, rather than relying on threadFlowLocation.index to refer to an element of the run.threadFlowLocations array. The GitHub Developer Security Portal will not display a result that uses such threadFlowLocations.. + /// + internal static string SARIF2018_InlineThreadFlowLocations_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2018_InlineThreadFlowLocations_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: The 'region' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults.. + /// + internal static string SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegion_Text { + get { + return ResourceManager.GetString("SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegion_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: The 'startLine' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults.. + /// + internal static string SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegionProperty_Text { + get { + return ResourceManager.GetString("SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegionProperty_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Every result must provide a 'region' that specifies its location with line and optional column information. The GitHub Developer Security Portal can display the correct location only for results that provide this information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults.. + /// + internal static string SARIF2019_RegionsMustProvideRequiredProperties_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2019_RegionsMustProvideRequiredProperties_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: This array contains {1} element(s), which exceeds the default limit of {2} imposed by the GitHub Developer Security Portal. The portal will only display information up to that limit. You can provide a configuration file at the root of your repository to specify a higher limit.. + /// + internal static string SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Error_Default_Text { + get { + return ResourceManager.GetString("SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Error_Default_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The GitHub Developer Security Portal limits the amount of information it displays. There are limits on the number of runs per log file, rules per run, results per run, locations per result, code flows per result, and steps per code flow. You can provide a configuration file at the root of your repository to specify higher limits.. + /// + internal static string SARIF2020_ReviewArraysThatExceedConfigurableDefaults_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2020_ReviewArraysThatExceedConfigurableDefaults_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: '{1}' is not a file path. The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme.. + /// + internal static string SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Error_Default_Text { + get { + return ResourceManager.GetString("SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Error_Default_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme.. + /// + internal static string SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: This result location is expressed as an absolute 'file' URI. The GitHub Developer Security Portal will reject this file because it cannot determine the location of the repository root (which it refers to as the "checkout path"). Either express result locations as relative URI references with respect to the checkout path, place the checkout path in 'invocations[].workingDirectory`, or place the checkout path in a configuration file at the root of the repository.. + /// + internal static string SARIF2022_ProvideCheckoutPath_Error_Default_Text { + get { + return ResourceManager.GetString("SARIF2022_ProvideCheckoutPath_Error_Default_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The GitHub Developer Security Portal (DSP) will reject a SARIF file that expresses result locations as absolute 'file' scheme URIs unless the DSP can determine the URI of the repository root (which the DSP refers to as the "checkout path"). There are three ways to address this issue. + /// + ///1. Recommended: Express all result locations as relative URI references with respect to the checkout path. + /// + ///1. Place the checkout path in 'invocations[].workingDirectory'. The SARIF specification defines that property to b [rest of string was truncated]";. + /// + internal static string SARIF2022_ProvideCheckoutPath_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2022_ProvideCheckoutPath_FullDescription_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {0}: This related location does not have a 'message' property, so the the GitHub Developer Security Portal (DSP) will reject the entire log file. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location.. + /// + internal static string SARIF2023_RelatedLocationsMustProvideRequiredProperties_Error_Default_Text { + get { + return ResourceManager.GetString("SARIF2023_RelatedLocationsMustProvideRequiredProperties_Error_Default_Text", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The GitHub Developer Security Portal (DSP) will reject a SARIF file that includes a "related location" with no 'message' property. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location.. + /// + internal static string SARIF2023_RelatedLocationsMustProvideRequiredProperties_FullDescription_Text { + get { + return ResourceManager.GetString("SARIF2023_RelatedLocationsMustProvideRequiredProperties_FullDescription_Text", resourceCulture); + } + } } } diff --git a/src/Sarif.Multitool/Rules/RuleResources.resx b/src/Sarif.Multitool/Rules/RuleResources.resx index cdda46510..98724ce51 100644 --- a/src/Sarif.Multitool/Rules/RuleResources.resx +++ b/src/Sarif.Multitool/Rules/RuleResources.resx @@ -391,4 +391,61 @@ Semantics: Assuming the reader of the log file (an end user or another tool) has {0}: The file location '{1}' is specified with absolute URI. Prefer a relative reference together with a uriBaseId property. + + Each result location must provide the property 'physicalLocation.artifactLocation.uri'. The GitHub Developer Security Portal will not display a result whose location does not provide the URI of the artifact that contains the result. + + + {0}: '{1}' is absent. The GitHub Developer Security Portal will not display a result location that does not provide the URI of the artifact that contains the result. + + + {0}: The 'locations' array is empty. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result. + + + {0}: The 'locations' property is absent. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result. + + + {0}: This 'threadFlowLocation' uses its 'index' property to refer to information in the 'run.threadFlowLocations' array. The GitHub Developer Security Portal will not display a result that includes such a 'threadFlowLocation'. + + + Results that include codeFlows must specify each threadFlowLocation directly within the codeFlow, rather than relying on threadFlowLocation.index to refer to an element of the run.threadFlowLocations array. The GitHub Developer Security Portal will not display a result that uses such threadFlowLocations. + + + {0}: The 'startLine' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults. + + + {0}: The 'region' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults. + + + Every result must provide a 'region' that specifies its location with line and optional column information. The GitHub Developer Security Portal can display the correct location only for results that provide this information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults. + + + {0}: This array contains {1} element(s), which exceeds the default limit of {2} imposed by the GitHub Developer Security Portal. The portal will only display information up to that limit. You can provide a configuration file at the root of your repository to specify a higher limit. + + + The GitHub Developer Security Portal limits the amount of information it displays. There are limits on the number of runs per log file, rules per run, results per run, locations per result, code flows per result, and steps per code flow. You can provide a configuration file at the root of your repository to specify higher limits. + + + {0}: '{1}' is not a file path. The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme. + + + The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme. + + + The GitHub Developer Security Portal (DSP) will reject a SARIF file that expresses result locations as absolute 'file' scheme URIs unless the DSP can determine the URI of the repository root (which the DSP refers to as the "checkout path"). There are three ways to address this issue. + +1. Recommended: Express all result locations as relative URI references with respect to the checkout path. + +1. Place the checkout path in 'invocations[].workingDirectory'. The SARIF specification defines that property to be the working directory of the process that executed the analysis tool, so if the tool was not invoked from the repository root directory, it isn't strictly legal to place the checkout path there. + +2. Place the checkout path in a configuration file at the root of the repository. This requires the analysis tool always to be invoked from that same directory. + + + {0}: This result location is expressed as an absolute 'file' URI. The GitHub Developer Security Portal will reject this file because it cannot determine the location of the repository root (which it refers to as the "checkout path"). Either express result locations as relative URI references with respect to the checkout path, place the checkout path in 'invocations[].workingDirectory`, or place the checkout path in a configuration file at the root of the repository. + + + {0}: This related location does not have a 'message' property, so the the GitHub Developer Security Portal (DSP) will reject the entire log file. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location. + + + The GitHub Developer Security Portal (DSP) will reject a SARIF file that includes a "related location" with no 'message' property. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location. + \ No newline at end of file diff --git a/src/Sarif.Multitool/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs b/src/Sarif.Multitool/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs index 466883959..a915adead 100644 --- a/src/Sarif.Multitool/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs +++ b/src/Sarif.Multitool/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs @@ -43,7 +43,7 @@ public class ExpressUriBaseIdsCorrectly : SarifValidationSkimmerBase protected override void Analyze(ArtifactLocation artifactLocation, string artifactLocationPointer) { - if (artifactLocation.UriBaseId != null && artifactLocation.Uri.IsAbsoluteUri) + if (artifactLocation.UriBaseId != null && artifactLocation.Uri?.IsAbsoluteUri == true) { // {0}: This 'artifactLocation' object has a 'uriBaseId' property '{1}', but its // 'uri' property '{2}' is an absolute URI. Since the purpose of 'uriBaseId' is diff --git a/src/Sarif.Multitool/Rules/SARIF2008.ProvideSchema.cs b/src/Sarif.Multitool/Rules/SARIF2008.ProvideSchema.cs index d9613069b..d5bebe5f9 100644 --- a/src/Sarif.Multitool/Rules/SARIF2008.ProvideSchema.cs +++ b/src/Sarif.Multitool/Rules/SARIF2008.ProvideSchema.cs @@ -27,7 +27,7 @@ public class ProvideSchema : SarifValidationSkimmerBase protected override void Analyze(SarifLog log, string logPointer) { - if (!Context.InputLogToken.HasProperty("$schema")) + if (!Context.InputLogToken.HasProperty(SarifPropertyName.Schema)) { // {0}: The SARIF log file does not contain a '$schema' property. Add a '$schema' // property that refers to the final, OASIS standard version of the SARIF 2.1.0 diff --git a/src/Sarif.Multitool/Rules/SARIF2016.FileUrisShouldBeRelative.cs b/src/Sarif.Multitool/Rules/SARIF2016.FileUrisShouldBeRelative.cs index a53bc2e2c..70ecc0d5b 100644 --- a/src/Sarif.Multitool/Rules/SARIF2016.FileUrisShouldBeRelative.cs +++ b/src/Sarif.Multitool/Rules/SARIF2016.FileUrisShouldBeRelative.cs @@ -70,7 +70,7 @@ private void AnalyzeResultLocations(IList locations, string locationsP string locationPointer = locationsPointer.AtIndex(i); Location location = locations[i]; - if (location.PhysicalLocation?.ArtifactLocation.Uri != null) + if (location?.PhysicalLocation?.ArtifactLocation?.Uri != null) { if (location.PhysicalLocation.ArtifactLocation.Uri.IsAbsoluteUri && location.PhysicalLocation.ArtifactLocation.Uri.IsFile) { diff --git a/src/Sarif.Multitool/Rules/SARIF2017.LocationsMustProvideRequiredProperties.cs b/src/Sarif.Multitool/Rules/SARIF2017.LocationsMustProvideRequiredProperties.cs new file mode 100644 index 000000000..c45c90f8d --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2017.LocationsMustProvideRequiredProperties.cs @@ -0,0 +1,108 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class LocationsMustProvideRequiredProperties : SarifValidationSkimmerBase + { + /// + /// SARIF2017 + /// + public override string Id => RuleId.LocationsMustProvideRequiredProperties; + + /// + /// Each result location must provide the property 'physicalLocation.artifactLocation.uri'. + /// The GitHub Developer Security Portal will not display a result whose location does not + /// provide the URI of the artifact that was analyzed. + /// + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_NoLocationsArray_Text), + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_EmptyLocationsArray_Text), + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_MissingLocationProperty_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + protected override void Analyze(Result result, string resultPointer) + { + if (result.Locations == null) + { + // {0}: The 'locations' property is absent. The GitHub Developer Security Portal + // will not display a result unless it provides a location that specifies the URI + // of the artifact that contains the result. + LogResult( + resultPointer, + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_NoLocationsArray_Text), + SarifPropertyName.Locations); + return; + } + + string locationsPointer = resultPointer.AtProperty(SarifPropertyName.Locations); + if (!result.Locations.Any()) + { + // {0}: The 'locations' array is empty. The GitHub Developer Security Portal will + // not display a result unless it provides a location that specifies the URI of the + // artifact that contains the result. + LogResult( + locationsPointer, + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_EmptyLocationsArray_Text)); + return; + } + + for (int i = 0; i < result.Locations.Count; i++) + { + ValidateLocation(result.Locations[i], locationsPointer.AtIndex(i)); + } + + string relatedLocationsPointer = resultPointer.AtProperty(SarifPropertyName.RelatedLocations); + if (result.RelatedLocations?.Any() == true) + { + for (int i = 0; i < result.RelatedLocations.Count; i++) + { + ValidateLocation(result.RelatedLocations[i], relatedLocationsPointer.AtIndex(i)); + } + } + } + + private void ValidateLocation(Location location, string locationPointer) + { + string missingProperty = null; + + if (location.PhysicalLocation == null) + { + missingProperty = SarifPropertyName.PhysicalLocation; + } + else if (location.PhysicalLocation.ArtifactLocation == null) + { + missingProperty = SarifPropertyName.ArtifactLocation; + locationPointer = locationPointer.AtProperty(SarifPropertyName.PhysicalLocation); + } + else if (location.PhysicalLocation.ArtifactLocation.Uri == null) + { + missingProperty = SarifPropertyName.Uri; + locationPointer = locationPointer.AtProperty(SarifPropertyName.PhysicalLocation).AtProperty(SarifPropertyName.ArtifactLocation); + } + + if (missingProperty != null) + { + // {0}: The '{1}' property is absent. The GitHub Developer Security Portal will + // not display a result whose location does not provide the URI of the artifact + // that contains the result. + LogResult( + locationPointer, + nameof(RuleResources.SARIF2017_LocationsMustProvideRequiredProperties_Error_MissingLocationProperty_Text), + missingProperty); + } + } + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2018.InlineThreadFlowLocations.cs b/src/Sarif.Multitool/Rules/SARIF2018.InlineThreadFlowLocations.cs new file mode 100644 index 000000000..b5af33877 --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2018.InlineThreadFlowLocations.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class InlineThreadFlowLocations : SarifValidationSkimmerBase + { + /// + /// SARIF2018 + /// + public override string Id => RuleId.InlineThreadFlowLocations; + + /// + /// Results that include codeFlows must specify each threadFlowLocation directly within + /// the codeFlow, rather than relying on threadFlowLocation.index to refer to an element + /// of the run.threadFlowLocations array. The GitHub Developer Security Portal will not + /// display a result that uses such threadFlowLocations. + /// + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2018_InlineThreadFlowLocations_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2018_InlineThreadFlowLocations_Error_Default_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + protected override void Analyze(ThreadFlowLocation threadFlowLocation, string threadFlowLocationPointer) + { + if (threadFlowLocation.Index >= 0) + { + // {0}: This 'threadFlowLocation' uses its 'index' property to refer to information + // in the 'run.threadFlowLocations' array. The GitHub Developer Security Portal + // will not display a result that includes such a 'threadFlowLocation'. + LogResult( + threadFlowLocationPointer.AtProperty(SarifPropertyName.Index), + nameof(RuleResources.SARIF2018_InlineThreadFlowLocations_Error_Default_Text)); + return; + } + } + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2019.RegionsMustProvideRequiredProperties.cs b/src/Sarif.Multitool/Rules/SARIF2019.RegionsMustProvideRequiredProperties.cs new file mode 100644 index 000000000..f1e7615e8 --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2019.RegionsMustProvideRequiredProperties.cs @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class RegionsMustProvideRequiredProperties : SarifValidationSkimmerBase + { + /// + /// SARIF2019 + /// + public override string Id => RuleId.RegionsMustProvideRequiredProperties; + + // Every result must provide a 'region' that specifies its location with line and optional + // column information. The GitHub Developer Security Portal can display the correct + // location only for results that provide this information. At minimum, 'region.startLine' + // is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', + // although all of those have reasonable defaults. + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2019_RegionsMustProvideRequiredProperties_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegion_Text), + nameof(RuleResources.SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegionProperty_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + protected override void Analyze(Result result, string resultPointer) + { + if (!(result.Locations?.Any() == true)) + { + // Rule SARIF2017.LocationsMustProvideRequiredProperties will catch this, so don't + // report it here. + return; + } + + for (int i = 0; i < result.Locations.Count; i++) + { + Location location = result.Locations[i]; + PhysicalLocation physicalLocation = location.PhysicalLocation; + if (physicalLocation == null) + { + // Rule SARIF2017.LocationsMustProvideRequiredProperties will catch this, so don't + // report it here. + continue; + } + + if (physicalLocation.Region == null) + { + string physicalLocationPointer = resultPointer + .AtProperty(SarifPropertyName.Locations) + .AtIndex(i) + .AtProperty(SarifPropertyName.PhysicalLocation); + + // {0}: The 'region' property is absent. The GitHub Developer Security Portal + // can display the correct location only for results that provide a 'region' + // object with line and optional column information. At minimum, + // 'region.startLine' is required. 'region' can also provide 'startColumn', + // 'endLine', and 'endColumn', although all of those have reasonable defaults. + LogResult( + physicalLocationPointer, + nameof(RuleResources.SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegion_Text)); + } + else if (physicalLocation.Region.StartLine == 0) + { + string regionPointer = resultPointer + .AtProperty(SarifPropertyName.Locations) + .AtIndex(i) + .AtProperty(SarifPropertyName.PhysicalLocation) + .AtProperty(SarifPropertyName.Region); + + // {0}: The 'startLine' property is absent. The GitHub Developer Security + // Portal can display the correct location only for results that provide a + // 'region' object with line and optional column information. At minimum, + // 'region.startLine' is required. 'region' can also provide 'startColumn', + // 'endLine', and 'endColumn', although all of those have reasonable defaults. + LogResult( + regionPointer, + nameof(RuleResources.SARIF2019_RegionsMustProvideRequiredProperties_Error_MissingRegionProperty_Text)); + } + } + } + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2020.ReviewArraysThatExceedConfigurableDefaults.cs b/src/Sarif.Multitool/Rules/SARIF2020.ReviewArraysThatExceedConfigurableDefaults.cs new file mode 100644 index 000000000..ab8e0dd9f --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2020.ReviewArraysThatExceedConfigurableDefaults.cs @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; + +using Microsoft.Json.Pointer; + +// TODO: root location pointer is "" in the log file. Didn't I already change that to "root" (=> ""?)? + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class ReviewArraysThatExceedConfigurableDefaults : SarifValidationSkimmerBase + { + /// + /// SARIF2020 + /// + public override string Id => RuleId.ReviewArraysThatExceedConfigurableDefaults; + + // The GitHub Developer Security Portal limits the amount of information it displays. There + // are limits on the number of runs per log file, rules per run, results per run, locations + // per result, code flows per result, and steps per code flow. You can provide a configuration + // file at the root of your repository to specify higher limits. + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2020_ReviewArraysThatExceedConfigurableDefaults_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Error_Default_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + // Some of the actual limits are impractically large for testing purposes, so make them + // settable. + // + // We create a dictionary whose keys are pseudo-JSON pointers to arrays of limited size + // and whose values are the corresponding limits. The dictionary keys cannot be simply + // the array's property names, because those can collide (see below where two different + // dictionaries have the same property name 'locations'). They can't be the "real" JSON + // pointers, either, because those include varying array indices along the paths. So when + // given a real JSON pointer, we'll replace all the indicies with 0s, and use the result + // to look up the array's size limit. + internal static readonly string s_runsPerLogKey = $"/{SarifPropertyName.Runs}"; + internal static readonly string s_rulesPerRunKey = $"{s_runsPerLogKey}/0/{SarifPropertyName.Tool}/{SarifPropertyName.Driver}/{SarifPropertyName.Rules}"; + internal static readonly string s_resultsPerRunKey = $"{s_runsPerLogKey}/0/{SarifPropertyName.Results}"; + internal static readonly string s_locationsPerResultKey = $"{s_resultsPerRunKey}/0/{SarifPropertyName.Locations}"; + internal static readonly string s_codeFlowsPerResultKey = $"{s_resultsPerRunKey}/0/{SarifPropertyName.CodeFlows}"; + internal static readonly string s_locationsPerThreadFlowKey = $"{s_codeFlowsPerResultKey}/0/{SarifPropertyName.ThreadFlows}/0/{SarifPropertyName.Locations}"; + + internal static Dictionary s_arraySizeLimitDictionary = new Dictionary + { + [s_runsPerLogKey] = 5, + [s_rulesPerRunKey] = 1000, + [s_resultsPerRunKey] = 1000, + [s_locationsPerResultKey] = 10, + [s_codeFlowsPerResultKey] = 100, + [s_locationsPerThreadFlowKey] = 100 + }; + + protected override void Analyze(SarifLog sarifLog, string sarifLogPointer) + { + CheckArraySize( + sarifLog.Runs?.Count, + sarifLogPointer.AtProperty(SarifPropertyName.Runs)); + } + + protected override void Analyze(Run run, string runPointer) + { + CheckArraySize( + run.Tool.Driver.Rules?.Count, + runPointer + .AtProperty(SarifPropertyName.Tool) + .AtProperty(SarifPropertyName.Driver) + .AtProperty(SarifPropertyName.Rules)); + + CheckArraySize( + run.Results?.Count, + runPointer.AtProperty(SarifPropertyName.Results)); + } + + protected override void Analyze(Result result, string resultPointer) + { + CheckArraySize( + result.Locations?.Count, + resultPointer.AtProperty(SarifPropertyName.Locations)); + + CheckArraySize( + result.CodeFlows?.Count, + resultPointer.AtProperty(SarifPropertyName.CodeFlows)); + } + + protected override void Analyze(ThreadFlow threadFlow, string threadFlowPointer) + { + CheckArraySize( + threadFlow.Locations?.Count, + threadFlowPointer.AtProperty(SarifPropertyName.Locations)); + } + + private void CheckArraySize(int? actualSize, string arrayPointer) + { + string dictionaryKey = DictionaryKeyFromJsonPointer(arrayPointer); + if (actualSize.HasValue && actualSize.Value > s_arraySizeLimitDictionary[dictionaryKey]) + { + // {0}: This array contains {1} element(s), which exceeds the default limit of {2} + // imposed by the GitHub Developer Security Portal. The portal will only display + // information up to that limit. You can provide a configuration file at the root + // of your repository to specify a higher limit. + LogResult( + arrayPointer, + nameof(RuleResources.SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Error_Default_Text), + actualSize.Value.ToString(CultureInfo.InvariantCulture), + s_arraySizeLimitDictionary[dictionaryKey].ToString(CultureInfo.InvariantCulture)); + } + } + + private const string ArrayIndexPattern = @"/\d+"; + private static readonly Regex s_arrayIndexRegex = new Regex(ArrayIndexPattern, RegexOptions.Compiled | RegexOptions.CultureInvariant); + + private string DictionaryKeyFromJsonPointer(string jsonPointer) + => s_arrayIndexRegex.Replace(jsonPointer, "/0"); + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths.cs b/src/Sarif.Multitool/Rules/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths.cs new file mode 100644 index 000000000..d676a6dff --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class LocationsMustBeRelativeUrisOrFilePaths : SarifValidationSkimmerBase + { + /// + /// SARIF2021 + /// + public override string Id => RuleId.LocationsMustBeRelativeUrisOrFilePaths; + + // The GitHub Developer Security Portal only displays results whose locations are specified + // by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme. + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Error_Default_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + protected override void Analyze(Result result, string resultPointer) + { + if (!(result.Locations?.Any() == true)) + { + // Rule SARIF2017.LocationsMustProvideRequiredProperties will catch this, so don't + // report it here. + return; + } + + string locationsPointer = resultPointer.AtProperty(SarifPropertyName.Locations); + for (int i = 0; i < result.Locations.Count; i++) + { + ValidateLocation(result.Locations[i], locationsPointer.AtIndex(i)); + } + + string relatedLocationsPointer = resultPointer.AtProperty(SarifPropertyName.RelatedLocations); + if (result.RelatedLocations?.Any() == true) + { + for (int i = 0; i < result.RelatedLocations.Count; i++) + { + ValidateLocation(result.RelatedLocations[i], relatedLocationsPointer.AtIndex(i)); + } + } + } + + private void ValidateLocation(Location location, string locationPointer) + { + Uri uri = location?.PhysicalLocation?.ArtifactLocation?.Uri; + if (uri == null) + { + // Rule SARIF2017.LocationsMustProvideRequiredProperties will catch this, so don't + // report it here. + return; + } + + if (uri.IsAbsoluteUri && uri.Scheme != "file") + { + string uriPointer = locationPointer + .AtProperty(SarifPropertyName.PhysicalLocation) + .AtProperty(SarifPropertyName.ArtifactLocation) + .AtProperty(SarifPropertyName.Uri); + + // {0}: '{1}' is not a file path. The GitHub Developer Security Portal only + // displays results whose locations are specified by file paths, either as + // relative URIs or as absolute URIs that use the 'file' scheme. + LogResult( + uriPointer, + nameof(RuleResources.SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Error_Default_Text), + uri.OriginalString); + } + } + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2022.ProvideCheckoutPath.cs b/src/Sarif.Multitool/Rules/SARIF2022.ProvideCheckoutPath.cs new file mode 100644 index 000000000..669650656 --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2022.ProvideCheckoutPath.cs @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class ProvideCheckoutPath : SarifValidationSkimmerBase + { + /// + /// SARIF2022 + /// + public override string Id => RuleId.ProvideCheckoutPath; + + // The GitHub Developer Security Portal (DSP) will reject a SARIF file that expresses + // result locations as absolute 'file' scheme URIs unless the DSP can determine the URI + // of the repository root (which the DSP refers to as the "checkout path"). There are + // three ways to address this issue. + // + // 1. Recommended: Express all result locations as relative URI references with respect to + // the checkout path. + // + // 2. Place the checkout path in 'invocations[].workingDirectory'. The SARIF specification + // defines that property to be the working directory of the process that executed the + // analysis tool, so if the tool was not invoked from the repository root directory, it + // isn't strictly legal to place the checkout path there. + // + // 3. Place the checkout path in a configuration file at the root of the repository.This + // requires the analysis tool always to be invoked from that same directory. + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2022_ProvideCheckoutPath_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2022_ProvideCheckoutPath_Error_Default_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + private List checkoutPaths; + + protected override void Analyze(Run run, string runPointer) + { + this.checkoutPaths = GetCheckoutPaths(run); + } + + protected override void Analyze(Result result, string resultPointer) + { + if (result.Locations?.Any() == true) + { + string locationsPointer = resultPointer.AtProperty(SarifPropertyName.Locations); + for (int i = 0; i < result.Locations.Count; i++) + { + ValidateLocation(result.Locations[i], locationsPointer.AtIndex(i)); + } + } + + if (result.RelatedLocations?.Any() == true) + { + string relatedLocationsPointer = resultPointer.AtProperty(SarifPropertyName.RelatedLocations); + for (int i = 0; i < result.RelatedLocations.Count; i++) + { + ValidateLocation(result.RelatedLocations[i], relatedLocationsPointer.AtIndex(i)); + } + } + } + + private List GetCheckoutPaths(Run run) + { + var checkoutPaths = new List(); + + if (run.Invocations?.Any() == true) + { + foreach (Invocation invocation in run.Invocations) + { + // We are assuming that DSP only looks at the URI and doesn't try to resolve + // if through their (hypothetical) equivalent of the SDK's TryReconstructAbsoluteUri. + // We'll need to determine that experimentally. + if (invocation.WorkingDirectory?.Uri?.IsAbsoluteUri == true) + { + string absoluteUri = invocation.WorkingDirectory.Uri.AbsoluteUri; + absoluteUri = EnsureTrailingSlash(absoluteUri); + checkoutPaths.Add(absoluteUri); + } + } + } + + return checkoutPaths; + } + + private string EnsureTrailingSlash(string uri) + => uri.EndsWith("/") ? uri : uri + "/"; + + private void ValidateLocation(Location location, string locationPointer) + { + Uri uri = location?.PhysicalLocation?.ArtifactLocation?.Uri; + if (uri?.IsAbsoluteUri == true && uri.Scheme == "file") + { + if (!IsKnownCheckoutPath(uri.AbsoluteUri)) + { + // {0}: This result location is expressed as an absolute 'file' URI. The GitHub + // Developer Security Portal will reject this file because it cannot determine + // the location of the repository root (which it refers to as the "checkout + // path"). Either express result locations as relative URI references with + // respect to the checkout path, place the checkout path in 'invocations[].workingDirectory`, + // or place the checkout path in a configuration file at the root of the + // repository. + LogResult( + locationPointer + .AtProperty(SarifPropertyName.PhysicalLocation) + .AtProperty(SarifPropertyName.ArtifactLocation) + .AtProperty(SarifPropertyName.Uri), + nameof(RuleResources.SARIF2022_ProvideCheckoutPath_Error_Default_Text)); + } + } + } + + private bool IsKnownCheckoutPath(string absoluteUri) + => this.checkoutPaths.Any(cp => absoluteUri.StartsWith(cp)); + } +} diff --git a/src/Sarif.Multitool/Rules/SARIF2023.ProvideRequiredRelatedLocationProperties.cs b/src/Sarif.Multitool/Rules/SARIF2023.ProvideRequiredRelatedLocationProperties.cs new file mode 100644 index 000000000..e925be70a --- /dev/null +++ b/src/Sarif.Multitool/Rules/SARIF2023.ProvideRequiredRelatedLocationProperties.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using System.Linq; + +using Microsoft.Json.Pointer; + +namespace Microsoft.CodeAnalysis.Sarif.Multitool.Rules +{ + public class RelatedLocationsMustProvideRequiredProperties : SarifValidationSkimmerBase + { + /// + /// SARIF2023 + /// + public override string Id => RuleId.RelatedLocationsMustProvideRequiredProperties; + + // The GitHub Developer Security Portal (DSP) will reject a SARIF file that includes a + // "related location" with no 'message' property. This is a bug in the DSP. You can set + // 'message' to an empty string if you don't have anything else to say about the location. + public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2023_RelatedLocationsMustProvideRequiredProperties_FullDescription_Text }; + + protected override IEnumerable MessageResourceNames => new string[] { + nameof(RuleResources.SARIF2023_RelatedLocationsMustProvideRequiredProperties_Error_Default_Text) + }; + + public override FailureLevel DefaultLevel => FailureLevel.Error; + + public override bool EnabledByDefault => false; + + protected override void Analyze(Result result, string resultPointer) + { + if (result.RelatedLocations?.Any() == true) + { + string relatedLocationsPointer = resultPointer.AtProperty(SarifPropertyName.RelatedLocations); + for (int i = 0; i < result.RelatedLocations.Count; i++) + { + ValidateRelatedLocation(result.RelatedLocations[i], relatedLocationsPointer.AtIndex(i)); + } + } + } + + private void ValidateRelatedLocation(Location relatedLocation, string relatedLocationPointer) + { + if (relatedLocation.Message == null) + { + // {0}: This related location does not have a 'message' property, so the the GitHub + // Developer Security Portal (DSP) will reject the entire log file. This is a bug + // in the DSP. You can set 'message' to an empty string if you don't have anything + // else to say about the location. + LogResult( + relatedLocationPointer, + nameof(RuleResources.SARIF2023_RelatedLocationsMustProvideRequiredProperties_Error_Default_Text)); + } + } + } +} diff --git a/src/Sarif.Multitool/Rules/SarifValidationSkimmerBase.cs b/src/Sarif.Multitool/Rules/SarifValidationSkimmerBase.cs index 10f50764a..fd920c010 100644 --- a/src/Sarif.Multitool/Rules/SarifValidationSkimmerBase.cs +++ b/src/Sarif.Multitool/Rules/SarifValidationSkimmerBase.cs @@ -47,7 +47,7 @@ protected void LogResult(string jPointer, string formatId, params string[] args) { Region region = GetRegionFromJPointer(jPointer); - // All messages start with "In {file}, at {jPointer}, ...". Prepend the jPointer to the args. + // All messages start with "{jPointer}: ...". Prepend the jPointer to the args. string[] argsWithPointer = new string[args.Length + 1]; Array.Copy(args, 0, argsWithPointer, 1, args.Length); argsWithPointer[0] = JsonPointerToJavaScript(jPointer); diff --git a/src/Sarif.Sdk.sln b/src/Sarif.Sdk.sln index eb39841e6..e19387366 100644 --- a/src/Sarif.Sdk.sln +++ b/src/Sarif.Sdk.sln @@ -110,6 +110,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ValidationRules", "Validati ..\docs\ValidationRules\RULEID.RULEFRIENDLYNAME.cs = ..\docs\ValidationRules\RULEID.RULEFRIENDLYNAME.cs EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "policies", "policies", "{C2397737-B10C-42BF-B2AB-11A86817ACCD}" + ProjectSection(SolutionItems) = preProject + ..\policies\github-dsp.config.sarif-external-properties = ..\policies\github-dsp.config.sarif-external-properties + ..\policies\github-dsp.config.xml = ..\policies\github-dsp.config.xml + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -322,6 +328,7 @@ Global {A2D43A0B-F2ED-42A5-A980-D6F4476FE455} = {7D46D6BE-C3CD-424C-9A20-245DE63A9C10} {6EEAC61E-A362-4C46-A9AD-00EDB74CFCF2} = {BBDE0751-B8A3-4EA6-A3DF-3CE7BA41EA0F} {81910EAA-C010-4940-90E5-BF64DE64381C} = {6EEAC61E-A362-4C46-A9AD-00EDB74CFCF2} + {C2397737-B10C-42BF-B2AB-11A86817ACCD} = {BBDE0751-B8A3-4EA6-A3DF-3CE7BA41EA0F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9EFA21E3-70A0-467C-9D1F-D5AD0DC1C1E6} diff --git a/src/Sarif/Core/ReportingDescriptor.cs b/src/Sarif/Core/ReportingDescriptor.cs index 5a1ad756d..a0081c10d 100644 --- a/src/Sarif/Core/ReportingDescriptor.cs +++ b/src/Sarif/Core/ReportingDescriptor.cs @@ -9,6 +9,20 @@ namespace Microsoft.CodeAnalysis.Sarif { public partial class ReportingDescriptor { + public string Moniker + { + get + { + string moniker = this.Id; + if (!string.IsNullOrWhiteSpace(this.Name)) + { + moniker += $".{this.Name}"; + } + + return moniker; + } + } + public string Format(string messageId, IEnumerable arguments) { return string.Format(CultureInfo.CurrentCulture, this.MessageStrings[messageId].Text, arguments.ToArray()); diff --git a/src/Sarif/PerLanguageOption.cs b/src/Sarif/PerLanguageOption.cs index c8053bf51..7f81a6fef 100644 --- a/src/Sarif/PerLanguageOption.cs +++ b/src/Sarif/PerLanguageOption.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Sarif public class PerLanguageOption : IOption { /// - /// A description of this specificoption. + /// A description of this specific option. /// public string Description { get; } diff --git a/src/Test.FunctionalTests.Sarif/Multitool/ValidateCommandTests.cs b/src/Test.FunctionalTests.Sarif/Multitool/ValidateCommandTests.cs index e87823649..ef2297fc0 100644 --- a/src/Test.FunctionalTests.Sarif/Multitool/ValidateCommandTests.cs +++ b/src/Test.FunctionalTests.Sarif/Multitool/ValidateCommandTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using FluentAssertions; @@ -21,10 +22,15 @@ using Xunit; using Xunit.Abstractions; +using static Microsoft.CodeAnalysis.Sarif.Multitool.Rules.ReviewArraysThatExceedConfigurableDefaults; + namespace Microsoft.CodeAnalysis.Sarif.FunctionalTests.Multitool { public class ValidateCommandTests : FileDiffingFunctionalTests { + private const string ValidTestFileNameSuffix = "_Valid.sarif"; + private const string InvalidTestFileNameSuffix = "_Invalid.sarif"; + private readonly IList validationRules; public ValidateCommandTests(ITestOutputHelper outputHelper, bool testProducesSarifCurrentVersion = true) : @@ -267,8 +273,94 @@ public void SARIF2016_FileUrisShouldBeRelative_Valid() public void SARIF2016_FileUrisShouldBeRelative_Invalid() => RunInvalidTestForRule(RuleId.FileUrisShouldBeRelative); - private const string ValidTestFileNameSuffix = "_Valid.sarif"; - private const string InvalidTestFileNameSuffix = "_Invalid.sarif"; + [Fact] + public void SARIF2017_LocationsMustProvideRequiredProperties_Valid() + => RunValidTestForRule(RuleId.LocationsMustProvideRequiredProperties); + + [Fact] + public void SARIF2017_LocationsMustProvideRequiredProperties_Invalid() + => RunInvalidTestForRule(RuleId.LocationsMustProvideRequiredProperties); + + [Fact] + public void SARIF2018_InlineThreadFlowLocations_Valid() + => RunValidTestForRule(RuleId.InlineThreadFlowLocations); + + [Fact] + public void SARIF2018_InlineThreadFlowLocations_Invalid() + => RunInvalidTestForRule(RuleId.InlineThreadFlowLocations); + + [Fact] + public void SARIF2019_RegionsMustProvideRequiredProperties_Valid() + => RunValidTestForRule(RuleId.RegionsMustProvideRequiredProperties); + + [Fact] + public void SARIF2019_RegionsMustProvideRequiredProperties_Invalid() + => RunInvalidTestForRule(RuleId.RegionsMustProvideRequiredProperties); + + [Fact] + public void SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Valid() + => RunArrayLimitTest(ValidTestFileNameSuffix); + + [Fact] + public void SARIF2020_ReviewArraysThatExceedConfigurableDefaults_Invalid() + => RunArrayLimitTest(InvalidTestFileNameSuffix); + + [Fact] + public void SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Valid() + => RunValidTestForRule(RuleId.LocationsMustBeRelativeUrisOrFilePaths); + + [Fact] + public void SARIF2021_LocationsMustBeRelativeUrisOrFilePaths_Invalid() + => RunInvalidTestForRule(RuleId.LocationsMustBeRelativeUrisOrFilePaths); + + [Fact] + public void SARIF2022_ProvideCheckoutPath_Valid() + => RunValidTestForRule(RuleId.ProvideCheckoutPath); + + [Fact] + public void SARIF2022_ProvideCheckoutPath_Invalid() + => RunInvalidTestForRule(RuleId.ProvideCheckoutPath); + + [Fact] + public void SARIF2023_RelatedLocationsMustProvideRequiredProperties_Valid() + => RunValidTestForRule(RuleId.RelatedLocationsMustProvideRequiredProperties); + + [Fact] + public void SARIF2023_RelatedLocationsMustProvideRequiredProperties_Invalid() + => RunInvalidTestForRule(RuleId.RelatedLocationsMustProvideRequiredProperties); + + private void RunArrayLimitTest(string testFileNameSuffix) + { + // Some of the actual limits are impractically large for testing purposes, + // so the following test will set smaller values. + int savedMaxRuns = s_arraySizeLimitDictionary[s_runsPerLogKey]; + int savedMaxRules = s_arraySizeLimitDictionary[s_rulesPerRunKey]; + int savedMaxResults = s_arraySizeLimitDictionary[s_resultsPerRunKey]; + int savedMaxResultLocations = s_arraySizeLimitDictionary[s_locationsPerResultKey]; + int savedMaxCodeFlows = s_arraySizeLimitDictionary[s_codeFlowsPerResultKey]; + int savedMaxThreadFlowLocations = s_arraySizeLimitDictionary[s_locationsPerThreadFlowKey]; + + try + { + s_arraySizeLimitDictionary[s_runsPerLogKey] = 1; + s_arraySizeLimitDictionary[s_rulesPerRunKey] = 1; + s_arraySizeLimitDictionary[s_resultsPerRunKey] = 1; + s_arraySizeLimitDictionary[s_locationsPerResultKey] = 1; + s_arraySizeLimitDictionary[s_codeFlowsPerResultKey] = 1; + s_arraySizeLimitDictionary[s_locationsPerThreadFlowKey] = 1; + + RunTestForRule(RuleId.ReviewArraysThatExceedConfigurableDefaults, testFileNameSuffix); + } + finally + { + s_arraySizeLimitDictionary[s_runsPerLogKey] = savedMaxRuns; + s_arraySizeLimitDictionary[s_rulesPerRunKey] = savedMaxRules; + s_arraySizeLimitDictionary[s_resultsPerRunKey] = savedMaxResults; + s_arraySizeLimitDictionary[s_locationsPerResultKey] = savedMaxResultLocations; + s_arraySizeLimitDictionary[s_codeFlowsPerResultKey] = savedMaxCodeFlows; + s_arraySizeLimitDictionary[s_locationsPerThreadFlowKey] = savedMaxThreadFlowLocations; + } + } private void RunValidTestForRule(string ruleId) => RunTestForRule(ruleId, ValidTestFileNameSuffix); @@ -278,11 +370,14 @@ private void RunInvalidTestForRule(string ruleId) private void RunTestForRule(string ruleId, string testFileNameSuffix) { - SarifValidationSkimmerBase rule = this.validationRules.Single(vr => vr.Id == ruleId); + SarifValidationSkimmerBase rule = GetRuleFromId(ruleId); string testFileName = MakeTestFileName(rule, testFileNameSuffix); RunTest(testFileName); } + private SarifValidationSkimmerBase GetRuleFromId(string ruleId) + => this.validationRules.Single(vr => vr.Id == ruleId); + private string MakeTestFileName(ReportingDescriptor rule, string testFileNameSuffix) => $"{rule.Id}.{rule.Name}{testFileNameSuffix}"; @@ -306,7 +401,7 @@ protected override string ConstructTestOutputFromInputResource(string inputResou string[] shouldNotTransform = { "SARIF1011", "SARIF2008" }; - bool updateInputsToCurrentSarif = ruleUnderTest.StartsWith("SARIF") + bool updateInputsToCurrentSarif = IsSarifRule(ruleUnderTest) && !shouldNotTransform.Contains(ruleUnderTest); var validateOptions = new ValidateOptions @@ -329,18 +424,25 @@ protected override string ConstructTestOutputFromInputResource(string inputResou mockFileSystem.Setup(x => x.ReadAllText(inputLogFilePath)).Returns(v2LogText); mockFileSystem.Setup(x => x.ReadAllText(It.IsNotIn(inputLogFilePath))).Returns(path => File.ReadAllText(path)); mockFileSystem.Setup(x => x.WriteAllText(It.IsAny(), It.IsAny())); - mockFileSystem.Setup(x => x.FileExists(validateOptions.ConfigurationFilePath)).Returns(true); - var validateCommand = new ValidateCommand(mockFileSystem.Object); + // Some rules are disabled by default, so create a configuration file that explicitly + // enables the rule under test. + using (TempFile configFile = CreateTempConfigFile(ruleUnderTest)) + { + validateOptions.ConfigurationFilePath = configFile.Name; + mockFileSystem.Setup(x => x.FileExists(validateOptions.ConfigurationFilePath)).Returns(true); - int returnCode = validateCommand.Run(validateOptions); + var validateCommand = new ValidateCommand(mockFileSystem.Object); - if (validateCommand.ExecutionException != null) - { - Console.WriteLine(validateCommand.ExecutionException.ToString()); - } + int returnCode = validateCommand.Run(validateOptions); + + if (validateCommand.ExecutionException != null) + { + Console.WriteLine(validateCommand.ExecutionException.ToString()); + } - returnCode.Should().Be(0); + returnCode.Should().Be(0); + } string actualLogFileContents = File.ReadAllText(actualLogFilePath); SarifLog actualLog = JsonConvert.DeserializeObject(actualLogFileContents); @@ -391,6 +493,52 @@ protected override string ConstructTestOutputFromInputResource(string inputResou return JsonConvert.SerializeObject(actualLog, Formatting.Indented); } + private static bool IsSarifRule(string ruleId) + => ruleId.StartsWith("SARIF"); + + private TempFile CreateTempConfigFile(string ruleId) + { + var sb = new StringBuilder(); + sb.AppendLine(""); + sb.AppendLine(""); + + if (IsSarifRule(ruleId)) + { + SarifValidationSkimmerBase rule = GetRuleFromId(ruleId); + RuleEnabledState ruleEnabledState = GetRuleEnabledState(rule); + + sb.AppendLine($" "); + sb.AppendLine($" "); + sb.AppendLine(" "); + } + + sb.AppendLine(""); + + var tempFile = new TempFile(".xml"); + File.WriteAllText(tempFile.Name, sb.ToString()); + return tempFile; + } + + private static RuleEnabledState GetRuleEnabledState(ReportingDescriptor rule) + { + FailureLevel? declaredLevel = rule.DefaultConfiguration?.Level; + + if (declaredLevel.HasValue) + { + return declaredLevel.Value switch + { + FailureLevel.Error => RuleEnabledState.Error, + FailureLevel.Warning => RuleEnabledState.Warning, + FailureLevel.Note => RuleEnabledState.Note, + _ => throw new ArgumentException("Non-failure validation rules are not yet supported.", rule.Moniker), + }; + } + else + { + return RuleEnabledState.Warning; + } + } + private IList GetValidationRules() { // Select one rule arbitrarily, find out what assembly it's in, and get all the other diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1002.UrisMustBeValid_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1002.UrisMustBeValid_Invalid.sarif index a66702049..8552eb661 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1002.UrisMustBeValid_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1002.UrisMustBeValid_Invalid.sarif @@ -24,6 +24,9 @@ "text": "{0}: The 'file' URI '{1}' contains a '..' segment. This is dangerous because if symbolic links are present, '..' might have different meanings on the machine that produced the log file and the machine where an end user or a tool consumes it." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif index d396c8b48..9f94d6a97 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif @@ -33,6 +33,9 @@ "text": "{0}: The '{1}' element of 'originalUriBaseIds' has a 'uri' property '{2}' that contains a query or a fragment. This is not valid because the purpose of the 'uriBaseId' property is to help resolve a relative reference to an absolute URI by concatenating the relative reference to the absolute base URI. This won't work if the base URI contains a query or a fragment." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1005.UriMustBeAbsolute_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1005.UriMustBeAbsolute_Invalid.sarif index fd7900580..6e957906d 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1005.UriMustBeAbsolute_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1005.UriMustBeAbsolute_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The value of this property is required to be an absolute URI, but '{1}' is a relative URI reference." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1006.InvocationPropertiesMustBeConsistent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1006.InvocationPropertiesMustBeConsistent_Invalid.sarif index daf33a7df..e7d56bb2e 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1006.InvocationPropertiesMustBeConsistent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1006.InvocationPropertiesMustBeConsistent_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The 'endTimeUtc' value '{1}' precedes the 'startTimeUtc' value '{2}'. The properties of an 'invocation' object must be internally consistent." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1007.RegionPropertiesMustBeConsistent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1007.RegionPropertiesMustBeConsistent_Invalid.sarif index d44dd910a..28c02cf63 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1007.RegionPropertiesMustBeConsistent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1007.RegionPropertiesMustBeConsistent_Invalid.sarif @@ -27,6 +27,9 @@ "text": "{0}: This 'region' object does not specify 'startLine', 'charOffset', or 'byteOffset'. As a result, it is impossible to determine whether this 'region' object describes a line/column text region, a character offset/length text region, or a binary region." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1008.PhysicalLocationPropertiesMustBeConsistent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1008.PhysicalLocationPropertiesMustBeConsistent_Invalid.sarif index a725d69d7..7aedad08c 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1008.PhysicalLocationPropertiesMustBeConsistent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1008.PhysicalLocationPropertiesMustBeConsistent_Invalid.sarif @@ -24,6 +24,9 @@ "text": "{0}: This 'physicalLocation' object contains both a 'region' and a 'contextRegion' property, but 'contextRegion' is not a proper superset of 'region'. This is invalid because the purpose of 'contextRegion' is to provide a viewing context around the 'region' which is the location of the result. It's possible that the tool reversed 'region' and 'contextRegion'. If 'region' and 'contextRegion' are identical, the tool must omit 'contextRegion'." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1009.IndexPropertiesMustBeConsistentWithArrays_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1009.IndexPropertiesMustBeConsistentWithArrays_Invalid.sarif index 2a8214582..bd9b5ccd8 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1009.IndexPropertiesMustBeConsistentWithArrays_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1009.IndexPropertiesMustBeConsistentWithArrays_Invalid.sarif @@ -24,6 +24,9 @@ "text": "{0}: This '{1}' object contains a property '{2}' with value {3}, but '{4}' has fewer than {5} elements. An index-valued properties must be valid for the array that it refers to." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1010.RuleIdMustBeConsistent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1010.RuleIdMustBeConsistent_Invalid.sarif index 433680b2f..21059a85f 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1010.RuleIdMustBeConsistent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1010.RuleIdMustBeConsistent_Invalid.sarif @@ -24,6 +24,9 @@ "text": "{0}: This result contains neither of the properties 'ruleId' or 'rule.id'. The SARIF specification ([§3.27.5](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317643)) requires at least one of these properties to be present." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1011.ReferenceFinalSchema_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1011.ReferenceFinalSchema_Invalid.sarif index 5105a29c9..0153095fb 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1011.ReferenceFinalSchema_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1011.ReferenceFinalSchema_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The '$schema' property value '{1}' does not refer to the final version of the SARIF 2.1.0 schema. If you are using an earlier version of the SARIF format, consider upgrading your analysis tool to produce the final version. If this file does in fact conform to the final version of the schema, upgrade the tool to populate the '$schema' property with a URL that refers to the final version of the schema." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1012.MessageArgumentsMustBeConsistentWithRule_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1012.MessageArgumentsMustBeConsistentWithRule_Invalid.sarif index 75ea2fc8d..80da91563 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1012.MessageArgumentsMustBeConsistentWithRule_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF1012.MessageArgumentsMustBeConsistentWithRule_Invalid.sarif @@ -24,6 +24,9 @@ "text": "{0}: The message with id '{1}' in rule '{2}' requires '{3}' arguments, but the 'arguments' array in this message object has only '{4}' element(s). When a tool creates a result message that use the 'id' and 'arguments' properties, it must ensure that the 'arguments' array has enough elements to provide values for every replacement sequence in the message specified by 'id'. For example, if the highest numbered replacement sequence in the specified message string is '{{3}}', then the 'arguments' array must contain 4 elements." } }, + "defaultConfiguration": { + "level": "error" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2002.ProvideMessageArguments_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2002.ProvideMessageArguments_Invalid.sarif index 2feda6048..500c895d4 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2002.ProvideMessageArguments_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2002.ProvideMessageArguments_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The 'message' property of this result contains a 'text' property. Consider replacing it with 'id' and 'arguments' properties. This potentially reduces the log file size, allows the message text to be improved without modifying the log file, and enables localization." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2003.ProvideVersionControlProvenance_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2003.ProvideVersionControlProvenance_Invalid.sarif index ad312c3cb..19af41350 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2003.ProvideVersionControlProvenance_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2003.ProvideVersionControlProvenance_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: This run does not provide 'versionControlProvenance'. As a result, it is not possible to determine which version of code was analyzed, nor to map relative paths to their locations within the repository." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2006.UrisShouldBeReachable_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2006.UrisShouldBeReachable_Invalid.sarif index 480b37165..8dacf74cc 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2006.UrisShouldBeReachable_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2006.UrisShouldBeReachable_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The URI '{1}' was not reachable via an HTTP GET request." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2009.ConsiderConventionalIdentifierValues_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2009.ConsiderConventionalIdentifierValues_Invalid.sarif index b10286fae..60b131637 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2009.ConsiderConventionalIdentifierValues_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2009.ConsiderConventionalIdentifierValues_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The 'id' property of the rule '{1}' does not follow the recommended format: a short string identifying the tool concatenated with a numeric rule number, for example, 'CS2001'. Using a conventional format for the rule id provides a more uniform experience across tools." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2010.ProvideCodeSnippets_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2010.ProvideCodeSnippets_Invalid.sarif index 404115705..1213e4324 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2010.ProvideCodeSnippets_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2010.ProvideCodeSnippets_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The 'region' object in this result location does not provide a 'snippet' property. Providing a code snippet enables users to see the code that triggered the result, even if they are not enlisted in the code." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2011.ProvideContextRegion_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2011.ProvideContextRegion_Invalid.sarif index 9b9f3e18a..dfe8b75bf 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2011.ProvideContextRegion_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2011.ProvideContextRegion_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: This result location does not provide a 'contextRegion' property. Providing a context region enables users to see a portion of the code that surrounds the result, even if they are not enlisted in the code." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2012.ProvideHelpUris_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2012.ProvideHelpUris_Invalid.sarif index 7e0cf2bf2..d846c37e3 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2012.ProvideHelpUris_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2012.ProvideHelpUris_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The rule '{1}' does not provide a help URI. Providing a URI where users can find detailed information about the rule helps users to understand the result and how they can best address it." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2013.ProvideEmbeddedFileContent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2013.ProvideEmbeddedFileContent_Invalid.sarif index 268347284..941d71c54 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2013.ProvideEmbeddedFileContent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2013.ProvideEmbeddedFileContent_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: This run does not provide embedded file content. Providing embedded file content enables users to examine results in their full context without having to enlist in the source repository. Embedding file content in a SARIF log file can dramatically increase its size, so consider the usage scenario when you decide whether to provide it." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2014.ProvideDynamicMessageContent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2014.ProvideDynamicMessageContent_Invalid.sarif index 4ba4392bd..7872f0e1b 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2014.ProvideDynamicMessageContent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2014.ProvideDynamicMessageContent_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: In rule '{1}', the message with id '{2}' does not include any dynamic content. Dynamic content makes your messages more specific and avoids the \"wall of bugs\" phenomenon, where hundreds of occurrences of the same message appear unapproachable." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2015.EnquoteDynamicMessageContent_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2015.EnquoteDynamicMessageContent_Invalid.sarif index 8dfa33701..0d8c95a4e 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2015.EnquoteDynamicMessageContent_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2015.EnquoteDynamicMessageContent_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: In rule '{1}', the message with id '{2}' includes dynamic content that is not enclosed in single quotes. Enquoting dynamic content makes it easier to spot, and single quotes give a less cluttered appearance." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2016.FileUrisShouldBeRelative_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2016.FileUrisShouldBeRelative_Invalid.sarif index 6d3b42d81..22cfc0679 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2016.FileUrisShouldBeRelative_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2016.FileUrisShouldBeRelative_Invalid.sarif @@ -21,6 +21,9 @@ "text": "{0}: The file location '{1}' is specified with absolute URI. Prefer a relative reference together with a uriBaseId property." } }, + "defaultConfiguration": { + "level": "note" + }, "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" } ] diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..2fb557a21 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,206 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2017", + "name": "LocationsMustProvideRequiredProperties", + "shortDescription": { + "text": "Each result location must provide the property 'physicalLocation.artifactLocation.uri'." + }, + "fullDescription": { + "text": "Each result location must provide the property 'physicalLocation.artifactLocation.uri'. The GitHub Developer Security Portal will not display a result whose location does not provide the URI of the artifact that contains the result." + }, + "messageStrings": { + "Error_NoLocationsArray": { + "text": "{0}: The 'locations' property is absent. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result." + }, + "Error_EmptyLocationsArray": { + "text": "{0}: The 'locations' array is empty. The GitHub Developer Security Portal will not display a result unless it provides a location that specifies the URI of the artifact that contains the result." + }, + "Error_MissingLocationProperty": { + "text": "{0}: '{1}' is absent. The GitHub Developer Security Portal will not display a result location that does not provide the URI of the artifact that contains the result." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_NoLocationsArray", + "arguments": [ + "runs[0].results[0]", + "locations" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 20, + "startColumn": 9 + } + } + } + ] + }, + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_EmptyLocationsArray", + "arguments": [ + "runs[0].results[1].locations" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 31, + "startColumn": 24 + } + } + } + ] + }, + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingLocationProperty", + "arguments": [ + "runs[0].results[2].locations[0]", + "physicalLocation" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 39, + "startColumn": 13 + } + } + } + ] + }, + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingLocationProperty", + "arguments": [ + "runs[0].results[2].locations[1].physicalLocation", + "artifactLocation" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 50, + "startColumn": 35 + } + } + } + ] + }, + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingLocationProperty", + "arguments": [ + "runs[0].results[2].locations[2].physicalLocation.artifactLocation", + "uri" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 61, + "startColumn": 37 + } + } + } + ] + }, + { + "ruleId": "SARIF2017", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingLocationProperty", + "arguments": [ + "runs[0].results[2].relatedLocations[0].physicalLocation.artifactLocation", + "uri" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 73, + "startColumn": 37 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..e28af9387 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif new file mode 100644 index 000000000..4a7a2d395 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif @@ -0,0 +1,75 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2018", + "name": "InlineThreadFlowLocations", + "shortDescription": { + "text": "Results that include codeFlows must specify each threadFlowLocation directly within the codeFlow, rather than relying on threadFlowLocation.index to refer to an element of the run.threadFlowLocations array." + }, + "fullDescription": { + "text": "Results that include codeFlows must specify each threadFlowLocation directly within the codeFlow, rather than relying on threadFlowLocation.index to refer to an element of the run.threadFlowLocations array. The GitHub Developer Security Portal will not display a result that uses such threadFlowLocations." + }, + "messageStrings": { + "Error_Default": { + "text": "{0}: This 'threadFlowLocation' uses its 'index' property to refer to information in the 'run.threadFlowLocations' array. The GitHub Developer Security Portal will not display a result that includes such a 'threadFlowLocation'." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2018.InlineThreadFlowLocations_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2018", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].codeFlows[0].threadFlows[0].locations[0].index" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 33, + "startColumn": 32 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif new file mode 100644 index 000000000..74487c6f3 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2018.InlineThreadFlowLocations_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..a1f246cf8 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,126 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2019", + "name": "RegionsMustProvideRequiredProperties", + "shortDescription": { + "text": "Every result must provide a 'region' that specifies its location with line and optional column information." + }, + "fullDescription": { + "text": "Every result must provide a 'region' that specifies its location with line and optional column information. The GitHub Developer Security Portal can display the correct location only for results that provide this information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults." + }, + "messageStrings": { + "Error_MissingRegion": { + "text": "{0}: The 'region' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults." + }, + "Error_MissingRegionProperty": { + "text": "{0}: The 'startLine' property is absent. The GitHub Developer Security Portal can display the correct location only for results that provide a 'region' object with line and optional column information. At minimum, 'region.startLine' is required. 'region' can also provide 'startColumn', 'endLine', and 'endColumn', although all of those have reasonable defaults." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2019", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingRegion", + "arguments": [ + "runs[0].results[0].locations[0].physicalLocation" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 20, + "startColumn": 35 + } + } + } + ] + }, + { + "ruleId": "SARIF2019", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingRegionProperty", + "arguments": [ + "runs[0].results[0].locations[1].physicalLocation.region" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 34, + "startColumn": 27 + } + } + } + ] + }, + { + "ruleId": "SARIF2019", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_MissingRegionProperty", + "arguments": [ + "runs[0].results[0].locations[2].physicalLocation.region" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 48, + "startColumn": 27 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..d25d36c40 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif new file mode 100644 index 000000000..ed4877f29 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif @@ -0,0 +1,207 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2020", + "name": "ReviewArraysThatExceedConfigurableDefaults", + "shortDescription": { + "text": "The GitHub Developer Security Portal limits the amount of information it displays." + }, + "fullDescription": { + "text": "The GitHub Developer Security Portal limits the amount of information it displays. There are limits on the number of runs per log file, rules per run, results per run, locations per result, code flows per result, and steps per code flow. You can provide a configuration file at the root of your repository to specify higher limits." + }, + "messageStrings": { + "Error_Default": { + "text": "{0}: This array contains {1} element(s), which exceeds the default limit of {2} imposed by the GitHub Developer Security Portal. The portal will only display information up to that limit. You can provide a configuration file at the root of your repository to specify a higher limit." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 4, + "startColumn": 11 + } + } + } + ] + }, + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].tool.driver.rules", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 9, + "startColumn": 20 + } + } + } + ] + }, + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 29, + "startColumn": 18 + } + } + } + ] + }, + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].locations", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 35, + "startColumn": 24 + } + } + } + ] + }, + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].codeFlows", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 51, + "startColumn": 24 + } + } + } + ] + }, + { + "ruleId": "SARIF2020", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].codeFlows[0].threadFlows[0].locations", + "2", + "1" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 55, + "startColumn": 32 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif new file mode 100644 index 000000000..221c03e12 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif new file mode 100644 index 000000000..dcbd5aa8a --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif @@ -0,0 +1,101 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2021", + "name": "LocationsMustBeRelativeUrisOrFilePaths", + "shortDescription": { + "text": "The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme." + }, + "fullDescription": { + "text": "The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme." + }, + "messageStrings": { + "Error_Default": { + "text": "{0}: '{1}' is not a file path. The GitHub Developer Security Portal only displays results whose locations are specified by file paths, either as relative URIs or as absolute URIs that use the 'file' scheme." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2021", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri", + "https://www.example.com/code/file.cs" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 22, + "startColumn": 63 + } + } + } + ] + }, + { + "ruleId": "SARIF2021", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].relatedLocations[0].physicalLocation.artifactLocation.uri", + "https://www.example.com/code/file.cs" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 31, + "startColumn": 63 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif new file mode 100644 index 000000000..03b7aa0d0 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif new file mode 100644 index 000000000..a50ebf01d --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif @@ -0,0 +1,99 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2022", + "name": "ProvideCheckoutPath", + "shortDescription": { + "text": "The GitHub Developer Security Portal (DSP) will reject a SARIF file that expresses result locations as absolute 'file' scheme URIs unless the DSP can determine the URI of the repository root (which the DSP refers to as the \"checkout path\")." + }, + "fullDescription": { + "text": "The GitHub Developer Security Portal (DSP) will reject a SARIF file that expresses result locations as absolute 'file' scheme URIs unless the DSP can determine the URI of the repository root (which the DSP refers to as the \"checkout path\"). There are three ways to address this issue.\r\n\r\n1. Recommended: Express all result locations as relative URI references with respect to the checkout path.\r\n\r\n1. Place the checkout path in 'invocations[].workingDirectory'. The SARIF specification defines that property to be the working directory of the process that executed the analysis tool, so if the tool was not invoked from the repository root directory, it isn't strictly legal to place the checkout path there.\r\n\r\n2. Place the checkout path in a configuration file at the root of the repository. This requires the analysis tool always to be invoked from that same directory." + }, + "messageStrings": { + "Error_Default": { + "text": "{0}: This result location is expressed as an absolute 'file' URI. The GitHub Developer Security Portal will reject this file because it cannot determine the location of the repository root (which it refers to as the \"checkout path\"). Either express result locations as relative URI references with respect to the checkout path, place the checkout path in 'invocations[].workingDirectory`, or place the checkout path in a configuration file at the root of the repository." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2022.ProvideCheckoutPath_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2022", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 30, + "startColumn": 50 + } + } + } + ] + }, + { + "ruleId": "SARIF2022", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].relatedLocations[0].physicalLocation.artifactLocation.uri" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 39, + "startColumn": 50 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Valid.sarif new file mode 100644 index 000000000..9f381bb39 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2022.ProvideCheckoutPath_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2022.ProvideCheckoutPath_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..9a0150994 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,75 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing", + "rules": [ + { + "id": "SARIF2023", + "name": "RelatedLocationsMustProvideRequiredProperties", + "shortDescription": { + "text": "The GitHub Developer Security Portal (DSP) will reject a SARIF file that includes a \"related location\" with no 'message' property." + }, + "fullDescription": { + "text": "The GitHub Developer Security Portal (DSP) will reject a SARIF file that includes a \"related location\" with no 'message' property. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location." + }, + "messageStrings": { + "Error_Default": { + "text": "{0}: This related location does not have a 'message' property, so the the GitHub Developer Security Portal (DSP) will reject the entire log file. This is a bug in the DSP. You can set 'message' to an empty string if you don't have anything else to say about the location." + } + }, + "defaultConfiguration": { + "enabled": false, + "level": "error" + }, + "helpUri": "http://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [ + { + "ruleId": "SARIF2023", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_Default", + "arguments": [ + "runs[0].results[0].relatedLocations[0]" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 28, + "startColumn": 13 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..a9ee33e6a --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/ExpectedOutputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "SARIF Functional Testing" + } + }, + "invocations": [ + { + "executionSuccessful": true + } + ], + "artifacts": [ + { + "location": { + "uri": "FunctionalTestOutput.ValidateCommand/Inputs.SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif", + "uriBaseId": "TEST_DIR" + } + } + ], + "results": [], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..7b9c46180 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,84 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "artifacts": [ + { + "location": { + "uri": "file.c" + } + } + ], + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "No locations array." + } + }, + { + "ruleId": "TEST1001", + "message": { + "text": "Empty locations array." + }, + "locations": [] + }, + { + "ruleId": "TEST1001", + "message": { + "text": "Locations with missing properties." + }, + "locations": [ + { + "properties": { + "comment": "Location with no physicalLocation" + }, + "logicalLocations": [ + { + "fullyQualifiedName": "the::logical::location" + } + ] + }, + { + "properties": { + "comment": "Location with no physicalLocation.artifactLocation" + }, + "physicalLocation": { + "address": { + "absoluteAddress": 1024 + } + } + }, + { + "properties": { + "comment": "Location with no physicalLocation.artifactLocation.uri" + }, + "physicalLocation": { + "artifactLocation": { + "index": 0 + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..020ff3f3e --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2017.LocationsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,41 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Testing." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif new file mode 100644 index 000000000..55e4391ce --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Invalid.sarif @@ -0,0 +1,57 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Testing." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "index": 0 + } + ] + } + ] + } + ] + } + ], + "threadFlowLocations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + }, + "importance": "essential" + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif new file mode 100644 index 000000000..c87db8fac --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2018.InlineThreadFlowLocations_Valid.sarif @@ -0,0 +1,52 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Testing." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file.c" + } + } + }, + "importance": "essential" + } + ] + } + ] + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..c15ac027e --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,63 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Locations with missing region properties." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "properties": { + "comment": "Location with no region." + } + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "charOffset": 12, + "charLength": 42 + } + }, + "properties": { + "comment": "Location specified by charOffset/Length." + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "byteOffset": 24, + "byteLength": 84 + }, + "properties": { + "comment": "Location with binary region." + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..d8d72d6be --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2019.RegionsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,35 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Location with required region properties." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "startLine": 12 + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif new file mode 100644 index 000000000..78f1bcffb --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Invalid.sarif @@ -0,0 +1,124 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "rules": [ + { + "id": "TEST1001", + "messageStrings": { + "Default": { + "text": "Message." + } + } + }, + { + "id": "TEST1002", + "messageStrings": { + "Default": { + "text": "Message." + } + } + } + ] + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "id": "Default." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + } + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file2.c" + } + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "startLine": 42 + } + } + } + }, + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file2.cs" + }, + "region": { + "startLine": 54 + } + } + } + } + ] + } + ] + }, + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "startLine": 42 + } + } + } + } + ] + } + ] + } + ] + }, + { + "ruleId": "TEST1001", + "message": { + "text": "Message." + } + } + ], + "columnKind": "utf16CodeUnits" + }, + { + "tool": { + "driver": { + "name": "Sarif Functional Testing" + } + }, + "results": [] + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif new file mode 100644 index 000000000..a09715f0a --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2020.ReviewArraysThatExceedConfigurableDefaults_Valid.sarif @@ -0,0 +1,63 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "rules": [ + { + "id": "TEST1001", + "messageStrings": { + "Default": { + "text": "Message." + } + } + } + ] + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "id": "Default." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + } + } + } + ], + "codeFlows": [ + { + "threadFlows": [ + { + "locations": [ + { + "location": { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + }, + "region": { + "startLine": 42 + } + } + } + } + ] + } + ] + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif new file mode 100644 index 000000000..c221a3180 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Invalid.sarif @@ -0,0 +1,41 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "A location that does not specify a file path." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "https://www.example.com/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "https://www.example.com/code/file.cs" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif new file mode 100644 index 000000000..d19fa7a66 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2021.LocationsMustBeRelativeUrisOrFilePaths_Valid.sarif @@ -0,0 +1,55 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Locations that specify file paths." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + } + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file.cs" + } + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///c:/code/file.cs" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif new file mode 100644 index 000000000..12f2c07d6 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Invalid.sarif @@ -0,0 +1,49 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "invocations": [ + { + "workingDirectory": { + "uri": "file:///C:/code" + }, + "executionSuccessful": true + } + ], + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Message." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///D:/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///D:/code/file.cs" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Valid.sarif new file mode 100644 index 000000000..d203d3fd1 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2022.ProvideCheckoutPath_Valid.sarif @@ -0,0 +1,62 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "invocations": [ + { + "workingDirectory": { + "uri": "file:///C:/code" + }, + "executionSuccessful": true + }, + { + "workingDirectory": { + "uri": "file:///D:/code" + }, + "executionSuccessful": true + } + ], + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Message." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///D:/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif new file mode 100644 index 000000000..32b6622f9 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Invalid.sarif @@ -0,0 +1,41 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Message." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif new file mode 100644 index 000000000..36cddab98 --- /dev/null +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF2023.RelatedLocationsMustProvideRequiredProperties_Valid.sarif @@ -0,0 +1,44 @@ +{ + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.5.json", + "version": "2.1.0", + "runs": [ + { + "tool": { + "driver": { + "name": "Sarif Functional Testing", + "version": "1.0" + } + }, + "results": [ + { + "ruleId": "TEST1001", + "message": { + "text": "Message." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + } + } + ], + "relatedLocations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///C:/code/file.cs" + } + }, + "message": { + "text": "" + } + } + ] + } + ], + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/src/build.props b/src/build.props index 7cc7a8296..c8cc3263c 100644 --- a/src/build.props +++ b/src/build.props @@ -20,8 +20,8 @@ having all the relevant values in one place. This property is actually used by the PowerShell script that hides ("delists") the previous package versions on nuget.org. --> - 2.3.3 - 2.3.2 + 2.3.4 + 2.3.3 2.1.0-rtm.5