Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce GitHub DSP analysis rules #2021

Merged
merged 44 commits into from
Aug 6, 2020
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9407fc6
Bump version; update release history.
Jul 30, 2020
79abb3a
Add GitHub DSP policy file.
Jul 30, 2020
f15178e
Merge branch 'master' into users/lgolding/dsp-rules-2
Jul 30, 2020
72b8cbd
Fix broken functional test.
Jul 30, 2020
fee99c9
Add user-facing strings for SARIF2017.
Jul 30, 2020
88fec5e
Define rule id for SARIF2017.
Jul 30, 2020
8c321cc
Introduce SARIF2017.LocationsMustHaveRequiredProperties.
Jul 30, 2020
07a7233
Add "valid" functional test for SARIF2017.LocationsMustHaveRequiredPr…
Jul 30, 2020
f94e54c
Add "invalid" functional test for SARIF2017.LocationsMustHaveRequired…
Jul 30, 2020
038c641
Cover case where result.locations is empty.
Jul 30, 2020
e3b030d
Move location property bags up to expose JPointer bug.
Jul 30, 2020
fa59293
Introduce Skimmer.EnabledByDefault
Jul 30, 2020
37685f6
Skimmer: Populate DefaultConfiguration so it appears in rule metadata.
Jul 30, 2020
0e3afc2
Don't execute default-disabled rules unless the configuration enables…
Jul 31, 2020
a0c36b6
Add first rule to policy file; add file to solution.
Jul 31, 2020
f162209
Add DSP XML config file.
Jul 31, 2020
31ab5bd
Remove associated tool GUID from SARIF config file.
Jul 31, 2020
57118bf
Update solution file for renamed policy file.
Jul 31, 2020
42f444d
Adjust line numbers to fix test broken by JPointer bug.
Jul 31, 2020
4e468ec
Update a comment.
Jul 31, 2020
0fa413d
Merge branch 'master' into users/lgolding/dsp-rules-2
Jul 31, 2020
a304d93
Rename misnamed resource strings.
Jul 31, 2020
4708c2c
Implement SARIF2018.InlineThreadFlowLocations.
Jul 31, 2020
18e3912
Implement SARIF2019.RegionsMustProvideRequiredProperties.
Jul 31, 2020
27ef72a
Update policy files for SARIF2019.
Jul 31, 2020
0db7e86
Implement SARIF2020.ReviewArraysThatExceedConfigurableDefaults.
Aug 1, 2020
6947dcb
Fix broken formatted messages; improve messages.
Aug 1, 2020
ac534bb
Fix naming errors in policy files and a bug in SARIF2019.
Aug 2, 2020
43bfc60
Implement SARIF2021.LocationsMustBeRelativeUrisOrFilePaths.
Aug 2, 2020
59a345e
Implement SARIF2022.ProvideCheckoutPath.
Aug 3, 2020
b05eb59
SARIF2017 now covers related locations.
Aug 3, 2020
b6ea1b9
SARIF2017: Add tests for relatedLocations.
Aug 3, 2020
fd9973b
SARIF2017: Really add relatedLocations logic this time.
Aug 3, 2020
173e3d7
Rename "policy" files to "config".
Aug 4, 2020
6a6e24e
Protect SARIF1004 against a null ref.
Aug 4, 2020
02646b4
Correct user-facing strings for SARIF2019 to match DSP behavior.
Aug 4, 2020
a1de09c
Improve user-facing strings for SARIF2021.
Aug 4, 2020
b7052ea
Avoid null ref in SARIF2022.
Aug 4, 2020
a50f065
Implement SARIF2023.RelatedLocationsMustProvideRequiredProperties.
Aug 4, 2020
6268f27
Update test for changed message.
Aug 4, 2020
6fdf5e0
Fix typo in summary comment.
Aug 4, 2020
1f1f0c2
Merge branch 'master' into users/lgolding/dsp-rules-2
Aug 4, 2020
661fafb
Refactor SARIF2021 to prepare for related locations.
Aug 5, 2020
1c5a33e
Apply SARIF2021 to related locations.
Aug 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions policies/github-dsp-policy.config.sarif-external-properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"$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": "LocationsMustHaveRequiredProperties",
"defaultConfiguration": {
"enabled": true
}
}
]
}
]
}
6 changes: 6 additions & 0 deletions policies/github-dsp-policy.config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Properties>
<Properties Key='SARIF2017.LocationsMustHaveRequiredProperties.Options'>
<Property Key='RuleEnabled' Value='Error' />
</Properties>
</Properties>
4 changes: 4 additions & 0 deletions src/ReleaseHistory.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# SARIF Package Release History (SDK, Driver, Converters, and Multitool)

