예제 #1
0
        protected override void AnalyzeTarget(
            IEnumerable <Skimmer <SarifValidationContext> > skimmers,
            SarifValidationContext context,
            HashSet <string> disabledSkimmers)
        {
            // The base class knows how to invoke the skimmers that implement smart validation,
            // but it doesn't know how to invoke schema validation, which has its own set of rules,
            // so we do that ourselves.
            //
            // Validate will return false if there are any JSON syntax errors. In that case
            // there's no point in going on.
            bool ok = Validate(context.TargetUri.LocalPath, context.SchemaFilePath, context.Logger);

            if (ok)
            {
                // Deserialize will return null if there are any JSON deserialization errors
                // (which can happen, for example, if a property required by the schema is
                // missing. In that case, again, there's no point in going on.
                string sarifText = FileSystem.ReadAllText(context.TargetUri.OriginalString);

                PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                    context.InputLogContents,
                    formatting: Formatting.None,
                    out sarifText);

                context.InputLogContents = sarifText;
                context.InputLog         = context.InputLogContents != null?Deserialize(context.InputLogContents) : null;

                if (context.InputLog != null)
                {
                    // Everything's ready, so run all the skimmers.
                    base.AnalyzeTarget(skimmers, context, disabledSkimmers);
                }
            }
        }
        protected override string ConstructTestOutputFromInputResource(string inputResourceName)
        {
            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                GetResourceText(inputResourceName),
                formatting: Formatting.Indented,
                out string transformedLog);

            SarifLog actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(transformedLog, formatting: Formatting.None, out transformedLog);

            Uri    originalUri = actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"].Uri;
            string uriString   = originalUri.ToString();

            // This code rewrites the log persisted URI to match the test environment
            string currentDirectory = Environment.CurrentDirectory;

            currentDirectory = currentDirectory.Substring(0, currentDirectory.IndexOf(@"\bld\"));
            uriString        = uriString.Replace("REPLACED_AT_TEST_RUNTIME", currentDirectory);

            actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation {
                Uri = new Uri(uriString, UriKind.Absolute)
            };

            var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);

            visitor.Visit(actualLog.Runs[0]);

            // Restore the remanufactured URI so that file diffing matches
            actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation {
                Uri = originalUri
            };

            return(JsonConvert.SerializeObject(actualLog, Formatting.Indented));
        }
예제 #3
0
        public SarifLog RunTestCase(string inputData, string expectedResult, bool prettyPrint = true)
        {
            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedResult, formatting: Formatting.Indented, out expectedResult);
            var converter = new T();

            // First retrieve converter JSON. This code will raise appropriate exceptions
            // for malformed data.
            string actualJson = Utilities.GetConverterJson(converter, inputData);

            // Next, let's ensure that the JSON is actually valid. The resulting
            // SARIF will be returned, allowing tests to perform additional validations.
            // We need to explicitly provide a settings object here to handle
            // special-cases in deserialization. If our grammar -> C# code hints
            // provided an ability to apply additional attributes to emitted code,
            // we wouldn't be required to do this. Filed an issue on this.
            // https://github.com/Microsoft/jschema/issues/6

            SarifLog log = JsonConvert.DeserializeObject <SarifLog>(actualJson);

            // Pretty-printed JSON literals can consume significant space in test code,
            // so we'll provide an option to collapse into minimal form
            actualJson = prettyPrint ? actualJson : JsonConvert.SerializeObject(log, Formatting.None);

            // Hard-coded JSON comparisons are useful for sniffing out small unexpected changes but
            // are fragile. It would be better for our testing to have a dedicated set of data-driven
            // tests that flag changes and for the unit-tests to work exclusively against the
            // object model.
            actualJson.Should().BeCrossPlatformEquivalent <SarifLog>(expectedResult);

            return(log);
        }
        private string RunConverter(StringBuilder sb, string toolFormat, string inputFileName)
        {
            string expectedFileName  = inputFileName + ".sarif";
            string generatedFileName = inputFileName + ".actual.sarif";

            try
            {
                this.converter.ConvertToStandardFormat(toolFormat, inputFileName, generatedFileName, LoggingOptions.OverwriteExistingOutputFile | LoggingOptions.PrettyPrint);
            }
            catch (Exception ex)
            {
                sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "The converter {0} threw an exception for input \"{1}\".", toolFormat, inputFileName));
                sb.AppendLine(ex.ToString());
                return(generatedFileName);
            }

            string expectedSarif = File.ReadAllText(expectedFileName);

            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedSarif, formatting: Formatting.Indented, out expectedSarif);

            string actualSarif = File.ReadAllText(generatedFileName);

            if (!AreEquivalent <SarifLog>(actualSarif, expectedSarif))
            {
                File.WriteAllText(expectedFileName, expectedSarif);
                File.WriteAllText(generatedFileName, actualSarif);

                string errorMessage = "The output of the {0} converter did not match for input {1}.";
                sb.AppendLine(string.Format(CultureInfo.CurrentCulture, errorMessage, toolFormat, inputFileName));
                sb.AppendLine("Check differences with:");
                sb.AppendLine(GenerateDiffCommand(toolFormat, expectedFileName, generatedFileName));
            }
            return(generatedFileName);
        }
예제 #5
0
        private bool Validate(string instanceFilePath, string schemaFilePath, IAnalysisLogger logger)
        {
            bool ok = true;

            try
            {
                string instanceText = FileSystem.ReadAllText(instanceFilePath);

                if (!s_DisablePrereleaseCompatibilityTransform)
                {
                    PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(instanceText, formatting: Formatting.Indented, out instanceText);
                }

                PerformSchemaValidation(instanceText, instanceFilePath, schemaFilePath, logger);
            }
            catch (JsonSyntaxException ex)
            {
                Result result = ex.ToSarifResult();
                ReportResult(result, logger);

                // If the file isn't syntactically valid JSON, we won't be able to run
                // the skimmers, because they rely on being able to deserialized the file
                // into a SarifLog object.
                ok = false;
            }
            catch (SchemaValidationException ex)
            {
                ReportInvalidSchemaErrors(ex, schemaFilePath, logger);
            }
            // The framework will catch all other, unexpected exceptions, and it will
            // cause the tool to exit with a non-0 exit code.

            return(ok);
        }
