public void ConfigureRules() { WriteOnce.SafeLog("TagTestCommand::ConfigRules", LogLevel.Trace); if (string.IsNullOrEmpty(_options.CustomRulesPath)) { throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED)); } RulesVerifier verifier = new RulesVerifier(_options.CustomRulesPath, _options.Log); verifier.Verify(); if (!verifier.IsVerified) { throw new OpException(MsgHelp.GetString(MsgHelp.ID.VERIFY_RULES_RESULTS_FAIL)); } _rulesSet = verifier.CompiledRuleset ?? new RuleSet(null); //error check based on ruleset not path enumeration if (!_rulesSet.Any()) { throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED)); } }
private void ConfigRules() { _logger.LogTrace("ExportTagsCommand::ConfigRules"); _rules = new RuleSet(_loggerFactory); if (!_options.IgnoreDefaultRules) { _rules = RuleSetUtils.GetDefaultRuleSet(_loggerFactory); } if (!string.IsNullOrEmpty(_options?.CustomRulesPath)) { if (Directory.Exists(_options.CustomRulesPath)) { _rules.AddDirectory(_options.CustomRulesPath); } else if (File.Exists(_options.CustomRulesPath)) { _rules.AddFile(_options.CustomRulesPath); } else { throw new OpException(MsgHelp.FormatString(MsgHelp.ID.CMD_INVALID_RULE_PATH, _options.CustomRulesPath)); } } //error check based on ruleset not path enumeration if (_rules == null || !_rules.Any()) { throw new OpException(MsgHelp.GetString(MsgHelp.ID.CMD_NORULES_SPECIFIED)); } }
/// <summary> /// Analyzes a directory of files. /// </summary> /// <param name="directory"> directory to analyze. </param> /// <returns> List of tags identified </returns> public async Task <List <IssueRecord> > AnalyzeDirectory(string directory) { Logger.Trace("AnalyzeDirectory({0})", directory); var analysisResults = new List <IssueRecord>(); RuleSet rules = new RuleSet(); if (Options["disable-default-rules"] is bool disableDefaultRules && !disableDefaultRules) { var assembly = Assembly.GetExecutingAssembly(); foreach (var resourceName in assembly.GetManifestResourceNames()) { if (resourceName.EndsWith(".json")) { try { var stream = assembly.GetManifestResourceStream(resourceName); using var resourceStream = new StreamReader(stream ?? new MemoryStream()); rules.AddString(resourceStream.ReadToEnd(), resourceName); } catch (Exception ex) { Logger.Warn(ex, "Error loading {0}: {1}", resourceName, ex.Message); } } } } if (Options["custom-rule-directory"] is string customDirectory) { rules.AddDirectory(customDirectory); } if (!rules.Any()) { Logger.Error("No rules were specified, unable to continue."); return(analysisResults); // empty } var processor = new RuleProcessor(rules) { EnableSuppressions = false, SeverityLevel = (Severity)31 }; string[] fileList; if (Directory.Exists(directory)) { fileList = Directory.GetFiles(directory, "*", SearchOption.AllDirectories); } else if (File.Exists(directory)) { fileList = new string[] { directory }; } else { Logger.Warn("{0} is neither a directory nor a file.", directory); return(analysisResults); // empty } foreach (var filename in fileList) { Logger.Trace($"Processing {filename}"); // TODO: Make this more resilient if (IGNORE_FILES.Contains(Path.GetFileName(filename))) { Logger.Trace($"Ignoring {filename}"); continue; } byte[] fileContents; try { fileContents = File.ReadAllBytes(filename); } catch (Exception ex) { Logger.Trace(ex, "File {0} cannot be read, ignoring.", filename); continue; } var buffer = NormalizeFileContent(filename, fileContents); Logger.Debug("Normalization complete."); double MIN_CRYPTO_OP_DENSITY = 0.10; try { // TODO don't do this if we disassembled native code var cryptoOperationLikelihood = CalculateCryptoOpDensity(buffer); Logger.Debug("Cryptographic operation density for {0} was {1}", filename, cryptoOperationLikelihood); if (cryptoOperationLikelihood >= MIN_CRYPTO_OP_DENSITY) { analysisResults.Add(new IssueRecord( Filename: filename, Filesize: buffer.Length, TextSample: "n/a", Issue: new Issue( Boundary: new Boundary(), StartLocation: new Location(), EndLocation: new Location(), Rule: new Rule("Crypto Symbols") { Id = "_CRYPTO_DENSITY", Name = "Cryptographic symbols", Description = cryptoOperationLikelihood.ToString(), Tags = new string[] { "Cryptography.GenericImplementation.HighDensityOperators" } } ) )); } Logger.Debug($"Analyzing {filename}, length={buffer.Length}"); Issue[]? fileResults = null; var task = Task.Run(() => processor.Analyze(buffer, Language.FromFileName(filename))); if (task.Wait(TimeSpan.FromSeconds(2))) { fileResults = task.Result; } else { Logger.Debug("DevSkim operation timed out."); return(analysisResults); } Logger.Debug("Operation Complete: {0}", fileResults?.Length); foreach (var issue in fileResults ?? Array.Empty <Issue>()) { var fileContentArray = buffer.Split(new[] { Environment.NewLine }, StringSplitOptions.None); var excerpt = new List <string>(); var startLoc = Math.Max(issue.StartLocation.Line - 1, 0); var endLoc = Math.Min(issue.EndLocation.Line + 1, fileContentArray.Length - 1); for (int i = startLoc; i <= endLoc; i++) { excerpt.Add(fileContentArray[i].Trim()); } analysisResults.Add(new IssueRecord( Filename: filename, Filesize: buffer.Length, TextSample: issue.StartLocation.Line + " => " + string.Join(Environment.NewLine, excerpt), Issue: issue) ); } } catch (Exception ex) { Logger.Warn(ex, "Error analyzing {0}: {1}", filename, ex.Message); Logger.Warn(ex.StackTrace); } } return(analysisResults); }