diff --git a/src/Sarif.Multitool.Library/Rules/RuleResources.Designer.cs b/src/Sarif.Multitool.Library/Rules/RuleResources.Designer.cs index 58dc91f63..63a082531 100644 --- a/src/Sarif.Multitool.Library/Rules/RuleResources.Designer.cs +++ b/src/Sarif.Multitool.Library/Rules/RuleResources.Designer.cs @@ -264,6 +264,16 @@ internal static string SARIF1002_UrisMustBeValid_FullDescription_Text { } } + /// + /// Looks up a localized string similar to The relative reference '{0}' begins with a slash, which will prevent it from combining properly with the absolute URI specified by a 'uriBaseId'.. + /// + internal static string SARIF1004_ExpressUriBaseIdsCorrectly_Error_RelativeReferenceMustNotBeginWithSlash_Text { + get { + return ResourceManager.GetString("SARIF1004_ExpressUriBaseIdsCorrectly_Error_RelativeReferenceMustNotBeginWithSlash" + + "_Text", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0}: The '{1}' element of 'originalUriBaseIds' has no 'uriBaseId' property, but its 'uri' property '{2}' is not an absolute URI. According to the SARIF specification, every such "top-level" entry in 'originalUriBaseIds' must specify an absolute URI, because the purpose of 'originalUriBaseIds' is to enable the resolution of relative references to absolute URIs.. /// diff --git a/src/Sarif.Multitool.Library/Rules/RuleResources.resx b/src/Sarif.Multitool.Library/Rules/RuleResources.resx index 2cac2c25f..13d819b67 100644 --- a/src/Sarif.Multitool.Library/Rules/RuleResources.resx +++ b/src/Sarif.Multitool.Library/Rules/RuleResources.resx @@ -155,7 +155,9 @@ This is part of a set of authoring practices that make your rule messages more r If an 'artifactLocation' object has a 'uriBaseId' property, its 'uri' property must be a relative reference, because if 'uri' is an absolute URI then 'uriBaseId' serves no purpose. -Every URI reference in 'originalUriBaseIds' must resolve to an absolute URI in the manner described in the SARIF specification [3.14.14](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317498). +Every URI reference in 'originalUriBaseIds' must resolve to an absolute URI in the manner described in the SARIF specification [3.14.14](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317498). + +Finally, a relative reference in 'artifactLocation.uri' must not begin with a slash, because that prevents it from combining properly with the absolute URI specified by a 'uriBaseId'. {0}: The value of this property is required to be an absolute URI, but '{1}' is a relative URI reference. @@ -461,4 +463,7 @@ Semantics: Assuming the reader of the log file (an end user or another tool) has {0}: '{1}' is not a Pascal identifier. For uniformity of experience across all tools that produce SARIF, the friendly name should be a single Pascal identifier, for example, 'ProvideRuleFriendlyName'. + + The relative reference '{0}' begins with a slash, which will prevent it from combining properly with the absolute URI specified by a 'uriBaseId'. + \ No newline at end of file diff --git a/src/Sarif.Multitool.Library/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs b/src/Sarif.Multitool.Library/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs index a915adead..9774609dc 100644 --- a/src/Sarif.Multitool.Library/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs +++ b/src/Sarif.Multitool.Library/Rules/SARIF1004.ExpressUriBaseIdsCorrectly.cs @@ -28,6 +28,9 @@ public class ExpressUriBaseIdsCorrectly : SarifValidationSkimmerBase /// Every URI reference in 'originalUriBaseIds' must resolve to an absolute URI in the manner /// described in the SARIF specification /// [3.14.14] (https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317498). + /// + /// Finally, a relative reference in 'artifactLocation.uri' must not begin with a slash, because + /// that prevents it from combining properly with the absolute URI specified by a 'uriBaseId'. /// public override MultiformatMessageString FullDescription => new MultiformatMessageString { Text = RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_FullDescription_Text }; @@ -36,14 +39,18 @@ public class ExpressUriBaseIdsCorrectly : SarifValidationSkimmerBase nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_TopLevelUriBaseIdMustBeAbsolute_Text), nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_UriBaseIdValueMustEndWithSlash_Text), nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_UriBaseIdValueMustNotContainDotDotSegment_Text), - nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_UriBaseIdValueMustNotContainQueryOrFragment_Text) + nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_UriBaseIdValueMustNotContainQueryOrFragment_Text), + nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_RelativeReferenceMustNotBeginWithSlash_Text) }; public override FailureLevel DefaultLevel => FailureLevel.Error; protected override void Analyze(ArtifactLocation artifactLocation, string artifactLocationPointer) { - if (artifactLocation.UriBaseId != null && artifactLocation.Uri?.IsAbsoluteUri == true) + Uri artifactLocationUri = artifactLocation.Uri; + if (artifactLocationUri == null) { return; } + + if (artifactLocation.UriBaseId != null && artifactLocationUri.IsAbsoluteUri) { // {0}: This 'artifactLocation' object has a 'uriBaseId' property '{1}', but its // 'uri' property '{2}' is an absolute URI. Since the purpose of 'uriBaseId' is @@ -55,6 +62,16 @@ protected override void Analyze(ArtifactLocation artifactLocation, string artifa artifactLocation.UriBaseId, artifactLocation.Uri.OriginalString); } + + if (!artifactLocationUri.IsAbsoluteUri && artifactLocationUri.OriginalString.StartsWith("/") == true) + { + // The relative reference '{0}' begins with a slash, which will prevent it from combining properly + // with the absolute URI specified by a 'uriBaseId'. + LogResult( + artifactLocationPointer.AtProperty(SarifPropertyName.Uri), + nameof(RuleResources.SARIF1004_ExpressUriBaseIdsCorrectly_Error_RelativeReferenceMustNotBeginWithSlash_Text), + artifactLocation.Uri.OriginalString); + } } protected override void Analyze(Run run, string runPointer) 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 9f94d6a97..67bd25207 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 @@ -14,7 +14,7 @@ "text": "When using the 'uriBaseId' property, obey the requirements in the SARIF specification [3.4.4](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317431) that enable it to fulfill its purpose of resolving relative references to absolute locations." }, "fullDescription": { - "text": "When using the 'uriBaseId' property, obey the requirements in the SARIF specification [3.4.4](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317431) that enable it to fulfill its purpose of resolving relative references to absolute locations. In particular:\r\n\r\nIf an 'artifactLocation' object has a 'uriBaseId' property, its 'uri' property must be a relative reference, because if 'uri' is an absolute URI then 'uriBaseId' serves no purpose.\r\n\r\nEvery URI reference in 'originalUriBaseIds' must resolve to an absolute URI in the manner described in the SARIF specification [3.14.14](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317498)." + "text": "When using the 'uriBaseId' property, obey the requirements in the SARIF specification [3.4.4](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317431) that enable it to fulfill its purpose of resolving relative references to absolute locations. In particular:\r\n\r\nIf an 'artifactLocation' object has a 'uriBaseId' property, its 'uri' property must be a relative reference, because if 'uri' is an absolute URI then 'uriBaseId' serves no purpose.\r\n\r\nEvery URI reference in 'originalUriBaseIds' must resolve to an absolute URI in the manner described in the SARIF specification [3.14.14](https://docs.oasis-open.org/sarif/sarif/v2.1.0/os/sarif-v2.1.0-os.html#_Toc34317498).\r\n\r\nFinally, a relative reference in 'artifactLocation.uri' must not begin with a slash, because that prevents it from combining properly with the absolute URI specified by a 'uriBaseId'." }, "messageStrings": { "Error_UriBaseIdRequiresRelativeUri": { @@ -31,6 +31,9 @@ }, "Error_UriBaseIdValueMustNotContainQueryOrFragment": { "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." + }, + "Error_RelativeReferenceMustNotBeginWithSlash": { + "text": "The relative reference '{0}' begins with a slash, which will prevent it from combining properly with the absolute URI specified by a 'uriBaseId'." } }, "defaultConfiguration": { @@ -334,7 +337,7 @@ "index": 0 }, "region": { - "startLine": 217, + "startLine": 224, "startColumn": 35 } } @@ -367,6 +370,31 @@ } ] }, + { + "ruleId": "SARIF1004", + "ruleIndex": 0, + "level": "error", + "message": { + "id": "Error_RelativeReferenceMustNotBeginWithSlash", + "arguments": [ + "runs[0].results[0].locations[1].physicalLocation.artifactLocation.uri", + "/leading_slash.c" + ] + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "index": 0 + }, + "region": { + "startLine": 171, + "startColumn": 43 + } + } + } + ] + }, { "ruleId": "SARIF1004", "ruleIndex": 0, @@ -386,7 +414,7 @@ "index": 0 }, "region": { - "startLine": 193, + "startLine": 200, "startColumn": 47 } } @@ -412,7 +440,7 @@ "index": 0 }, "region": { - "startLine": 226, + "startLine": 233, "startColumn": 37 } } @@ -438,7 +466,7 @@ "index": 0 }, "region": { - "startLine": 175, + "startLine": 182, "startColumn": 43 } } @@ -464,7 +492,7 @@ "index": 0 }, "region": { - "startLine": 208, + "startLine": 215, "startColumn": 37 } } @@ -490,7 +518,7 @@ "index": 0 }, "region": { - "startLine": 237, + "startLine": 244, "startColumn": 39 } } diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif index ce94b0f50..c431b4eb6 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Invalid.sarif @@ -164,6 +164,14 @@ "uriBaseId": "%SRCROOT%" } } + }, + { + "physicalLocation": { + "artifactLocation": { + "uri": "/leading_slash.c" + + } + } } ], "stacks": [ diff --git a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Valid.sarif b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Valid.sarif index cd28b112c..f8a44d7e2 100644 --- a/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Valid.sarif +++ b/src/Test.FunctionalTests.Sarif/TestData/Multitool/ValidateCommand/Inputs/SARIF1004.ExpressUriBaseIdsCorrectly_Valid.sarif @@ -77,19 +77,19 @@ "uriBaseId": "%SRCROOT%" }, "stdin": { - "uri": "/c:/log/in.txt", + "uri": "log/in.txt", "uriBaseId": "%SRCROOT%" }, "stdout": { - "uri": "/c:/log/out.txt", + "uri": "log/out.txt", "uriBaseId": "%SRCROOT%" }, "stderr": { - "uri": "/c:/log/err.txt", + "uri": "log/err.txt", "uriBaseId": "%SRCROOT%" }, "stdoutStderr": { - "uri": "/c:/log/out-err.txt", + "uri": "log/out-err.txt", "uriBaseId": "%SRCROOT%" } } @@ -112,7 +112,7 @@ "repositoryUri": "https://github.com/example-corp/browser", "revisionId": "de67ef7", "mappedTo": { - "uri": "/browser", + "uri": "browser", "uriBaseId": "%SRCROOT%" } }