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)); }
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); }
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); }
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); }
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); }
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); }
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)); }
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 _)); } }
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()); }
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; } }
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); }
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(); }
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)); }
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); }
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(); }
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)); } }
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); }
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); }