## **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`.
Expand Down
12 changes: 9 additions & 3 deletions src/Sarif.Driver/Sdk/AnalyzeCommandBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -546,12 +546,12 @@ protected virtual void AnalyzeTargets(
TContext rootContext,
IEnumerable<string> targets)
{
SortedSet<string> disabledSkimmers = new SortedSet<string>();
var disabledSkimmers = new SortedSet<string>();

foreach (Skimmer<TContext> skimmer in skimmers)
{
PerLanguageOption<RuleEnabledState> ruleEnabledProperty;
ruleEnabledProperty = DefaultDriverOptions.CreateRuleSpecificOption(skimmer, DefaultDriverOptions.RuleEnabled);
PerLanguageOption<RuleEnabledState> ruleEnabledProperty =
DefaultDriverOptions.CreateRuleSpecificOption(skimmer, DefaultDriverOptions.RuleEnabled);

RuleEnabledState ruleEnabled = rootContext.Policy.GetProperty(ruleEnabledProperty);

Expand All @@ -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())
Expand Down
9 changes: 7 additions & 2 deletions src/Sarif.Driver/Sdk/RuleEnabledState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum RuleEnabledState
Disabled = 0x1,

/// <summary>
/// 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.
/// </summary>
Expand All @@ -31,6 +31,11 @@ public enum RuleEnabledState
/// <summary>
/// User has elevated all failures from a check to errors.
/// </summary>
Error = 0x4
Error = 0x4,

/// <summary>
/// User has reduced all signal from a rule to notes.
/// </summary>
Note = 0x8
}
}
9 changes: 8 additions & 1 deletion src/Sarif.Driver/Sdk/Skimmer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public abstract class Skimmer<TContext> : ReportingDescriptor
public Skimmer()
{
this.Options = new Dictionary<string, string>();
this.DefaultConfiguration = new ReportingConfiguration
{
Level = this.DefaultLevel,
Enabled = this.EnabledByDefault
};
}

private IDictionary<string, MultiformatMessageString> multiformatMessageStrings;
Expand All @@ -20,7 +25,9 @@ public Skimmer()