예제 #6
0
        public void RebaseUriVisitor_VisitFileData_RebasesAllTheThings()
        {
            string comprehensiveSarifPath = Path.Combine(Environment.CurrentDirectory, @"v2\SpecExamples\Comprehensive.sarif");

            string inputText = File.ReadAllText(comprehensiveSarifPath);

            SarifLog sarifLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(inputText, formatting: Formatting.None, out inputText);

            sarifLog.Runs.Count().Should().Be(1);

            var visitor = new RebaseVerifyingVisitor();

            visitor.VisitRun(sarifLog.Runs[0]);

            string outputText = JsonConvert.SerializeObject(sarifLog, Formatting.Indented);

            string uriRootText     = "file:///home/buildAgent/";
            string toolsRootBaseId = "TOOLS_ROOT";
            string srcRootBaseId   = "SRCROOT";

            int uriCount = 19;
            int toolsRootUriBaseIdCount = 4;
            int srcRootUriBaseIdCount   = 1;
            int uriBaseIdCount          = toolsRootUriBaseIdCount + srcRootUriBaseIdCount;
            int uriRootTextCount        = 13;

            visitor.FileLocationUriBaseIds.Count.Should().Be(uriCount);
            visitor.FileLocationUriBaseIds.Where(u => u == null).Count().Should().Be(uriCount - uriBaseIdCount);
            visitor.FileLocationUriBaseIds.Where(u => u != null).Count().Should().Be(uriBaseIdCount);
            visitor.FileLocationUriBaseIds.Where(u => u == toolsRootBaseId).Count().Should().Be(toolsRootUriBaseIdCount);
            visitor.FileLocationUriBaseIds.Where(u => u == srcRootBaseId).Count().Should().Be(srcRootUriBaseIdCount);

            visitor.FileLocationUris.Count.Should().Be(uriCount);
            visitor.FileLocationUris.Where(u => u != null && u.StartsWith(uriRootText)).Count().Should().Be(uriRootTextCount);

            string agentRootBaseId = "AGENT_ROOT";

            var rebaseUriVisitor = new RebaseUriVisitor(agentRootBaseId, new Uri(uriRootText));
            Run rebasedRun       = rebaseUriVisitor.VisitRun(sarifLog.Runs[0]);

            outputText = JsonConvert.SerializeObject(sarifLog, Formatting.Indented);

            visitor = new RebaseVerifyingVisitor();
            visitor.VisitRun(rebasedRun);

            visitor.FileLocationUriBaseIds.Count.Should().Be(uriCount);
            visitor.FileLocationUriBaseIds.Where(u => u == null).Count().Should().Be(1);
            visitor.FileLocationUriBaseIds.Where(u => u == toolsRootBaseId).Count().Should().Be(toolsRootUriBaseIdCount);
            visitor.FileLocationUriBaseIds.Where(u => u == srcRootBaseId).Count().Should().Be(srcRootUriBaseIdCount);
            visitor.FileLocationUriBaseIds.Where(u => u == agentRootBaseId).Count().Should().Be(uriRootTextCount);

            visitor.FileLocationUris.Count.Should().Be(uriCount);

            // The AGENT_ROOT originalUriBaseId should _not_ be counted as a file location.
            visitor.FileLocationUris.Where(u => u != null && u.StartsWith(uriRootText)).Count().Should().Be(0);
        }
예제 #7
0
 private IEnumerable <SarifLog> ParseFiles(IEnumerable <string> sarifFiles)
 {
     foreach (string file in sarifFiles)
     {
         yield return(PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                          File.ReadAllText(file),
                          formatting: Formatting.None,
                          out string sarifText));
     }
 }
        protected override string ConstructTestOutputFromInputResource(string inputResourceName, object parameter)
        {
            string inputResourceText = GetResourceText(inputResourceName);

            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                inputResourceText,
                formatting: Formatting.Indented,
                out string transformedLog);

            return(transformedLog);
        }
        public void PrereleaseCompatibilityTransformer_UpgradesPrereleaseTwoZeroZero()
        {
            string comprehensiveSarifPath = Path.Combine(Environment.CurrentDirectory, @"v2\ObsoleteFormats\ComprehensivePrereleaseTwoZeroZero.sarif");

            string sarifText = File.ReadAllText(comprehensiveSarifPath);

            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(sarifText, formatting: Formatting.None, out sarifText);

            SarifLog sarifLog = JsonConvert.DeserializeObject <SarifLog>(sarifText);

            JsonConvert.SerializeObject(sarifLog);
        }
        public void ValueEquals_ReturnsTrueForTwoIdenticalLogObjects()
        {
            const string ComprehensiveTestSamplePath     = @"v2\SpecExamples\Comprehensive.sarif";
            string       comprehensiveTestSampleContents = File.ReadAllText(ComprehensiveTestSamplePath);

            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(comprehensiveTestSampleContents, formatting: Formatting.None, out comprehensiveTestSampleContents);

            SarifLog expectedLog = JsonConvert.DeserializeObject <SarifLog>(comprehensiveTestSampleContents);
            SarifLog actualLog   = JsonConvert.DeserializeObject <SarifLog>(comprehensiveTestSampleContents);

            expectedLog.ValueEquals(actualLog).Should().BeTrue();
        }
        protected void Verify(string testFileName, bool disablePrereleaseCompatibilityTransform)
        {
            string targetPath     = Path.Combine(_testDirectory, testFileName);
            string actualFilePath = MakeActualFilePath(_testDirectory, testFileName);

            string inputLogContents = File.ReadAllText(targetPath);

            if (!disablePrereleaseCompatibilityTransform)
            {
                PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(inputLogContents, formatting: Formatting.Indented, out inputLogContents);
            }

            SarifLog inputLog = JsonConvert.DeserializeObject <SarifLog>(inputLogContents);

            bool expectedResultsArePresent = inputLog.Runs[0].TryGetProperty(ExpectedResultsPropertyName, out ExpectedValidationResults expectedResults);

            expectedResultsArePresent.Should().Be(true);

            var skimmer = new TSkimmer();

            using (var logger = new SarifLogger(
                       actualFilePath,
                       LoggingOptions.None,
                       tool: null,
                       run: null,
                       analysisTargets: new string[] { targetPath },
                       invocationTokensToRedact: null))
            {
                logger.AnalysisStarted();

                var context = new SarifValidationContext
                {
                    Rule             = skimmer,
                    Logger           = logger,
                    TargetUri        = new Uri(targetPath),
                    SchemaFilePath   = JsonSchemaFile,
                    InputLogContents = inputLogContents,
                    InputLog         = inputLog
                };

                skimmer.Initialize(context);
                context.Logger.AnalyzingTarget(context);

                skimmer.Analyze(context);

                logger.AnalysisStopped(RuntimeConditions.None);
            }

            string   actualLogContents = File.ReadAllText(actualFilePath);
            SarifLog outputLog         = JsonConvert.DeserializeObject <SarifLog>(actualLogContents);

            Verify(outputLog.Runs[0], expectedResults);
        }
예제 #12
0
        private void ProcessInputSarifLog(string filePath)
        {
            SarifLog sarifLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                _fileSystem.FileReadAllText(filePath),
                formatting: Formatting.None,
                out string sarifText);

            if (_options.MergeRuns)
            {
                new FixupVisitor().VisitSarifLog(sarifLog);
            }

            _mergeLogsChannel.Writer.TryWrite(sarifLog);
            Interlocked.Decrement(ref _filesToProcessCount);
        }
예제 #13
0
        protected override string ConstructTestOutputFromInputResource(string inputResource)
        {
            string v2LogText = GetResourceText(inputResource);

            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(v2LogText, formatting: Formatting.Indented, out v2LogText);
            SarifLog v2Log = JsonConvert.DeserializeObject <SarifLog>(v2LogText);

            var transformer = new SarifCurrentToVersionOneVisitor
            {
                EmbedVersionTwoContentInPropertyBag = false
            };

            transformer.VisitSarifLog(v2Log);

            SarifLogVersionOne v1Log = transformer.SarifLogVersionOne;

            return(JsonConvert.SerializeObject(v1Log, SarifTransformerUtilities.JsonSettingsV1Indented));
        }
예제 #14
0
 private SarifLog TransformFileToVersionTwo(string inputFilePath, string inputVersion)
 {
     if (inputVersion == "1.0.0")
     {
         //  Converting version 1 to version 2
         SarifLogVersionOne actualLog = ReadSarifFile <SarifLogVersionOne>(_fileSystem, inputFilePath, SarifContractResolverVersionOne.Instance);
         var visitor = new SarifVersionOneToCurrentVisitor();
         visitor.VisitSarifLogVersionOne(actualLog);
         return(visitor.SarifLog);
     }
     else
     {
         //  Converting prerelease version 2 to version 2
         return(PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                    _fileSystem.FileReadAllText(inputFilePath),
                    formatting: Formatting.None,
                    out string _));
     }
 }
예제 #15
0
        public void ValidatesAllTestFiles()
        {
            var validator = new Validator(_schema);
            var sb        = new StringBuilder();

            foreach (string inputFile in TestCases)
            {
                string instanceText = File.ReadAllText(inputFile);

                PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(instanceText, formatting: Formatting.None, out instanceText);

                Result[] errors = validator.Validate(instanceText, inputFile);

                if (errors.Length > 0)
                {
                    sb.AppendLine(FailureReason(errors));
                }
            }

            sb.Length.Should().Be(0, sb.ToString());
        }
예제 #16
0
        private void Verify(string testFileName, bool disablePreleaseCompatibilityTransform = false)
        {
            try
            {
                ValidateCommand.s_DisablePrereleaseCompatibilityTransform = disablePreleaseCompatibilityTransform;
                string testDirectory = Path.Combine(Environment.CurrentDirectory, TestDataDirectory);

                string testFilePath     = Path.Combine(TestDataDirectory, testFileName);
                string expectedFilePath = MakeExpectedFilePath(testDirectory, testFileName);
                string actualFilePath   = MakeActualFilePath(testDirectory, testFileName);

                var validateOptions = new ValidateOptions
                {
                    SarifOutputVersion   = SarifVersion.Current,
                    TargetFileSpecifiers = new[] { testFilePath },
                    OutputFilePath       = actualFilePath,
                    SchemaFilePath       = JsonSchemaFile,
                    Quiet = true
                };

                new ValidateCommand().Run(validateOptions);

                string actualLogContents   = File.ReadAllText(actualFilePath);
                string expectedLogContents = File.ReadAllText(expectedFilePath);
                PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedLogContents, formatting: Newtonsoft.Json.Formatting.None, out expectedLogContents);

                // We can't just compare the text of the log files because properties
                // like start time, and absolute paths, will differ from run to run.
                // Until SarifLogger has a "deterministic" option (see http://github.com/Microsoft/sarif-sdk/issues/500),
                // we perform a selective compare of just the elements we care about.
                SelectiveCompare(actualLogContents, expectedLogContents);
            }
            finally
            {
                ValidateCommand.s_DisablePrereleaseCompatibilityTransform = false;
            }
        }
예제 #17
0
        public int Run(TransformOptions transformOptions)
        {
            try
            {
                // Only set --output-file if --inline isn't specified. ValidateOptions will check
                // to make sure that exactly one of those two options is set.
                if (!transformOptions.Inline)
                {
                    transformOptions.OutputFilePath = CommandUtilities.GetTransformedOutputFileName(transformOptions);
                }

                bool valid = ValidateOptions(transformOptions);
                if (!valid)
                {
                    return(FAILURE);
                }

                // NOTE: we don't actually utilize the dataToInsert command-line data yet...
                OptionallyEmittedData dataToInsert = transformOptions.DataToInsert.ToFlags();

                string inputFilePath = transformOptions.InputFilePath;
                string inputVersion  = SniffVersion(inputFilePath);

                // If the user wants to transform to current v2, we check to see whether the input
                // file is v2 or pre-release v2. We upgrade both formats to current v2.
                //
                // Correspondingly, if the input file is v2 of any kind, we first ensure that it is
                // current v2, then drop it down to v1.
                //
                // We do not support transforming to any obsoleted pre-release v2 formats.
                if (transformOptions.SarifOutputVersion == SarifVersion.Current)
                {
                    if (inputVersion == "1.0.0")
                    {
                        SarifLogVersionOne actualLog = ReadSarifFile <SarifLogVersionOne>(_fileSystem, transformOptions.InputFilePath, SarifContractResolverVersionOne.Instance);
                        var visitor = new SarifVersionOneToCurrentVisitor();
                        visitor.VisitSarifLogVersionOne(actualLog);
                        WriteSarifFile(_fileSystem, visitor.SarifLog, transformOptions.OutputFilePath, transformOptions.Formatting);
                    }
                    else
                    {
                        // We have a pre-release v2 file that we should upgrade to current.
                        PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                            _fileSystem.ReadAllText(inputFilePath),
                            formatting: transformOptions.Formatting,
                            out string sarifText);

                        _fileSystem.WriteAllText(transformOptions.OutputFilePath, sarifText);
                    }
                }
                else
                {
                    if (inputVersion == "1.0.0")
                    {
                        SarifLogVersionOne logV1 = ReadSarifFile <SarifLogVersionOne>(_fileSystem, transformOptions.InputFilePath, SarifContractResolverVersionOne.Instance);
                        logV1.SchemaUri = SarifVersion.OneZeroZero.ConvertToSchemaUri();
                        WriteSarifFile(_fileSystem, logV1, transformOptions.OutputFilePath, transformOptions.Formatting, SarifContractResolverVersionOne.Instance);
                    }
                    else
                    {
                        string currentSarifVersion = SarifUtilities.StableSarifVersion;

                        string   sarifText = _fileSystem.ReadAllText(inputFilePath);
                        SarifLog actualLog = null;

                        if (inputVersion != currentSarifVersion)
                        {
                            // Note that we don't provide formatting here. It is not required to indent the v2 SARIF - it
                            // will be transformed to v1 later, where we should apply the indentation settings.
                            actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                                sarifText,
                                formatting: Formatting.None,
                                out sarifText);
                        }
                        else
                        {
                            actualLog = JsonConvert.DeserializeObject <SarifLog>(sarifText);
                        }

                        var visitor = new SarifCurrentToVersionOneVisitor();
                        visitor.VisitSarifLog(actualLog);

                        WriteSarifFile(_fileSystem, visitor.SarifLogVersionOne, transformOptions.OutputFilePath, transformOptions.Formatting, SarifContractResolverVersionOne.Instance);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return(FAILURE);
            }

            return(SUCCESS);
        }