protected virtual IEnumerable<string> 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<string, MultiformatMessageString> MessageStrings
{
Expand Down
5 changes: 5 additions & 0 deletions src/Sarif.Multitool/Rules/RuleId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ 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 LocationsMustHaveRequiredProperties = "SARIF2017";

// TEMPLATE:
// public const string RuleFriendlyName = "SARIFnnnn";
}
Expand Down
36 changes: 36 additions & 0 deletions src/Sarif.Multitool/Rules/RuleResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/Sarif.Multitool/Rules/RuleResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -391,4 +391,16 @@ Semantics: Assuming the reader of the log file (an end user or another tool) has
<data name="SARIF2016_FileUrisShouldBeRelative_Note_Default_Text" xml:space="preserve">
<value>{0}: The file location '{1}' is specified with absolute URI. Prefer a relative reference together with a uriBaseId property.</value>
</data>
<data name="SARIF2017_LocationsMustHaveRequiredProperties_FullDescription_Text" xml:space="preserve">
<value>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.</value>
</data>
<data name="SARIF2017_LocationsMustHaveRequired_Properties_Error_Default_Text" xml:space="preserve">
<value>{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.</value>
</data>
<data name="SARIF2017_LocationsMustHaveRequired_Properties_Error_EmptyLocationsArray_Text" xml:space="preserve">
<value>{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.</value>
</data>
<data name="SARIF2017_LocationsMustHaveRequired_Properties_Error_NoLocationsArray_Text" xml:space="preserve">
<value>{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.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private void AnalyzeResultLocations(IList<Location> 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)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// 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 LocationsMustHaveRequiredProperties : SarifValidationSkimmerBase
{
/// <summary>
/// SARIF2017
/// </summary>
public override string Id => RuleId.LocationsMustHaveRequiredProperties;

/// <summary>
/// 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.
/// </summary>
public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF2017_LocationsMustHaveRequiredProperties_FullDescription_Text };

protected override IEnumerable<string> MessageResourceNames => new string[] {
nameof(RuleResources.SARIF2017_LocationsMustHaveRequired_Properties_Error_NoLocationsArray_Text),
nameof(RuleResources.SARIF2017_LocationsMustHaveRequired_Properties_Error_EmptyLocationsArray_Text),
nameof(RuleResources.SARIF2017_LocationsMustHaveRequired_Properties_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 == 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_LocationsMustHaveRequired_Properties_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_LocationsMustHaveRequired_Properties_Error_EmptyLocationsArray_Text));
return;
}

for (int i = 0; i < result.Locations.Count; i++)
{
Location location = result.Locations[i];
string missingProperty = null;
string jsonPointer = null;
Copy link
Collaborator

@eddynaka eddynaka Jul 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string jsonPointer = null [](start = 16, length = 25)

I would start jsonPointer as LocationPointer.AtIndex(i), since every place you have that. Then, update the other places below to specific cases when necessary. #ByDesign

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose to do it this way because otherwise, we unnecessarily calculate .AtIndex(i) for every location in every result in the log file. This way, we only calculate it in the rare case where the rule fires.


In reply to: 463585630 [](ancestors = 463585630)


if (location.PhysicalLocation == null)
{
missingProperty = SarifPropertyName.PhysicalLocation;
jsonPointer = locationsPointer.AtIndex(i);
}
else if (location.PhysicalLocation.ArtifactLocation == null)
{
missingProperty = SarifPropertyName.ArtifactLocation;
jsonPointer = locationsPointer.AtIndex(i).AtProperty(SarifPropertyName.PhysicalLocation);
}
else if (location.PhysicalLocation.ArtifactLocation.Uri == null)
{
missingProperty = SarifPropertyName.Uri;
jsonPointer = locationsPointer.AtIndex(i).AtProperty(SarifPropertyName.PhysicalLocation).AtProperty(SarifPropertyName.ArtifactLocation);
}

if (missingProperty != null)
{
Debug.Assert(jsonPointer != 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(
jsonPointer,
nameof(RuleResources.SARIF2017_LocationsMustHaveRequired_Properties_Error_Default_Text),
missingProperty);
}
}
}
}
}
7 changes: 7 additions & 0 deletions src/Sarif.Sdk.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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-policy.config.xml = ..\policies\github-dsp-policy.config.xml
..\policies\github-dsp-policy.sarif-external-properties = ..\policies\github-dsp-policy.sarif-external-properties
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -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}
Expand Down
14 changes: 14 additions & 0 deletions src/Sarif/Core/ReportingDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> arguments)
{
return string.Format(CultureInfo.CurrentCulture, this.MessageStrings[messageId].Text, arguments.ToArray());
Expand Down
2 changes: 1 addition & 1 deletion src/Sarif/PerLanguageOption.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.Sarif
public class PerLanguageOption<T> : IOption
{
/// <summary>
/// A description of this specificoption.
/// A description of this specific option.
/// </summary>
public string Description { get; }

Expand Down
Loading