예제 #18
0
        public static async Task ProcessLogFileCoreAsync(string filePath, string toolFormat, bool promptOnLogConversions, bool cleanErrors, bool openInEditor)
        {
            SarifLog log            = null;
            string   logText        = null;
            string   outputPath     = null;
            bool     saveOutputFile = true;

            if (toolFormat.MatchesToolFormat(ToolFormat.None))
            {
                await RetryInvokeAsync(
                    async() =>
                {
                    using (var logStreamReader = new StreamReader(filePath, Encoding.UTF8))
                    {
                        logText = await logStreamReader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false);
                    }
                },
                    retryInterval : TimeSpan.FromMilliseconds(300),
                    maxAttemptCount : 5);

                Match match = MatchVersionProperty(logText);
                if (match.Success)
                {
                    string inputVersion = match.Groups["version"].Value;

                    if (inputVersion == SarifUtilities.V1_0_0)
                    {
                        // They're opening a v1 log, so we need to transform it.
                        // Ask if they'd like to save the v2 log.
                        MessageDialogCommand response = promptOnLogConversions ?
                                                        await PromptToSaveProcessedLogAsync(Resources.TransformV1_DialogMessage).ConfigureAwait(continueOnCapturedContext: false) :
                                                        MessageDialogCommand.No;

                        if (response == MessageDialogCommand.Cancel)
                        {
                            return;
                        }

                        var settingsV1 = new JsonSerializerSettings()
                        {
                            ContractResolver = SarifContractResolverVersionOne.Instance,
                        };

                        SarifLogVersionOne v1Log = JsonConvert.DeserializeObject <SarifLogVersionOne>(logText, settingsV1);
                        var transformer          = new SarifVersionOneToCurrentVisitor();
                        transformer.VisitSarifLogVersionOne(v1Log);
                        log = transformer.SarifLog;

                        if (response == MessageDialogCommand.Yes)
                        {
                            // Prompt for a location to save the transformed log.
                            outputPath = await PromptForFileSaveLocationAsync(Resources.SaveTransformedV1Log_DialogTitle, filePath).ConfigureAwait(continueOnCapturedContext: false);

                            if (string.IsNullOrEmpty(outputPath))
                            {
                                return;
                            }
                        }

                        logText = JsonConvert.SerializeObject(log);
                    }
                    else if (inputVersion != VersionConstants.StableSarifVersion)
                    {
                        // It's an older v2 version, so send it through the pre-release compat transformer.
                        // Ask if they'd like to save the transformed log.
                        MessageDialogCommand response = promptOnLogConversions ?
                                                        await PromptToSaveProcessedLogAsync(string.Format(Resources.TransformPrereleaseV2_DialogMessage, VersionConstants.StableSarifVersion)).ConfigureAwait(continueOnCapturedContext: false) :
                                                        MessageDialogCommand.No;

                        if (response == MessageDialogCommand.Cancel)
                        {
                            return;
                        }

                        log = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(logText, Formatting.Indented, out logText);

                        if (response == MessageDialogCommand.Yes)
                        {
                            // Prompt for a location to save the transformed log.
                            outputPath = await PromptForFileSaveLocationAsync(Resources.SaveTransformedPrereleaseV2Log_DialogTitle, filePath).ConfigureAwait(continueOnCapturedContext: false);

                            if (string.IsNullOrEmpty(outputPath))
                            {
                                return;
                            }
                        }
                    }
                    else
                    {
                        // Since we didn't do any pre-processing, we don't need to write to a temp location.
                        outputPath     = filePath;
                        saveOutputFile = false;
                    }
                }
                else
                {
                    await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                    // The version property wasn't found within the first 100 characters.
                    // Per the spec, it should appear first in the sarifLog object.
                    VsShellUtilities.ShowMessageBox(ServiceProvider.GlobalProvider,
                                                    Resources.VersionPropertyNotFound_DialogTitle,
                                                    null, // title
                                                    OLEMSGICON.OLEMSGICON_QUERY,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return;
                }
            }
            else
            {
                // They're opening a non-SARIF log, so we need to convert it.
                // Ask if they'd like to save the converted log.
                MessageDialogCommand response = promptOnLogConversions ?
                                                await PromptToSaveProcessedLogAsync(Resources.ConvertNonSarifLog_DialogMessage).ConfigureAwait(continueOnCapturedContext: false) :
                                                MessageDialogCommand.No;

                if (response == MessageDialogCommand.Cancel)
                {
                    return;
                }

                // The converter doesn't have async methods, so spin
                // up a task to do this.
                await System.Threading.Tasks.Task.Run(() =>
                {
                    var sb = new StringBuilder();
                    using (FileStream fileStream = File.OpenRead(filePath))
                    {
                        using (var outputTextWriter = new StringWriter(sb))
                            using (var outputJson = new JsonTextWriter(outputTextWriter))
                                using (var output = new ResultLogJsonWriter(outputJson))
                                {
                                    var converter = new ToolFormatConverter();
                                    converter.ConvertToStandardFormat(toolFormat, fileStream, output);
                                }

                        logText = sb.ToString();

                        if (response == MessageDialogCommand.Yes)
                        {
                            // Prompt for a location to save the converted log.
                            outputPath = PromptForFileSaveLocationAsync(Resources.SaveConvertedLog_DialogTitle, filePath).Result;
                        }
                    }
                }).ConfigureAwait(continueOnCapturedContext: false);
            }

            if (string.IsNullOrEmpty(outputPath))
            {
                outputPath = Path.GetTempFileName() + ".sarif";
            }

            if (saveOutputFile)
            {
                await SaveLogFileAsync(outputPath, logText).ConfigureAwait(continueOnCapturedContext: false);
            }

            if (log == null)
            {
                log = JsonConvert.DeserializeObject <SarifLog>(logText);
            }

            await ProcessSarifLogAsync(log, outputPath, cleanErrors : cleanErrors, openInEditor : openInEditor).ConfigureAwait(continueOnCapturedContext: false);
        }
        public static void ProcessLogFile(string filePath, Solution solution, string toolFormat = ToolFormat.None, bool promptOnLogConversions = true)
        {
            SarifLog log = null;

            string logText;
            string outputPath     = null;
            bool   saveOutputFile = true;

            if (toolFormat.MatchesToolFormat(ToolFormat.None))
            {
                logText = File.ReadAllText(filePath);

                Match match = MatchVersionProperty(logText);
                if (match.Success)
                {
                    string inputVersion = match.Groups["version"].Value;

                    if (inputVersion == SarifUtilities.V1_0_0)
                    {
                        // They're opening a v1 log, so we need to transform it.
                        // Ask if they'd like to save the v2 log.
                        MessageDialogCommand response = promptOnLogConversions ? PromptToSaveProcessedLog(Resources.TransformV1_DialogMessage) : MessageDialogCommand.No;

                        if (response == MessageDialogCommand.Cancel)
                        {
                            return;
                        }

                        JsonSerializerSettings settingsV1 = new JsonSerializerSettings()
                        {
                            ContractResolver = SarifContractResolverVersionOne.Instance
                        };

                        SarifLogVersionOne v1Log = JsonConvert.DeserializeObject <SarifLogVersionOne>(logText, settingsV1);
                        var transformer          = new SarifVersionOneToCurrentVisitor();
                        transformer.VisitSarifLogVersionOne(v1Log);
                        log = transformer.SarifLog;

                        if (response == MessageDialogCommand.Yes)
                        {
                            // Prompt for a location to save the transformed log.
                            outputPath = PromptForFileSaveLocation(Resources.SaveTransformedV1Log_DialogTitle, filePath);

                            if (string.IsNullOrEmpty(outputPath))
                            {
                                return;
                            }
                        }

                        logText = JsonConvert.SerializeObject(log);
                    }
                    else if (inputVersion != VersionConstants.StableSarifVersion)
                    {
                        // It's an older v2 version, so send it through the pre-release compat transformer.
                        // Ask if they'd like to save the transformed log.
                        MessageDialogCommand response = promptOnLogConversions ? PromptToSaveProcessedLog(string.Format(Resources.TransformPrereleaseV2_DialogMessage, VersionConstants.StableSarifVersion)) : MessageDialogCommand.No;

                        if (response == MessageDialogCommand.Cancel)
                        {
                            return;
                        }

                        log = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(logText, Formatting.Indented, out logText);

                        if (response == MessageDialogCommand.Yes)
                        {
                            // Prompt for a location to save the transformed log.
                            outputPath = PromptForFileSaveLocation(Resources.SaveTransformedPrereleaseV2Log_DialogTitle, filePath);

                            if (string.IsNullOrEmpty(outputPath))
                            {
                                return;
                            }
                        }
                    }
                    else
                    {
                        // Since we didn't do any pre-processing, we don't need to write to a temp location.
                        outputPath     = filePath;
                        saveOutputFile = false;
                    }
                }
                else
                {
                    // The version property wasn't found within the first 100 characters.
                    // Per the spec, it should appear first in the sarifLog object.
                    VsShellUtilities.ShowMessageBox(SarifViewerPackage.ServiceProvider,
                                                    Resources.VersionPropertyNotFound_DialogTitle,
                                                    null, // title
                                                    OLEMSGICON.OLEMSGICON_QUERY,
                                                    OLEMSGBUTTON.OLEMSGBUTTON_OK,
                                                    OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
                    return;
                }
            }
            else
            {
                // They're opening a non-SARIF log, so we need to convert it.
                // Ask if they'd like to save the converted log.
                MessageDialogCommand response = promptOnLogConversions ? PromptToSaveProcessedLog(Resources.ConvertNonSarifLog_DialogMessage) : MessageDialogCommand.No;

                if (response == MessageDialogCommand.Cancel)
                {
                    return;
                }

                var converter = new ToolFormatConverter();
                var sb        = new StringBuilder();

                using (var input = new MemoryStream(File.ReadAllBytes(filePath)))
                {
                    var outputTextWriter = new StringWriter(sb);
                    var outputJson       = new JsonTextWriter(outputTextWriter);
                    var output           = new ResultLogJsonWriter(outputJson);

                    input.Seek(0, SeekOrigin.Begin);
                    converter.ConvertToStandardFormat(toolFormat, input, output);

                    // This is serving as a flush mechanism.
                    output.Dispose();

                    logText = sb.ToString();

                    if (response == MessageDialogCommand.Yes)
                    {
                        // Prompt for a location to save the converted log.
                        outputPath = PromptForFileSaveLocation(Resources.SaveConvertedLog_DialogTitle, filePath);
                    }
                }
            }

            if (string.IsNullOrEmpty(outputPath))
            {
                outputPath = Path.GetTempFileName() + ".sarif";
            }

            if (saveOutputFile)
            {
                SaveLogFile(outputPath, logText);
            }

            if (log == null)
            {
                log = JsonConvert.DeserializeObject <SarifLog>(logText);
            }

            ProcessSarifLog(log, outputPath, solution, showMessageOnNoResults: promptOnLogConversions);

            SarifTableDataSource.Instance.BringToFront();
        }
예제 #20
0
        protected override string ConstructTestOutputFromInputResource(string inputResourceName, object parameter)
        {
            PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                GetResourceText(inputResourceName),
                formatting: Formatting.Indented,
                out string transformedLog);

            SarifLog actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(transformedLog, formatting: Formatting.None, out transformedLog);

            // For CoreTests only - this code rewrites the log persisted URI to match the test environment
            if (inputResourceName == "Inputs.CoreTests-Relative.sarif")
            {
                Uri    originalUri = actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"].Uri;
                string uriString   = originalUri.ToString();

                string currentDirectory = Environment.CurrentDirectory;
                currentDirectory = currentDirectory.Substring(0, currentDirectory.IndexOf(@"\bld\"));
                uriString        = uriString.Replace("REPLACED_AT_TEST_RUNTIME", currentDirectory);

                actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation {
                    Uri = new Uri(uriString, UriKind.Absolute)
                };

                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);

                // Restore the remanufactured URI so that file diffing matches
                actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation {
                    Uri = originalUri
                };
            }
            else if (inputResourceName == "Inputs.CoreTests-Absolute.sarif")
            {
                Uri    originalUri = actualLog.Runs[0].Artifacts[0].Location.Uri;
                string uriString   = originalUri.ToString();

                string currentDirectory = Environment.CurrentDirectory;
                currentDirectory = currentDirectory.Substring(0, currentDirectory.IndexOf(@"\bld\"));
                uriString        = uriString.Replace("REPLACED_AT_TEST_RUNTIME", currentDirectory);

                actualLog.Runs[0].Artifacts[0].Location = new ArtifactLocation {
                    Uri = new Uri(uriString, UriKind.Absolute)
                };

                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);

                // Restore the remanufactured URI so that file diffing matches
                actualLog.Runs[0].Artifacts[0].Location = new ArtifactLocation {
                    Uri = originalUri
                };
            }
            else
            {
                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);
            }

            // Verify and remove Guids, because they'll vary with every run and can't be compared to a fixed expected output
            if (_currentOptionallyEmittedData.HasFlag(OptionallyEmittedData.Guids))
            {
                for (int i = 0; i < actualLog.Runs[0].Results.Count; ++i)
                {
                    Result result = actualLog.Runs[0].Results[i];
                    if (string.IsNullOrEmpty(result.Guid))
                    {
                        Assert.True(false, $"Results[{i}] had no Guid assigned, but OptionallyEmittedData.Guids flag was set.");
                    }

                    result.Guid = null;
                }
            }

            return(JsonConvert.SerializeObject(actualLog, Formatting.Indented));
        }
예제 #21
0
        private void CompareActualToExpected(
            IList <string> inputResourceNames,
            IDictionary <string, string> expectedOutputResourceNameDictionary,
            IDictionary <string, string> expectedSarifTextDictionary,
            IDictionary <string, string> actualSarifTextDictionary)
        {
            if (inputResourceNames.Count == 0)
            {
                throw new ArgumentException("No input resources were specified", nameof(inputResourceNames));
            }

            if (expectedOutputResourceNameDictionary.Count == 0)
            {
                throw new ArgumentException("No expected output resources were specified", nameof(expectedOutputResourceNameDictionary));
            }

            if (expectedSarifTextDictionary.Count != expectedOutputResourceNameDictionary.Count)
            {
                throw new ArgumentException($"The number of expected output files ({expectedSarifTextDictionary.Count}) does not match the number of expected output resources {expectedOutputResourceNameDictionary.Count}");
            }

            if (expectedSarifTextDictionary.Count != actualSarifTextDictionary.Count)
            {
                throw new ArgumentException($"The number of actual output files ({actualSarifTextDictionary.Count}) does not match the number of expected output files {expectedSarifTextDictionary.Count}");
            }

            bool passed = true;

            if (RebaselineExpectedResults)
            {
                passed = false;
            }
            else
            {
                // Reify the list of keys because we're going to modify the dictionary in place.
                List <string> keys = expectedSarifTextDictionary.Keys.ToList();

                foreach (string key in keys)
                {
                    if (_testProducesSarifCurrentVersion)
                    {
                        PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedSarifTextDictionary[key], Formatting.Indented, out string transformedSarifText);
                        expectedSarifTextDictionary[key] = transformedSarifText;

                        passed &= AreEquivalent <SarifLog>(actualSarifTextDictionary[key], expectedSarifTextDictionary[key]);
                    }
                    else
                    {
                        passed &= AreEquivalent <SarifLogVersionOne>(actualSarifTextDictionary[key], expectedSarifTextDictionary[key], SarifContractResolverVersionOne.Instance);
                    }
                }
            }

            if (!passed)
            {
                string errorMessage = string.Format(@"there should be no unexpected diffs detected comparing actual results to '{0}'.", string.Join(", ", inputResourceNames));
                var    sb           = new StringBuilder(errorMessage);

                if (!Utilities.RunningInAppVeyor)
                {
                    string expectedRootDirectory = null;
                    string actualRootDirectory   = null;

                    bool firstKey = true;
                    foreach (string key in expectedOutputResourceNameDictionary.Keys)
                    {
                        string expectedFilePath = GetOutputFilePath("ExpectedOutputs", expectedOutputResourceNameDictionary[key]);
                        string actualFilePath   = GetOutputFilePath("ActualOutputs", expectedOutputResourceNameDictionary[key]);

                        if (firstKey)
                        {
                            expectedRootDirectory = Path.GetDirectoryName(expectedFilePath);
                            actualRootDirectory   = Path.GetDirectoryName(actualFilePath);

                            Directory.CreateDirectory(expectedRootDirectory);
                            Directory.CreateDirectory(actualRootDirectory);

                            firstKey = false;
                        }

                        File.WriteAllText(expectedFilePath, expectedSarifTextDictionary[key]);
                        File.WriteAllText(actualFilePath, actualSarifTextDictionary[key]);
                    }

                    sb.AppendLine("To compare all difference for this test suite:");
                    sb.AppendLine(GenerateDiffCommand(TypeUnderTest, expectedRootDirectory, actualRootDirectory) + Environment.NewLine);

                    if (RebaselineExpectedResults)
                    {
                        string intermediateFolder = !string.IsNullOrEmpty(IntermediateTestFolder) ? IntermediateTestFolder + @"\" : string.Empty;
                        string testDirectory      = Path.Combine(GetProductTestDataDirectory(TestBinaryName, intermediateFolder + TypeUnderTest), "ExpectedOutputs");
                        Directory.CreateDirectory(testDirectory);

                        // We retrieve all test strings from embedded resources. To rebaseline, we need to
                        // compute the enlistment location from which these resources are compiled.
                        foreach (string key in expectedOutputResourceNameDictionary.Keys)
                        {
                            string expectedFilePath = Path.Combine(testDirectory, expectedOutputResourceNameDictionary[key]);
                            File.WriteAllText(expectedFilePath, actualSarifTextDictionary[key]);
                        }
                    }
                }

                if (!RebaselineExpectedResults)
                {
                    ValidateResults(sb.ToString());
                }
            }

            RebaselineExpectedResults.Should().BeFalse();
        }
        public async Task <ValidationResponse> Validate(ValidationRequest validationRequest)
        {
            string inputFilePath       = Path.Combine(_postedFilesDirectory, validationRequest.SavedFileName);
            string transformedFileName = Path.GetFileNameWithoutExtension(inputFilePath) + ".transformed.sarif";
            string transformedFilePath = Path.Combine(_postedFilesDirectory, transformedFileName);
            string outputFileName      = Path.GetFileNameWithoutExtension(validationRequest.PostedFileName) + ValidationLogSuffix;
            string outputFilePath      = Path.Combine(_postedFilesDirectory, outputFileName);

            string arguments = $"validate --output \"{outputFilePath}\" --json-schema \"{_schemaFilePath}\" --force --pretty-print --rich-return-code \"{transformedFilePath}\"";

            ValidationResponse validationResponse;

            try
            {
                string inputText    = File.ReadAllText(inputFilePath);
                string inputVersion = null;

                // Get the schema version of the unmodified input log
                using (StringReader reader = new StringReader(inputText))
                {
                    // Read the first 100 characters. This avoids the problem of reading a huge line from a minified log.
                    char[] buffer = new char[100];
                    reader.ReadBlock(buffer, 0, buffer.Length);
                    Match match = Regex.Match(inputText, VersionRegexPattern, RegexOptions.Compiled);

                    if (match.Success)
                    {
                        inputVersion = match.Groups["version"].Value;
                    }
                }

                string transformedText;
                string transformedVersion = null;
                PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(inputText, Formatting.Indented, out transformedText);

                // Get the schema version of the transformed log
                using (StringReader reader = new StringReader(transformedText))
                {
                    // We know we have indent-formatted JSON, so read the third line which has the version property.
                    string line = null;
                    for (int i = 0; i < 3; i++)
                    {
                        line = reader.ReadLine();
                    }

                    Match match = Regex.Match(line, VersionRegexPattern, RegexOptions.Compiled);

                    if (match.Success)
                    {
                        transformedVersion = match.Groups["version"].Value;
                    }
                }

                File.WriteAllText(transformedFilePath, transformedText);

                ProcessResult processResult = await _processRunner.RunProcess(_multitoolExePath, arguments);

                validationResponse = new ValidationResponse
                {
                    Message                = $"The SARIF validation service received a request to validate \"{validationRequest.PostedFileName}\".",
                    Arguments              = arguments,
                    ExitCode               = processResult.ExitCode,
                    StandardError          = processResult.StandardError,
                    StandardOutput         = processResult.StandardOutput,
                    IsTransformed          = inputVersion != transformedVersion,
                    TransformedLogContents = transformedText,
                    ResultsLogContents     = _fileSystem.ReadAllText(outputFilePath)
                };
            }
            catch (Exception ex)
            {
                validationResponse = new ValidationResponse
                {
                    ExitCode = int.MaxValue,
                    Message  = $"Validation of file {validationRequest.PostedFileName} failed: {ex.Message}"
                };
            }
            finally
            {
                if (_fileSystem.FileExists(outputFilePath))
                {
                    _fileSystem.DeleteFile(outputFilePath);
                }

                if (_fileSystem.FileExists(transformedFilePath))
                {
                    _fileSystem.DeleteFile(transformedFilePath);
                }
            }

            return(validationResponse);
        }
예제 #23
0
        protected virtual void RunTest(string inputResourceName, string expectedOutputResourceName = null)
        {
            expectedOutputResourceName = expectedOutputResourceName ?? inputResourceName;
            // When retrieving constructed test content, we pass the resourceName as the test
            // specified it. When constructing actual and expected file names from this data,
            // however, we will ensure that the name has the ".sarif" extension. We do this
            // for test classes such as the Fortify converter that operate again non-SARIF inputs.
            string actualSarifText = ConstructTestOutputFromInputResource("Inputs." + inputResourceName);

            expectedOutputResourceName = Path.GetFileNameWithoutExtension(expectedOutputResourceName) + ".sarif";

            var sb = new StringBuilder();

            string expectedSarifText = GetResourceText("ExpectedOutputs." + expectedOutputResourceName);

            bool passed = false;

            if (!RebaselineExpectedResults)
            {
                if (_testProducesSarifCurrentVersion)
                {
                    PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(expectedSarifText, Formatting.Indented, out expectedSarifText);
                    passed = AreEquivalent <SarifLog>(actualSarifText, expectedSarifText);
                }
                else
                {
                    passed = AreEquivalent <SarifLogVersionOne>(actualSarifText, expectedSarifText, SarifContractResolverVersionOne.Instance);
                }
            }

            if (!passed)
            {
                string errorMessage = string.Format(@"there should be no unexpected diffs detected comparing actual results to '{0}'.", inputResourceName);
                sb.AppendLine(errorMessage);

                if (!Utilities.RunningInAppVeyor)
                {
                    string expectedFilePath = GetOutputFilePath("ExpectedOutputs", expectedOutputResourceName);
                    string actualFilePath   = GetOutputFilePath("ActualOutputs", expectedOutputResourceName);

                    string expectedRootDirectory = Path.GetDirectoryName(expectedFilePath);
                    string actualRootDirectory   = Path.GetDirectoryName(actualFilePath);

                    Directory.CreateDirectory(expectedRootDirectory);
                    Directory.CreateDirectory(actualRootDirectory);

                    File.WriteAllText(expectedFilePath, expectedSarifText);
                    File.WriteAllText(actualFilePath, actualSarifText);

                    sb.AppendLine("To compare all difference for this test suite:");
                    sb.AppendLine(GenerateDiffCommand(TypeUnderTest, Path.GetDirectoryName(expectedFilePath), Path.GetDirectoryName(actualFilePath)) + Environment.NewLine);

                    if (RebaselineExpectedResults)
                    {
                        string intermediateFolder = !string.IsNullOrEmpty(IntermediateTestFolder) ? IntermediateTestFolder + @"\" : String.Empty;
                        string testDirectory      = Path.Combine(GetProductTestDataDirectory(TestBinaryName, intermediateFolder + TypeUnderTest), "ExpectedOutputs");
                        Directory.CreateDirectory(testDirectory);

                        // We retrieve all test strings from embedded resources. To rebaseline, we need to
                        // compute the enlistment location from which these resources are compiled.

                        expectedFilePath = Path.Combine(testDirectory, expectedOutputResourceName);
                        File.WriteAllText(expectedFilePath, actualSarifText);
                    }
                }

                if (!RebaselineExpectedResults)
                {
                    ValidateResults(sb.ToString());
                }
            }

            RebaselineExpectedResults.Should().BeFalse();
        }
예제 #24
0
        private void RunRules(StringBuilder sb, string inputFileName)
        {
            string fileName        = Path.GetFileName(inputFileName);
            string actualDirectory = Path.Combine(Path.GetDirectoryName(inputFileName), "Actual");
            string expectedDirectory;

            if (PlatformSpecificHelpers.RunningOnWindows())
            {
                expectedDirectory = Path.Combine(Path.GetDirectoryName(inputFileName), "Expected");
            }
            else
            {
                expectedDirectory = Path.Combine(Path.GetDirectoryName(inputFileName), "NonWindowsExpected");
            }
            if (!Directory.Exists(actualDirectory))
            {
                Directory.CreateDirectory(actualDirectory);
            }

            string expectedFileName = Path.Combine(expectedDirectory, fileName + ".sarif");
            string actualFileName   = Path.Combine(actualDirectory, fileName + ".sarif");

            var command = new AnalyzeCommand();
            var options = new AnalyzeOptions
            {
                Force                 = true,
                Verbose               = true,
                Recurse               = false,
                PrettyPrint           = true,
                ComputeFileHashes     = true,
                OutputFilePath        = actualFileName,
                ConfigurationFilePath = "default",
                SarifOutputVersion    = SarifVersion.Current,
                TargetFileSpecifiers  = new string[] { inputFileName }
            };

            int result = command.Run(options);

            // Note that we don't ensure a success code. That is because we
            // are running end-to-end tests for valid and invalid files

            var settings = new JsonSerializerSettings()
            {
                Formatting = Newtonsoft.Json.Formatting.Indented
            };

            string expectedText = File.ReadAllText(expectedFileName);
            string actualText   = File.ReadAllText(actualFileName);

            // Replace repository root absolute path with Z:\ for machine and enlistment independence
            string repoRoot = Path.GetFullPath(Path.Combine(actualDirectory, "..", "..", "..", ".."));

            actualText = actualText.Replace(repoRoot.Replace(@"\", @"\\"), @"Z:");
            actualText = actualText.Replace(repoRoot.Replace(@"\", @"/"), @"Z:");

            // Remove stack traces as they can change due to inlining differences by configuration and runtime.
            actualText = Regex.Replace(actualText, @"\\r\\n   at [^""]+", "");

            actualText = actualText.Replace(@"""Sarif""", @"""BinSkim""");
            actualText = actualText.Replace(@"        ""fileVersion"": ""15.0.0""," + Environment.NewLine, string.Empty);

            actualText = Regex.Replace(actualText, @"\s*""fullName""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""semanticVersion""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""sarifLoggerVersion""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""dottedQuadFileVersion""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""Comments""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""CompanyName""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""ProductName""[^\n]+?\n", Environment.NewLine);

            actualText = Regex.Replace(actualText, @"\s*""time""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""endTimeUtc""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""startTimeUtc""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"\s*""processId""[^\n]+?\n", Environment.NewLine);
            actualText = Regex.Replace(actualText, @"      ""id""[^,]+,\s+""tool""", @"      ""tool""", RegexOptions.Multiline);

            // Write back the normalized actual text so that the diff command given on failure shows what was actually compared.

            Encoding utf8encoding = new UTF8Encoding(true);

            using (var textWriter = new StreamWriter(actualFileName, false, utf8encoding))
            {
                textWriter.Write(actualText);
            }

            // Make sure we can successfully deserialize what was just generated
            SarifLog expectedLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                expectedText,
                settings.Formatting,
                out expectedText);

            SarifLog actualLog = JsonConvert.DeserializeObject <SarifLog>(actualText, settings);

            var visitor = new ResultDiffingVisitor(expectedLog);

            if (!visitor.Diff(actualLog.Runs[0].Results))
            {
                string errorMessage = "The output of the tool did not match for input {0}.";
                sb.AppendLine(string.Format(CultureInfo.CurrentCulture, errorMessage, inputFileName));
                sb.AppendLine("Check differences with:");
                sb.AppendLine(this.GenerateDiffCommand(expectedFileName, actualFileName));
            }
        }
예제 #25
0
        protected override string ConstructTestOutputFromInputResource(string inputResourceName, object parameter)
        {
            SarifLog actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                GetResourceText(inputResourceName),
                formatting: Formatting.Indented,
                updatedLog: out _);

            // Some of the tests operate on SARIF files that mention the absolute path of the file
            // that was "analyzed" (InsertOptionalDataVisitor.txt). That path depends on the repo
            // root, and so can vary depending on the machine where the tests are run. To avoid
            // this problem, both the input files and the expected output files contain a fixed
            // string "REPLACED_AT_TEST_RUNTIME" in place of the directory portion of the path. But some
            // of the tests must read the contents of the analyzed file (for instance, when the
            // test requires snippets or file hashes to be inserted). Those test require the actual
            // path. Therefore we replace the fixed string with the actual path, execute the
            // visitor, and then restore the fixed string so the actual output can be compared
            // to the expected output.
            string enlistmentRoot = GitHelper.Default.GetRepositoryRoot(Environment.CurrentDirectory, useCache: false);

            if (inputResourceName == "Inputs.CoreTests-Relative.sarif")
            {
                Uri originalUri = actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"].Uri;
                string uriString = originalUri.ToString();

                uriString = uriString.Replace(EnlistmentRoot, enlistmentRoot);

                actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation { Uri = new Uri(uriString, UriKind.Absolute) };

                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);

                // Restore the remanufactured URI so that file diffing succeeds.
                actualLog.Runs[0].OriginalUriBaseIds["TESTROOT"] = new ArtifactLocation { Uri = originalUri };

                // In some of the tests, the visitor added an originalUriBaseId for the repo root.
                // Adjust that one, too.
                string repoRootUriBaseId = InsertOptionalDataVisitor.GetUriBaseId(0);
                if (actualLog.Runs[0].OriginalUriBaseIds.TryGetValue(repoRootUriBaseId, out ArtifactLocation artifactLocation))
                {
                    Uri repoRootUri = artifactLocation.Uri;
                    string repoRootString = repoRootUri.ToString();
                    repoRootString = repoRootString.Replace(enlistmentRoot.Replace(@"\", "/"), EnlistmentRoot);

                    actualLog.Runs[0].OriginalUriBaseIds[repoRootUriBaseId] = new ArtifactLocation { Uri = new Uri(repoRootString, UriKind.Absolute) };
                }
            }
            else if (inputResourceName == "Inputs.CoreTests-Absolute.sarif")
            {
                Uri originalUri = actualLog.Runs[0].Artifacts[0].Location.Uri;
                string uriString = originalUri.ToString();

                uriString = uriString.Replace(EnlistmentRoot, enlistmentRoot);

                actualLog.Runs[0].Artifacts[0].Location = new ArtifactLocation { Uri = new Uri(uriString, UriKind.Absolute) };

                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);

                // Restore the remanufactured URI so that file diffing matches
                actualLog.Runs[0].Artifacts[0].Location = new ArtifactLocation { Uri = originalUri };
            }
            else
            {
                var visitor = new InsertOptionalDataVisitor(_currentOptionallyEmittedData);
                visitor.Visit(actualLog.Runs[0]);
            }

            // Verify and remove Guids, because they'll vary with every run and can't be compared to a fixed expected output.
            if (_currentOptionallyEmittedData.HasFlag(OptionallyEmittedData.Guids))
            {
                for (int i = 0; i < actualLog.Runs[0].Results.Count; ++i)
                {
                    Result result = actualLog.Runs[0].Results[i];
                    result.Guid.Should().NotBeNullOrEmpty(because: "OptionallyEmittedData.Guids flag was set");

                    result.Guid = null;
                }
            }

            if (_currentOptionallyEmittedData.HasFlag(OptionallyEmittedData.VersionControlDetails))
            {
                VersionControlDetails versionControlDetails = actualLog.Runs[0].VersionControlProvenance[0];

                // Verify and replace the mapped directory (enlistment root), because it varies
                // from machine to machine.
                var mappedUri = new Uri(enlistmentRoot + @"\", UriKind.Absolute);
                versionControlDetails.MappedTo.Uri.Should().Be(mappedUri);
                versionControlDetails.MappedTo.Uri = new Uri($"file:///{EnlistmentRoot}/");

                // When OptionallyEmittedData includes any file-related content, the visitor inserts
                // an artifact that points to the enlistment root. So we have to verify and adjust
                // that as well.
                IList<Artifact> artifacts = actualLog.Runs[0].Artifacts;
                if (artifacts.Count >= 2)
                {
                    artifacts[1].Location.Uri.Should().Be(enlistmentRoot);
                    artifacts[1].Location.Uri = new Uri($"file:///{EnlistmentRoot}/");
                }

                // Verify and replace the remote repo URI, because it would be different in a fork.
                var gitHelper = new GitHelper();
                Uri remoteUri = gitHelper.GetRemoteUri(enlistmentRoot);

                versionControlDetails.RepositoryUri.Should().Be(remoteUri);
                versionControlDetails.RepositoryUri = new Uri("https://REMOTE_URI");

                // Verify and remove branch and revision id, because they vary from run to run.
                versionControlDetails.Branch.Should().NotBeNullOrEmpty(because: "OptionallyEmittedData.VersionControlInformation flag was set");
                versionControlDetails.Branch = null;

                versionControlDetails.RevisionId.Should().NotBeNullOrEmpty(because: "OptionallyEmittedData.VersionControlInformation flag was set");
                versionControlDetails.RevisionId = null;
            }

            return JsonConvert.SerializeObject(actualLog, Formatting.Indented);
        }
예제 #26
0
        public int Run(TransformOptions transformOptions)
        {
            try
            {
                if (transformOptions.TargetVersion != SarifVersion.OneZeroZero && transformOptions.TargetVersion != SarifVersion.Current)
                {
                    Console.WriteLine(MultitoolResources.ErrorInvalidTransformTargetVersion);
                    return(1);
                }

                OptionallyEmittedData dataToInsert = transformOptions.DataToInsert.ToFlags();

                // NOTE: we don't actually utilize the dataToInsert command-line data yet...

                string fileName = CommandUtilities.GetTransformedOutputFileName(transformOptions);

                var formatting = transformOptions.PrettyPrint
                    ? Formatting.Indented
                    : Formatting.None;


                string inputFilePath = transformOptions.InputFilePath;
                string inputVersion  = SniffVersion(inputFilePath);

                // If the user wants to transform to current v2, we check to see whether the input
                // file is v2 or pre-release v2. We upgrade both formats to current v2.
                //
                // Correspondingly, if the input file is v2 of any kind, we first ensure that it is
                // current v2, then drop it down to v1.
                //
                // We do not support transforming to any obsoleted pre-release v2 formats.
                if (transformOptions.TargetVersion == SarifVersion.Current)
                {
                    if (inputVersion == "1.0.0")
                    {
                        SarifLogVersionOne actualLog = FileHelpers.ReadSarifFile <SarifLogVersionOne>(_fileSystem, transformOptions.InputFilePath, SarifContractResolverVersionOne.Instance);
                        var visitor = new SarifVersionOneToCurrentVisitor();
                        visitor.VisitSarifLogVersionOne(actualLog);
                        FileHelpers.WriteSarifFile(_fileSystem, visitor.SarifLog, fileName, formatting);
                    }
                    else
                    {
                        // We have a pre-release v2 file that we should upgrade to current.
                        PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                            _fileSystem.ReadAllText(inputFilePath),
                            formatting: formatting,
                            out string sarifText);

                        _fileSystem.WriteAllText(fileName, sarifText);
                    }
                }
                else
                {
                    if (inputVersion == "1.0.0")
                    {
                        _fileSystem.WriteAllText(fileName, _fileSystem.ReadAllText(inputFilePath));
                    }
                    else
                    {
                        string currentSarifVersion = SarifUtilities.SemanticVersion;

                        string   sarifText = _fileSystem.ReadAllText(inputFilePath);
                        SarifLog actualLog = null;

                        if (inputVersion != currentSarifVersion)
                        {
                            // Note that we don't provide formatting here. It is not required to indent the v2 SARIF - it
                            // will be transformed to v1 later, where we should apply the indentation settings.
                            actualLog = PrereleaseCompatibilityTransformer.UpdateToCurrentVersion(
                                sarifText,
                                formatting: Formatting.None,
                                out sarifText);
                        }
                        else
                        {
                            actualLog = JsonConvert.DeserializeObject <SarifLog>(sarifText);
                        }

                        var visitor = new SarifCurrentToVersionOneVisitor();
                        visitor.VisitSarifLog(actualLog);

                        FileHelpers.WriteSarifFile(_fileSystem, visitor.SarifLogVersionOne, fileName, formatting, SarifContractResolverVersionOne.Instance);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                return(1);
            }

            return(0);
        }