Initial ApplicationInspector check-in

This commit is contained in:
David Alcantar 2019-10-09 15:17:14 -07:00
Родитель a9f2fb3271
Коммит 8276f196d1
159 изменённых файлов: 38934 добавлений и 116 удалений

63
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

38
.github/ISSUE_TEMPLATE/bug_report.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.

20
.github/ISSUE_TEMPLATE/feature_request.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

94
.gitignore поставляемый
Просмотреть файл

@ -1,7 +1,5 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
@ -24,14 +22,11 @@ bld/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
@ -45,29 +40,19 @@ TestResult.xml
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
@ -105,9 +90,6 @@ ipch/
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
@ -128,14 +110,6 @@ _TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
@ -167,9 +141,9 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
@ -180,12 +154,12 @@ PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
**/packages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
@ -202,7 +176,6 @@ AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
@ -219,12 +192,9 @@ ClientBin/
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
@ -239,19 +209,15 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
@ -261,7 +227,6 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
@ -269,9 +234,6 @@ node_modules/
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@ -297,34 +259,10 @@ paket-files/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
/AppInspector/htmlReport
/AppInspectorLog.txt
/AppInspector/Log.txt
/AppInspector/LogB4.txt
/AppInspector/wip.txt
/AppInspector/linux/ApplicationInspector
/Microsoft.DevSkim/linux/ApplicationInspector

36
AppInspector.sln Normal file
Просмотреть файл

@ -0,0 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.645
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppInspector.CLI", "AppInspector\AppInspector.CLI.csproj", "{C6D58D43-481F-456F-90E8-FAC3779E6CC6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{876245F3-D7C5-4AA3-A288-2CE94BF63B8E}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DevSkim", "Microsoft.DevSkim\Microsoft.DevSkim.csproj", "{C19A98D2-629D-4F4D-87E4-3154416970BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6D58D43-481F-456F-90E8-FAC3779E6CC6}.Release|Any CPU.Build.0 = Release|Any CPU
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C19A98D2-629D-4F4D-87E4-3154416970BA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1D8F88F7-47D4-475A-B1AF-713132222341}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,127 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PackageProjectUrl>https://github.com/microsoft/ApplicationInspector</PackageProjectUrl>
<RepositoryUrl>https://github.com/microsoft/ApplicationInspector</RepositoryUrl>
<RepositoryType></RepositoryType>
<PackageTags>Static Linter</PackageTags>
<PackageReleaseNotes>Pre-release version</PackageReleaseNotes>
<Description>Characterizes software content</Description>
<Copyright>(c) Microsoft Corporation. All rights reserved</Copyright>
<HighEntropyVA>true</HighEntropyVA>
<PackageId>ApplicationInspector</PackageId>
<Product>ApplicationInspector</Product>
<Authors>ApplicationInspector</Authors>
<Version>1.0.0</Version>
<AssemblyName>ApplicationInspector</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
<PlatformTarget>AnyCPU</PlatformTarget>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants />
</PropertyGroup>
<ItemGroup>
<Compile Remove="htmlreport\**" />
<Compile Remove="linux\**" />
<EmbeddedResource Remove="htmlreport\**" />
<EmbeddedResource Remove="linux\**" />
<None Remove="htmlreport\**" />
<None Remove="linux\**" />
</ItemGroup>
<ItemGroup>
<None Remove="html\partials\_file_listing.liquid" />
<None Remove="html\partials\_report_overview.liquid" />
<None Remove="html\partials\_report_profile.liquid" />
<None Remove="html\partials\_report_summary.liquid" />
<None Remove="log.txt" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="html\partials\_file_listing.liquid" />
<EmbeddedResource Include="html\partials\_report_overview.liquid">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</EmbeddedResource>
<EmbeddedResource Include="html\partials\_report_profile.liquid" />
<EmbeddedResource Include="html\partials\_report_summary.liquid" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.6.0" />
<PackageReference Include="DotLiquid" Version="2.0.314" />
<PackageReference Include="Handlebars.Net" Version="1.10.1" />
<PackageReference Include="MediaTypeMap.Core" Version="2.3.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="NLog" Version="4.6.7" />
<PackageReference Include="SharpZipLib" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.DevSkim\Microsoft.DevSkim.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Properties\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Update="htmltemplates\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="preferences\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="rules\**">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Update="html\index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="html\resources\appinspector.css">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="html\resources\appinspector.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<None Include="C:\temp\authorization.json" Link="authorization.json" />
</ItemGroup>
<ItemGroup>
<Folder Include="preferences\" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties /></VisualStudio></ProjectExtensions>
</Project>

751
AppInspector/AppMetaData.cs Normal file
Просмотреть файл

@ -0,0 +1,751 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Microsoft.DevSkim;
using System.IO;
using System.Linq;
using System.Dynamic;
using System.Runtime.Serialization.Json;
namespace Microsoft.AppInspector.CLI.Writers
{
/// <summary>
/// Parent wrapper class for representing source characterization parts
/// Contains data elements that represent post processing options
/// Contains data elements that are related to organization and presentation of tagGroups
/// </summary>
[Serializable]
public class AppProfile
{
[JsonProperty(PropertyName = "appInspectorVer")]
public string Version { get; set; }
[JsonProperty(PropertyName = "sourcePath")]
public string SourcePath { get; set; }
[JsonProperty(PropertyName = "appInspectorArgs")]
public string Args { get; set; }
[JsonProperty(PropertyName = "dateScanned")]
public string DateScanned { get; set; }
[JsonProperty(PropertyName = "rulePaths")]
public HashSet<string> RulePaths { get { return MetaData.RulePaths; } }
public AppMetaData MetaData { get; set; }
//has to be public to be visible to htmlwriter
[JsonProperty(PropertyName = "TagReportGroupLists")]
public Dictionary<string, List<TagInfo>> KeyedTagInfoLists { get; }//dynamic lists for grouping tag properties in reporting
[JsonIgnore]
public Dictionary<string, List<TagInfo>> KeyedSortedTagInfoLists { get; } //split to avoid json serialization with others
[JsonIgnore]
public List<MatchRecord> MatchList { get; set; }//results list of rulesprocessing
[JsonIgnore]
public List<TagCategory> TagGroupPreferences { get; set; }//read preferred list of groups and tags for profile page
//Report properties
[JsonIgnore]
public bool ExcludeRollup { get; set; }
[JsonIgnore]
public bool SimpleTagsOnly { get; set; }
[JsonIgnore]
public bool UniqueTagsOnly { get; }
/// <summary>
/// Constructor initializes several internal lists not populated by rules processing
/// </summary>
/// <param name="sourcePath">code</param>
/// <param name="rulePaths">rules</param>
/// <param name="excludeRollup">omit aggregated rollup e.g. simple output with matches</param>
/// <param name="simpleTagsOnly">simple output override</param>
/// <param name="uniqueTagsOnly">avoid duplicate tag reporting</param>
public AppProfile(string sourcePath, List<string> rulePaths, bool excludeRollup, bool simpleTagsOnly, bool uniqueTagsOnly)
{
SourcePath = sourcePath;
Version = Program.GetVersion();
MatchList = new List<MatchRecord>();
KeyedTagInfoLists = new Dictionary<string, List<TagInfo>>();
KeyedSortedTagInfoLists = new Dictionary<string, List<TagInfo>>();
//read default/user preferences on what tags to report presence on and groupings
TagGroupPreferences = JsonConvert.DeserializeObject<List<TagCategory>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagGroupPref)));
ExcludeRollup = excludeRollup;
SimpleTagsOnly = simpleTagsOnly;
UniqueTagsOnly = uniqueTagsOnly;
MetaData = new AppMetaData(sourcePath, rulePaths)
{
RulePaths = rulePaths.ToHashSet<string>()
};
}
/// <summary>
/// Aggregate tags found into lists by organizing into customer preferred
/// groups of taginfo objects
/// TagGroupPreferences are organized by category i.e. profile or composition pages then by groups within
/// file to be read
/// </summary>
public void PrepareReport()
{
//start with all unique tags to initialize which is then used to sort into groups of tagInfo lists
MetaData.UniqueTags = GetUniqueTags();
foreach (TagCategory CategoryTagGroup in TagGroupPreferences)
{
foreach (TagGroup tagGroup in CategoryTagGroup.Groups)
{
foreach (TagSearchPattern pattern in tagGroup.Patterns)
pattern.Detected = MetaData.UniqueTags.Any(v => v.Contains(pattern.SearchPattern));
}
}
//create simple ranked page lists for sorted display for app defined report page
KeyedSortedTagInfoLists["tagGrpAllTagsByConfidence"] = GetTagInfoListByConfidence();
KeyedSortedTagInfoLists["tagGrpAllTagsBySeverity"] = GetTagInfoListBySeverity();
KeyedSortedTagInfoLists["tagGrpAllTagsByName"] = GetTagInfoListByName();
//create dynamic "category" groups of tags with pattern relationship established from TagReportGroups.json
//that can be used to populate reports with various attributes for each tag detected
foreach (TagCategory tagCategory in TagGroupPreferences)
{
foreach (TagGroup group in tagCategory.Groups)
{
if (tagCategory.Type == TagCategory.tagInfoType.uniqueTags)
KeyedTagInfoLists["tagGrp" + group.DataRef] = GetUniqueMatchingTagInfoList(group);
else if (tagCategory.Type == TagCategory.tagInfoType.allTags)
KeyedTagInfoLists["tagGrp" + group.DataRef] = GetAllMatchingTagInfoList(group);
}
}
//TBD: Alternative to use here instead of AnalyzeCommand
//What is missed if called here instead of Analyze which may not add duplicates?
//allow each record to be tested for presence of customizable preferred tags
/*foreach (MatchRecord matchRecord in MatchList)
{
MetaData.AddStandardProperties(matchRecord);
}*/
}
#region TagListGroupingMethods
/// <summary>
/// Retrieve the set of groups of tags for specified file section in TagReportGroups.json read previously i.e. in PrepareReport
/// </summary>
/// <param name="category"></param>
/// <returns></returns>
public List<TagInfo> GetTagInfoList(string category)
{
List<TagInfo> result = new List<TagInfo>();
List<TagGroup> tagGroups = GetCategoryTagGroups(category);
foreach (TagGroup group in tagGroups)
{
result.AddRange(KeyedTagInfoLists["tagGrp" + group.DataRef]);
}
return result;
}
/// <summary>
/// Get a list of taggroups for a given file name e.g. profile or composition
/// </summary>
/// <param name="category"></param>
/// <returns></returns>
public List<TagGroup> GetCategoryTagGroups(string category)
{
List<TagGroup> result = new List<TagGroup>();
foreach (TagCategory categoryTagGroup in TagGroupPreferences)
{
if (categoryTagGroup.Name == category)
{
result = categoryTagGroup.Groups;
break;
}
}
return result;
}
private HashSet<string> GetUniqueTags()
{
HashSet<string> results = new HashSet<string>();
foreach (MatchRecord match in MatchList)
{
foreach (string tag in match.Issue.Rule.Tags)
results.Add(tag);
}
return results;
}
/// <summary>
/// Builds list of matching tags by profile pattern
/// Ensures only one instance of a given tag in results unlike GetAllMatchingTags method
/// </summary>
/// <param name="tagPattern"></param>
/// <returns></returns>
private List<TagInfo> GetUniqueMatchingTagInfoList(TagGroup tagGroup, bool addNotFound=true)
{
List<TagInfo> result = new List<TagInfo>();
HashSet<string> hashSet = new HashSet<string>();
foreach (TagSearchPattern pattern in tagGroup.Patterns)
{
if (pattern.Detected)//set at program.RollUp already so don't search for again
{
var tagPatternRegex = new Regex(pattern.SearchPattern, RegexOptions.IgnoreCase);
foreach (var match in MatchList)
{
foreach (var tagItem in match.Issue.Rule.Tags)
{
if (tagPatternRegex.IsMatch(tagItem))
{
if (!hashSet.Contains(pattern.SearchPattern))
{
result.Add(new TagInfo
{
Tag = tagItem,
Confidence = match.Issue.Confidence.ToString(),
Severity = match.Issue.Rule.Severity.ToString(),
ShortTag = pattern.DisplayName,
StatusIcon = pattern.DetectedIcon,
Detected = true
}) ;
hashSet.Add(pattern.SearchPattern);
}
else //already have in results but...
{//ensure we have highest confidence, severity as there are likly multiple matches for this tag pattern
foreach (TagInfo updateItem in result)
{
if (updateItem.Tag == tagItem)
{
DevSkim.Confidence oldConfidence;
Enum.TryParse(updateItem.Confidence, out oldConfidence);
if (match.Issue.Confidence > oldConfidence)
{
updateItem.Confidence = match.Issue.Confidence.ToString();
}
DevSkim.Severity oldSeverity;
Enum.TryParse(updateItem.Severity, out oldSeverity);
if (match.Issue.Rule.Severity > oldSeverity)
{
updateItem.Severity = match.Issue.Rule.Severity.ToString();
}
break;
}
}
}
}
}
}
}
else if (addNotFound) //allow page to report on false presense items
{
TagInfo tagInfo = new TagInfo
{
Tag = pattern.SearchPattern,
Detected = false,
ShortTag = pattern.DisplayName,
StatusIcon = pattern.NotDetectedIcon,
Confidence = "",
Severity = ""
};
result.Add(tagInfo);
hashSet.Add(tagInfo.Tag);
}
}
return result;
}
/// <summary>
/// Gets a set of matching tags for a set of patterns returning for all matches
/// </summary>
/// <param name="patterns"></param>
/// <param name="addNotFound"></param>
/// <returns></returns>
private List<TagInfo> GetAllMatchingTagInfoList(TagGroup tagGroup, bool addNotFound = true)
{
List<TagInfo> result = new List<TagInfo>();
HashSet<string> hashSet = new HashSet<string>();
foreach (TagSearchPattern pattern in tagGroup.Patterns)
{
if (pattern.Detected)
{
var tagPatternRegex = new Regex(pattern.SearchPattern, RegexOptions.IgnoreCase);
foreach (var match in MatchList)
{
foreach (var tagItem in match.Issue.Rule.Tags)
{
if (tagPatternRegex.IsMatch(tagItem))
{
if (!hashSet.Contains(tagItem))
{
result.Add(new TagInfo
{
Tag = tagItem,
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
Severity = match.Issue.Rule.Severity.ToString(),
ShortTag = tagItem.Substring(tagItem.LastIndexOf('.') + 1),
StatusIcon = pattern.DetectedIcon,
Detected = true
});
hashSet.Add(tagItem);
}
else
{//ensure we have highest confidence, severity as there are likly multiple matches for this tag pattern
foreach (TagInfo updateItem in result)
{
if (updateItem.Tag == tagItem)
{
DevSkim.Confidence oldConfidence;
Enum.TryParse(updateItem.Confidence, out oldConfidence);
if (match.Issue.PatternMatch.Confidence > oldConfidence)
{
updateItem.Confidence = match.Issue.PatternMatch.Confidence.ToString();
}
DevSkim.Severity oldSeverity;
Enum.TryParse(updateItem.Severity, out oldSeverity);
if (match.Issue.Rule.Severity > oldSeverity)
{
updateItem.Severity = match.Issue.Rule.Severity.ToString();
}
break;
}
}
}
}
}
}
}
}
return result;
}
#endregion
#region SortTagsMethods
/// <summary>
/// List of taginfo items ordered by name
/// </summary>
/// <returns></returns>
private List<TagInfo> GetTagInfoListByName()
{
List<string> orderedTags = MetaData.UniqueTags.ToList<string>();
orderedTags.Sort();
HashSet<string> dupCheck = new HashSet<string>();
List<TagInfo> result = new List<TagInfo>();
foreach (string tag in orderedTags)
{
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
foreach (var match in MatchList)
{
foreach (string testTag in match.Issue.Rule.Tags)
{
if (searchPattern.IsMatch(tag) && dupCheck.Add(testTag))
{
result.Add(new TagInfo
{
Tag = testTag,
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
Severity = match.Issue.Rule.Severity.ToString(),
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
});
break;
}
}
}
}
return result;
}
/// <summary>
/// Tags sorted by confidence
/// Todo: address array of tags in rule
/// </summary>
/// <returns></returns>
private List<TagInfo> GetTagInfoListByConfidence()
{
List<TagInfo> result = new List<TagInfo>();
HashSet<string> dupCheck = new HashSet<string>();
DevSkim.Confidence[] confidences = { Confidence.High, Confidence.Medium, Confidence.Low };
foreach (Confidence test in confidences)
{
foreach (string tag in MetaData.UniqueTags)
{
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
foreach (var match in MatchList)
{
foreach (string testTag in match.Issue.Rule.Tags)
{
if (searchPattern.IsMatch(testTag))
{
if (match.Issue.PatternMatch.Confidence == test && dupCheck.Add(tag))
result.Add(new TagInfo
{
Tag = testTag,
Confidence = test.ToString(),
Severity = match.Issue.Rule.Severity.ToString(),
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
});
}
}
}
}
}
return result;
}
/// <summary>
/// Sorted by Severity
/// </summary>
/// <returns></returns>
private List<TagInfo> GetTagInfoListBySeverity()
{
List<TagInfo> result = new List<TagInfo>();
HashSet<string> dupCheck = new HashSet<string>();
DevSkim.Severity[] severities = { Severity.Critical, Severity.Important, Severity.Moderate, Severity.BestPractice, Severity.ManualReview };
foreach (Severity test in severities)
{
foreach (string tag in MetaData.UniqueTags)
{
var searchPattern = new Regex(tag, RegexOptions.IgnoreCase);
foreach (var match in MatchList)
{
foreach (string testTag in match.Issue.Rule.Tags)
{
if (searchPattern.IsMatch(testTag))
{
if (match.Issue.Rule.Severity == test && dupCheck.Add(tag))
result.Add(new TagInfo
{
Tag = testTag,
Confidence = match.Issue.PatternMatch.Confidence.ToString(),
Severity = test.ToString(),
ShortTag = testTag.Substring(testTag.LastIndexOf('.') + 1),
});
}
}
}
}
}
return result;
}
#endregion
}
/// <summary>
/// Contains meta data elements around the source scanned
/// Contains rollup data for reporting purposes
/// </summary>
[Serializable]
public class AppMetaData
{
//Multi-list of elements makes it easier to pass to HTML template engine -direct getters also work
[JsonIgnore]
private Dictionary<string, string> _propertyTagSearchPatterns;
[JsonIgnore] //named properties below will handle for serialization
public Dictionary<string, HashSet<string>> KeyedPropertyLists { get; }
public AppMetaData(string sourcePath, List<string> rulePaths)
{
//Initial value for ApplicationName may be replaced if rule pattern match found later
if (Directory.Exists(sourcePath))
{
try
{
ApplicationName = sourcePath.Substring(sourcePath.LastIndexOf(Path.DirectorySeparatorChar)).Replace(Path.DirectorySeparatorChar, ' ').Trim();
}
catch (Exception)
{
ApplicationName = Path.GetFileNameWithoutExtension(sourcePath);
}
}
else
{
ApplicationName = Path.GetFileNameWithoutExtension(sourcePath);
}
//initialize set groups of dynamic lists variables that may have more than one value; some are filled
//using tag tests and others by different means like file type examination
KeyedPropertyLists = new Dictionary<string, HashSet<string>>
{
["strGrpRulePaths"] = rulePaths.ToHashSet(),
["strGrpPackageTypes"] = new HashSet<string>(),
["strGrpAppTypes"] = new HashSet<string>(),
["strGrpFileTypes"] = new HashSet<string>(),
["strGrpUniqueTags"] = new HashSet<string>(),
["strGrpOutputs"] = new HashSet<string>(),
["strGrpTargets"] = new HashSet<string>(),
["strGrpOSTargets"] = new HashSet<string>(),
["strGrpFileExtensions"] = new HashSet<string>(),
["strGrpFileNames"] = new HashSet<string>(),
["strGrpCPUTargets"] = new HashSet<string>(),
["strGrpCloudTargets"] = new HashSet<string>(),
["strGrpUniqueDependencies"] = new HashSet<string>()
};
//predefined standard tags to track; only some are propertygrouplist are tag based
_propertyTagSearchPatterns = new Dictionary<string, string>();
_propertyTagSearchPatterns.Add("strGrpOSTargets", ".OS.Targets");
_propertyTagSearchPatterns.Add("strGrpCloudTargets", ".Cloud");
_propertyTagSearchPatterns.Add("strGrpOutputs", ".Outputs");
_propertyTagSearchPatterns.Add("strGrpCPUTargets", ".CPU");
//read default/user preferences on what tags to count
TagCounters = JsonConvert.DeserializeObject<List<TagCounter>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagCounterPref)));
HashSet<string> dupCountersCheck = new HashSet<string>();
foreach (TagCounter counter in TagCounters)
if (!dupCountersCheck.Add(counter.Tag))
throw new Exception("Duplicate tagCounter found in TagCounters.json preferences file");
Languages = new Dictionary<string, int>();
}
public void AddLanguage(string language)
{
if (Languages.ContainsKey(language))
Languages[language]++;
else
Languages.Add(language, 1);
}
//simple properties
[JsonProperty(PropertyName = "applicationName")]
public string ApplicationName { get; set; }
[JsonProperty(PropertyName = "sourceVersion")]
public string SourceVersion { get; set; }
[JsonProperty(PropertyName = "authors")]
public string Authors { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
private DateTime _lastUpdated = DateTime.MinValue;
[JsonProperty(PropertyName = "lastUpdated")]
public string LastUpdated { get; set; }
//stats
[JsonProperty(PropertyName = "filesAnalyzed")]
public int FilesAnalyzed { get; set; }
[JsonProperty(PropertyName = "totalFiles")]
public int TotalFiles { get; set; }
[JsonProperty(PropertyName = "filesSkipped")]
public int FilesSkipped { get; set; }
[JsonProperty(PropertyName = "filesAffected")]
public int FilesAffected { get; set; }
//following "counter" methods can not use enumeration on matches list which are unique by default
[JsonProperty(PropertyName = "totalMatchesCount")]
public int TotalMatchesCount { get; set; }
[JsonProperty(PropertyName = "uniqueMatchesCount")]
public int UniqueMatchesCount { get { return UniqueTags.Count; } }
[JsonIgnore]
public Dictionary<string, TagCounter> KeyedPropertyCounters { get; }
[JsonProperty("selectTagCounters")]
public List<TagCounter> TagCounters { get; }
//predefined lists in KeyedPropertyLists for easy retrieval and loose coupling
[JsonProperty(PropertyName = "packageTypes")]
public HashSet<string> PackageTypes { get { return KeyedPropertyLists["strGrpPackageTypes"]; } }
[JsonProperty(PropertyName = "appTypes")]
public HashSet<string> AppTypes { get { return KeyedPropertyLists["strGrpAppTypes"]; } }
[JsonIgnore]
public HashSet<string> RulePaths { get { return KeyedPropertyLists["strGrpRulePaths"]; } set { KeyedPropertyLists["strGrpRulePaths"] = value; } }
[JsonIgnore]
public HashSet<string> FileNames { get { return KeyedPropertyLists["strGrpFileNames"]; } }
[JsonProperty(PropertyName = "uniqueTags")]
public HashSet<string> UniqueTags
{
get
{
return KeyedPropertyLists["strGrpUniqueTags"];
}
set
{
KeyedPropertyLists["strGrpUniqueTags"] = value;
}
}
//convenience getters for standard lists of values
[JsonProperty(PropertyName = "uniqueDependencies")]
public HashSet<string> UniqueDependencies { get { return KeyedPropertyLists["strGrpUniqueDependencies"]; } }
[JsonProperty(PropertyName = "outputs")]
public HashSet<string> Outputs { get { return KeyedPropertyLists["strGrpOutputs"]; } }
[JsonProperty(PropertyName = "targets")]
public HashSet<string> Targets { get { return KeyedPropertyLists["strGrpTargets"]; } }
[JsonProperty(PropertyName = "languages")]
public Dictionary<string, int> Languages;
[JsonProperty(PropertyName = "OSTargets")]
public HashSet<string> OSTargets { get { return KeyedPropertyLists["strGrpOSTargets"]; } }
[JsonProperty(PropertyName = "fileExtensions")]
public HashSet<string> FileExtensions
{ get { return KeyedPropertyLists["strGrpFileExtensions"]; } }
[JsonProperty(PropertyName = "cloudTargets")]
public HashSet<string> CloudTargets { get { return KeyedPropertyLists["strGrpCloudTargets"]; } }
[JsonProperty(PropertyName = "CPUTargets")]
public HashSet<string> CPUTargets { get { return KeyedPropertyLists["strGrpCPUTargets"]; } }
private string ExtractJSONValue(string s)
{
try
{
var parts = s.Split(':');
var value = parts[1];
value = value.Replace("\"", "");
value = value.Trim();
return value;
} catch(Exception)
{
return s;
}
}
/// <summary>
/// Part of post processing to test for matches against app defined properties
/// defined in MetaData class
/// TODO: decide if we can just call from AppProfile PrepareReport instead
/// </summary>
/// <param name="matchRecord"></param>
public bool AddStandardProperties(MatchRecord matchRecord)
{
bool includeAsMatch = true;
//standard testing for presence of a tag against the preffered set of tags
foreach (string key in _propertyTagSearchPatterns.Keys)
{
var tagPatternRegex = new Regex(_propertyTagSearchPatterns[key], RegexOptions.IgnoreCase);
if (matchRecord.Issue.Rule.Tags.Any(v => tagPatternRegex.IsMatch(v)))
{
KeyedPropertyLists[key].Add(matchRecord.TextSample);
}
}
//update counts for default or user specified tags
foreach (TagCounter counter in TagCounters)
{
if (matchRecord.Issue.Rule.Tags.Any(v => v.Contains(counter.Tag)))
{
counter.Count++;
includeAsMatch = counter.IncludeAsMatch;
}
}
// Author
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Author"))
this.Authors = ExtractJSONValue(matchRecord.TextSample);
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Description"))
this.Description = ExtractJSONValue(matchRecord.TextSample);
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Name"))
this.ApplicationName = ExtractJSONValue(matchRecord.TextSample);
if (matchRecord.Issue.Rule.Tags.Contains("Metadata.Application.Version"))
this.SourceVersion = ExtractJSONValue(matchRecord.TextSample);
//special handling; attempt to detect app types...review for multiple tag limiation
String solutionType = Helper.DetectSolutionType(matchRecord.Filename, matchRecord.Language, matchRecord.Issue.Rule.Tags[0], matchRecord.TextSample);
if (!string.IsNullOrEmpty(solutionType) && !AppTypes.Contains(solutionType))
AppTypes.Add(solutionType);
#region wip
//special handling solution name; for efficency (?) use separate tests; note Tags is not an ienumerable
//TODO this needs work as the text sample of PY projects is not compatible; check Rule accuracy
/*
foreach (string tag in matchRecord.Issue.Rule.Tags)
{
if (tag.Contains("Solution.Name"))
{
int index = matchRecord.TextSample.IndexOf("\"");
if (-1 != index)
{
ApplicationName = matchRecord.TextSample.Substring(index + 1);
ApplicationName = ApplicationName.Replace("\"", "");
ApplicationName = ApplicationName.Trim();
}
else
ApplicationName = matchRecord.TextSample;
break;
}
}
//special handling for version possible format of textMatch i.e. <version="1.0"...
foreach (string tag in matchRecord.Issue.Rule.Tags)
{
if (tag.Contains("Solution.Version"))
{
int index = matchRecord.TextSample.IndexOf("\"");
if (-1 != index)
{
SourceVersion = matchRecord.TextSample.Substring(index + 1);
index = SourceVersion.IndexOf("\"");
if (-1 != index)
SourceVersion = SourceVersion.Substring(0, index);
SourceVersion = SourceVersion.Trim();
}
else
SourceVersion = System.Net.WebUtility.HtmlEncode(matchRecord.TextSample);
break;
}
}*/
#endregion
return includeAsMatch;
}
}
}

Просмотреть файл

@ -0,0 +1,686 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using ICSharpCode.SharpZipLib.GZip;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using MimeTypes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ICSharpCode.SharpZipLib.Core;
using Microsoft.AppInspector.CLI.Writers;
using Microsoft.DevSkim;
using System.Text.RegularExpressions;
using System.Text;
using Newtonsoft.Json;
using System.Diagnostics;
namespace Microsoft.AppInspector.CLI.Commands
{
public class AnalyzeCommand : ICommand
{
readonly int MAX_FILESIZE = 1024 * 1000 * 5; // Do not analyze files larger than 5 MB
// Enable processing compressed files
readonly string[] COMPRESSED_EXTENSIONS = "zip,gz,gzip,gem,tar,tgz,tar.gz,xz,7z".Split(",");
Regex IgnoreMimeRegex;
public enum ExitCode
{
NoMatches = 0,
MatchesFound = 1,
CriticalError = 2
}
AppProfile _appProfile;
RuleProcessor _rulesProcessor;
Writer _outputWriter;
DateTime DateScanned { get; set; }
DateTime _lastUpdated;
public DateTime LastUpdated
{
get { return _lastUpdated; }
set
{
//find last updated file in solution
if (_lastUpdated < value)
_lastUpdated = value;
}
}
//cmdline arguments
private string _arg_sourcePath;
private string _arg_outputFile;
private string _arg_fileFormat;
private string _arg_outputTextFormat;
private string _arg_customRulePath;
private bool _arg_ignoreDefaultRules;
private bool _arg_outputUniqueTagsOnly;
private string _arg_confidenceFilters;
private bool _arg_simpleTagsOnly;
private Confidence _arg_confidence;
private WriteOnce.ConsoleVerbosityLevel _arg_consoleVerbosityLevel;
public AnalyzeCommand(AnalyzeCommandOptions opts)
{
_arg_sourcePath = opts.SourcePath;
_arg_outputFile = opts.OutputFilePath;
_arg_fileFormat = opts.OutputFileFormat;
_arg_outputTextFormat = opts.TextOutputFormat;
_arg_outputUniqueTagsOnly = opts.UniqueTagsOnly;
_arg_customRulePath = opts.CustomRulesPath;
_arg_confidenceFilters = opts.ConfidenceFilters;
_arg_ignoreDefaultRules = opts.IgnoreDefaultRules;
_arg_simpleTagsOnly = opts.SimpleTagsOnly;
Enum.TryParse(opts.ConsoleVerbosityLevel, true, out _arg_consoleVerbosityLevel);
WriteOnce.Verbosity = _arg_consoleVerbosityLevel;
IgnoreMimeRegex = new Regex(@"^(audio|video)/.*$");
//quick validations and setup
if (!Directory.Exists(_arg_sourcePath) && !File.Exists(_arg_sourcePath))
{
string errorMsg = string.Format("Invalid source file or directory{0}", _arg_sourcePath);
WriteOnce.Error(errorMsg);
throw new Exception(errorMsg);
}
LastUpdated = DateTime.MinValue;
DateScanned = DateTime.Now;
ConfigureConfidenceFilters();
ConfigRules();
ConfigOutput();
}
#region configureMethods
/// <summary>
/// Expects user to supply all that apply
/// </summary>
void ConfigureConfidenceFilters()
{
//parse and verify confidence values
if (String.IsNullOrEmpty(_arg_confidenceFilters))
_arg_confidence = Confidence.High | Confidence.Medium; //excludes low by default
else
{
string[] confidences = _arg_confidenceFilters.Split(',');
foreach (string confidence in confidences)
{
Confidence single;
if (Enum.TryParse(confidence, true, out single))
_arg_confidence |= single;
else
throw new Exception("Invalid run argument value for -x");
}
}
}
/// <summary>
/// Add default and/or custom rules paths
/// Iterate paths and add to ruleset
/// </summary>
void ConfigRules()
{
RuleSet rulesSet = new RuleSet(Program.Logger);
List<string> rulePaths = new List<string>();
if (!_arg_ignoreDefaultRules)
rulePaths.Add(Helper.GetPath(Helper.AppPath.defaultRules));
if (!string.IsNullOrEmpty(_arg_customRulePath))
rulePaths.Add(_arg_customRulePath);
foreach (string rulePath in rulePaths)
{
if (Directory.Exists(rulePath))
rulesSet.AddDirectory(rulePath);
else
rulesSet.AddFile(rulePath);
}
//error check based on ruleset not path enumeration
if (rulesSet.Count() == 0)
{
WriteOnce.Error("No rules specified");
throw new Exception("No rules specified");
}
//instantiate a RuleProcessor with the added rules and exception for dependency
_rulesProcessor = new RuleProcessor(rulesSet, _arg_confidence, _arg_outputUniqueTagsOnly, _arg_simpleTagsOnly, Program.Logger);
if (_arg_outputUniqueTagsOnly)
{
List<TagException> tagExceptions = JsonConvert.DeserializeObject<List<TagException>>(File.ReadAllText(Helper.GetPath(Helper.AppPath.tagCounterPref)));
string[] exceptions = new string[tagExceptions.Count];
for (int i=0;i<tagExceptions.Count;i++)
exceptions[i] = tagExceptions[i].Tag;
_rulesProcessor.UniqueTagExceptions = exceptions;
}
_appProfile = new AppProfile(_arg_sourcePath, rulePaths, false, _arg_simpleTagsOnly, _arg_outputUniqueTagsOnly);
_appProfile.Args = "analyze -f " + _arg_fileFormat + " -u " + _arg_outputUniqueTagsOnly.ToString().ToLower() + " -v " +
WriteOnce.Verbosity.ToString() + " -x " + _arg_confidence + " -i " + _arg_ignoreDefaultRules.ToString().ToLower();
}
void ConfigOutput()
{
//Set output type, format and outstream
_outputWriter = WriterFactory.GetWriter(_arg_fileFormat ?? "text", (string.IsNullOrEmpty(_arg_outputFile)) ? null : "text", _arg_outputTextFormat);
if (!string.IsNullOrEmpty(_arg_outputFile))
{
if (_arg_fileFormat != "html")
_outputWriter.TextWriter = File.CreateText(_arg_outputFile);//not needed if html output since application controlled
}
else
_outputWriter.TextWriter = Console.Out;
}
#endregion
/// <summary>
/// Main entry point to start analysis; handles setting up rules, directory enumeration
/// file type detection and handoff
/// </summary>
/// <returns></returns>
public int Run()
{
DateTime start = DateTime.Now;
WriteOnce.Write("Analyze command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
//if it's a file, make an IEnumerable out of it.
IEnumerable<string> fileList;
if (!Directory.Exists(_arg_sourcePath))
fileList = new List<string>() { _arg_sourcePath };
else
fileList = Directory.EnumerateFiles(_arg_sourcePath, "*.*", SearchOption.AllDirectories);
_appProfile.MetaData.TotalFiles = fileList.Count();
// Iterate through all files and process against rules
foreach (string filename in fileList)
{
var fileExtension = new FileInfo(filename).Extension;
if (COMPRESSED_EXTENSIONS.Any(fileExtension.Contains))
ExpandAndProcess(filename);
else
ProcessAsFile(filename);
//progress report
int totalFilesReviewed = _appProfile.MetaData.FilesAnalyzed + _appProfile.MetaData.FilesSkipped;
int percentCompleted = (int)((float)totalFilesReviewed / (float)_appProfile.MetaData.TotalFiles * 100);
WriteOnce.Write(string.Format("\r{0}% source files processed", percentCompleted), ConsoleColor.Gray, WriteOnce.ConsoleVerbosityLevel.Medium);
}
//prepare summary report
WriteOnce.Write(string.Format("\r100% applicable files processed\t\t\t\t"), ConsoleColor.Gray, WriteOnce.ConsoleVerbosityLevel.Medium);
WriteOnce.NewLine();
WriteOnce.Info("Preparing report...");
_appProfile.MetaData.LastUpdated = LastUpdated.ToString();
_appProfile.DateScanned = DateScanned.ToString();
_appProfile.PrepareReport();
//close output files
FlushAll();
if (_appProfile.MetaData.TotalFiles == _appProfile.MetaData.FilesSkipped)
WriteOnce.Error("No file types found in source path that are supported.");
else if (_appProfile.MatchList.Count == 0)
WriteOnce.Error("No pattern matches were detected for files in source path.");
else
WriteOnce.Any("Report complete.", ConsoleColor.Cyan);
TimeSpan timeSpan = start - DateTime.Now;
Program.Logger.Trace(String.Format("Processing time: seconds:{0}", timeSpan.TotalSeconds*-1));
return _appProfile.MatchList.Count() == 0 ? (int)ExitCode.NoMatches :
(int)ExitCode.MatchesFound;
}
/// <summary>
/// Wrapper for files that are on disk and ready to read
/// </summary>
/// <param name="filename"></param>
void ProcessAsFile(string filename)
{
_appProfile.MetaData.FileNames.Add(filename);
_appProfile.MetaData.PackageTypes.Add("uncompressed");
if (new System.IO.FileInfo(filename).Length > MAX_FILESIZE)
{
Program.Logger.Error(filename + " is too large. File skipped");
_appProfile.MetaData.FilesSkipped++;
return;
}
string fileText = File.ReadAllText(filename);
ProcessInMemory(filename, fileText);
}
/// <summary>
/// Main WORKHORSE for analyzing file; called directly from decompression functions
/// </summary>
/// <param name="filename"></param>
/// <param name="fileText"></param>
void ProcessInMemory(string filePath, string fileText)
{
if (fileText.Length > MAX_FILESIZE)
{
Program.Logger.Error(filePath + " is too large. File skipped");
_appProfile.MetaData.FilesSkipped++;
return;
}
//determine if file is a compressed item to unpackage for processing
string language = Language.FromFileName(filePath);
// Skip files written in unknown language
if (string.IsNullOrEmpty(language))
{
Program.Logger.Trace("Language not found for file: " + filePath);
Program.Logger.Trace("But processing anyway: " + filePath);
language = Path.GetFileName(filePath);
_appProfile.MetaData.FilesSkipped++;
return;
}
else
{
Program.Logger.Trace("Preparing to process file: " + filePath);
}
#region minorRollupTracking
_appProfile.MetaData.FilesAnalyzed++;
_appProfile.MetaData.AddLanguage(language);
_appProfile.MetaData.FileExtensions.Add(Path.GetExtension(filePath).Replace('.', ' ').TrimStart());
LastUpdated = File.GetLastWriteTime(filePath);
#endregion
//process file against rules
Issue[] matches = _rulesProcessor.Analyze(fileText, language);
//if any matches found for this file...
if (matches.Count() > 0)
{
_appProfile.MetaData.FilesAffected++;
_appProfile.MetaData.TotalMatchesCount += matches.Count();
HashSet<string> uniqueTagsControl = new HashSet<string>();
// Iterate through each match issue
foreach (Issue match in matches)
{
Program.Logger.Trace("Processing pattern matches for ruleId {0}, ruleName {1} file {2}", match.Rule.Id, match.Rule.Name, filePath);
//maintain a list of unique tags; multi-purpose but primarily for filtering -u option
bool dupTagFound = false;
foreach (string t in match.Rule.Tags)
dupTagFound = !uniqueTagsControl.Add(t);
//all unique dependendencies saved even if this tag pattern is not-unique
var tagPatternRegex = new Regex("Dependency.SourceInclude", RegexOptions.IgnoreCase);
String textMatch;
if (match.Rule.Tags.Any(v => tagPatternRegex.IsMatch(v)))
textMatch = ExtractDependency(fileText, match.Boundary.Index, match.PatternMatch, language);
else
textMatch = ExtractTextSample(fileText, match.Boundary.Index, match.Boundary.Length);
//TODO put all this in Issue class and avoid new wrapper type
MatchRecord record = new MatchRecord()
{
Filename = filePath,
Language = language,
Filesize = fileText.Length,
TextSample = textMatch,
Excerpt = ExtractExcerpt(fileText, match.StartLocation.Line),
Issue = match
};
//preserve issue level characteristics as rolled up meta data of interest
bool valid = _appProfile.MetaData.AddStandardProperties(record);
//bail after extracting any dependency unique items IF user requested
if (_arg_outputUniqueTagsOnly && dupTagFound)
continue;
else if (valid)
_appProfile.MatchList.Add(record);
}
}
else
{
Program.Logger.Trace("No pattern matches detected for file: " + filePath);
}
}
#region PostRulesMatchProcessingAssist
/// <summary>
/// Simple but keeps calling code consistent
/// </summary>
/// <param name="fileText"></param>
/// <param name="index"></param>
/// <param name="length"></param>
/// <returns></returns>
string ExtractTextSample(string fileText, int index, int length)
{
string result = "";
try
{
result = fileText.Substring(index, length).Trim();
}
catch (Exception)
{
//control the error description and continue; error in devskim possible
Program.Logger.Error("Unexpected indexing issue in ExtractTextSample");
}
return result;
}
/// <summary>
/// Helper to special case additional processing to just get the values without the import keywords etc.
/// and encode for html output
/// </summary>
/// <param name="text"></param>
/// <param name="language"></param>
/// <returns></returns>
string ExtractDependency(string text, int startIndex, SearchPattern pattern, string language)
{
// import value; load value; include value;
string rawResult = "";
int endIndex = text.IndexOf('\n', startIndex);
if (-1 != startIndex && -1 != endIndex)
{
rawResult = text.Substring(startIndex, endIndex - startIndex).Trim();
//recreate regex used to find entire value
Regex regex = new Regex(pattern.Pattern);
MatchCollection matches = regex.Matches(rawResult);
//remove surrounding import or trailing comments
if (matches.Count > 0)
{
foreach (Match match in matches)
{
if (match.Groups.Count == 1)//handles cases like "using Newtonsoft.Json"
{
string[] parseValues = match.Groups[0].Value.Split(' ');
if (parseValues.Length == 1)
rawResult = parseValues[0].Trim();
else if (parseValues.Length > 1)
rawResult = parseValues[1].Trim(); //should be value; time will tell if fullproof
}
else if (match.Groups.Count > 1)//handles cases like include <stdio.h>
rawResult = match.Groups[1].Value.Trim();
//else if > 2 too hard to match; do nothing
break;//only designed to expect one match per line i.e. not include value include value
}
}
String finalResult = rawResult.Replace(";", "");
_appProfile.MetaData.UniqueDependencies.Add(finalResult);
return System.Net.WebUtility.HtmlEncode(finalResult);
}
return rawResult;
}
/// <summary>
/// Located here to include during Match creation to avoid a call later or putting in constructor
/// Needed in match ensuring value exists at time of report writing rather than expecting a callback
/// from the template
/// </summary>
/// <param name="fileName"></param>
/// <param name="startLineNumber"></param>
/// <param name="length"></param>
/// <returns></returns>
private string ExtractExcerpt(string text, int startLineNumber, int length = 10)
{
if (String.IsNullOrEmpty(text))
{
return "";
}
var lines = text.Split('\n');
var distance = (int)((length - 1.0) / 2.0);
// Sanity check
if (startLineNumber < 0) startLineNumber = 0;
if (startLineNumber >= lines.Length) startLineNumber = lines.Length - 1;
var excerptStartLine = Math.Max(0, startLineNumber - distance);
var excerptEndLine = Math.Min(lines.Length - 1, startLineNumber + distance);
/* This is a little wacky, but if the code snippet we're viewing is already
* indented 16 characters minimum, we don't want to show all that extra white-
* space, so we'll find the smallest number of spaces at the beginning of
* each line and use that.
*/
var n = (int)Math.Floor(Math.Log10(excerptEndLine) + 1);
var minSpaces = -1;
for (var i = excerptStartLine; i <= excerptEndLine; i++)
{
var numPrefixSpaces = lines[i].TakeWhile(c => c == ' ').Count();
minSpaces = (minSpaces == -1 || numPrefixSpaces < minSpaces) ? numPrefixSpaces : minSpaces;
}
var sb = new StringBuilder();
// We want to go from (start - 5) to (start + 5) (off by one?)
// LINE=10, len=5, we want 8..12, so N-(L-1)/2 to N+(L-1)/2
// But cap those values at 0/end
for (var i = excerptStartLine; i <= excerptEndLine; i++)
{
string line = lines[i].Substring(minSpaces).TrimEnd();
sb.AppendLine(line);
//string line = System.Net.WebUtility.HtmlEncode(lines[i].Substring(minSpaces).TrimEnd());
//sb.AppendFormat("{0} {1}\n", (i + 1).ToString().PadLeft(n, ' '), line);
}
return System.Convert.ToBase64String(Encoding.UTF8.GetBytes(sb.ToString()));
}
public void FlushAll()
{
if (_outputWriter != null)
{
_outputWriter.WriteApp(_appProfile);
if (_outputWriter.TextWriter != null && _arg_fileFormat != "html")
{
_outputWriter.FlushAndClose();//not required for html formal i.e. multiple files already closed
_outputWriter = null;
if (!String.IsNullOrEmpty(_arg_outputFile))
WriteOnce.WriteLine(String.Format("See {0}.", _arg_outputFile));
else
WriteOnce.WriteLine("\n");
}
}
}
#endregion
#region ZipDecompression
void ExpandAndProcess(string filename)
{
// Ignore images and other junk like that
var fileExtension = new FileInfo(filename).Extension;
var mimeType = MimeTypeMap.GetMimeType(fileExtension);
bool mimeMatch = false;
if (!IgnoreMimeRegex.IsMatch(mimeType))
{
var isValidExtension = COMPRESSED_EXTENSIONS.Any(fileExtension.Contains);
if (isValidExtension || fileExtension == "ts")
mimeMatch = true;
else if (mimeType.Contains("zip", StringComparison.CurrentCultureIgnoreCase) || // Should have been caught in file extensions above, but still OK.
mimeType.Contains("tar", StringComparison.CurrentCultureIgnoreCase) ||
mimeType.Contains("compressed", StringComparison.CurrentCultureIgnoreCase))
mimeMatch = true;
if (mimeMatch)
{
// Now process the file
switch (fileExtension)
{
case ".tgz":
ProcessTarGzFile(filename);
break;
case ".gz":
if (filename.Contains(".tar.gz"))
{
ProcessTarGzFile(filename);
}
break;
case ".jar":
case ".zip":
ProcessZipFile(filename);
break;
case ".gem":
case ".tar":
case ".nupkg":
Program.Logger.Warn($"Processing of {fileExtension} not implemented yet.");
break;
default:
Program.Logger.Warn("no support for compressed type: " + fileExtension);
break;
}
_appProfile.MetaData.PackageTypes.Add("compressed");
}
else
_appProfile.MetaData.PackageTypes.Add("compressed-unsupported");
}
}
void ProcessZipFile(string filename)
{
Program.Logger.Trace("Analyzing .zip file: [{0}])", filename);
ZipFile zipFile;
int filesCount = 0;
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
using (var memoryStream = new MemoryStream())
{
zipFile = new ZipFile(fileStream);
_appProfile.MetaData.TotalFiles = (int)zipFile.Count;
foreach (ZipEntry zipEntry in zipFile)
{
if (zipEntry.IsDirectory)
{
continue;
}
filesCount++;
byte[] buffer = new byte[4096];
var zipStream = zipFile.GetInputStream(zipEntry);
if (zipEntry.Size > MAX_FILESIZE)
{
_appProfile.MetaData.FilesSkipped++;
Program.Logger.Error(string.Format("{0} in {1} is too large. File skipped", zipEntry.Name, filename));
zipFile.Close();
continue;
}
StreamUtils.Copy(zipStream, memoryStream, buffer);
var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(zipEntry.Name));
if (IgnoreMimeRegex.IsMatch(mimeType) && new FileInfo(filename).Extension != "ts")
{
_appProfile.MetaData.FilesSkipped++;
Program.Logger.Error("Ignoring zip entry [{0}]", zipEntry.Name);
}
else
{
byte[] streamByteArray = memoryStream.ToArray();
ProcessInMemory(Path.GetFileName(zipEntry.Name), Encoding.UTF8.GetString(streamByteArray, 0, streamByteArray.Length));
}
memoryStream.SetLength(0); // Clear out the stream
}
_appProfile.MetaData.TotalFiles += filesCount;
zipFile.Close();
}
}
void ProcessTarGzFile(string filename)
{
Program.Logger.Trace("Analyzing .tar.gz file: [{0}])", filename);
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
using (var gzipStream = new GZipInputStream(fileStream))
using (var memoryStream = new MemoryStream())
{
var tarStream = new TarInputStream(gzipStream);
TarEntry tarEntry;
int filesCount = 0;
while ((tarEntry = tarStream.GetNextEntry()) != null)
{
if (tarEntry.IsDirectory)
{
continue;
}
filesCount++;
tarStream.CopyEntryContents(memoryStream);
if (tarEntry.Size > MAX_FILESIZE)
{
_appProfile.MetaData.FilesSkipped++;
Program.Logger.Error(string.Format("{0} in {1} is too large. File skipped", tarEntry.Name, filename));
tarStream.Close();
continue;
}
var mimeType = MimeTypeMap.GetMimeType(Path.GetExtension(tarEntry.Name));
if (IgnoreMimeRegex.IsMatch(mimeType) && new FileInfo(filename).Extension != "ts")
{
_appProfile.MetaData.FilesSkipped++;
Program.Logger.Error("Ignoring tar entry [{0}]", tarEntry.Name);
}
else
{
//file name may contain slashes; remove prior to call
byte[] streamByteArray = memoryStream.ToArray();
ProcessInMemory(Path.GetFileName(tarEntry.Name), Encoding.UTF8.GetString(streamByteArray, 0, streamByteArray.Length));
}
memoryStream.SetLength(0); // Clear out the stream
}
_appProfile.MetaData.TotalFiles+= filesCount;
tarStream.Close();
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.DevSkim;
namespace Microsoft.AppInspector.CLI.Commands
{
public class ExportTagsCommand : ICommand
{
public enum ExitCode
{
Success = 0,
Error = 1,
CriticalError = 2
}
private string _arg_RulesPath;
private string _arg_outputFile;
public ExportTagsCommand(ExportTagsCommandOptions opt)
{
_arg_RulesPath = opt.CustomRulesPath;
_arg_outputFile = opt.OutputFilePath;
}
public int Run()
{
WriteOnce.Write("Export unique tags command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
if (String.IsNullOrEmpty(_arg_RulesPath))
{
_arg_RulesPath = Helper.GetPath(Helper.AppPath.defaultRules);
}
else if (!Directory.Exists(_arg_RulesPath) && !File.Exists(_arg_RulesPath))
{
WriteOnce.Error(String.Format("Not a valid rule file or directory {0}", _arg_RulesPath));
return (int)ExitCode.CriticalError;
}
//setup output
TextWriter outputWriter;
if (!string.IsNullOrEmpty(_arg_outputFile))
{
outputWriter = File.CreateText(_arg_outputFile);
outputWriter.WriteLine(Program.GetVersionString());
WriteOnce.Writer = outputWriter;
}
else
{
//override user if no output file so output to console appears
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.High;
}
//initialize rules
RuleSet rules = new RuleSet();
rules.AddDirectory(_arg_RulesPath);
SortedDictionary<string, string> uniqueTags = new SortedDictionary<string, string>();
foreach (Rule r in rules)
{
//builds a list of unique tags
foreach (string t in r.Tags)
{
if (uniqueTags.ContainsKey(t))
continue;
else
uniqueTags.Add(t, t);
}
}
//separate loop so results are sorted (Sorted type)
foreach (string s in uniqueTags.Values)
WriteOnce.Any(s, WriteOnce.ConsoleVerbosityLevel.High);
WriteOnce.Any("Export rule tags completed.", ConsoleColor.Cyan);
WriteOnce.FlushAll();
return (int)ExitCode.Success;
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
namespace Microsoft.AppInspector.CLI.Commands
{
public interface ICommand
{
int Run();
}
}

Просмотреть файл

@ -0,0 +1,218 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace Microsoft.AppInspector.CLI.Commands
{
[Serializable]
public class TagsFile
{
[JsonProperty(PropertyName = "tags")]
public string[] Tags { get; set; }
}
/// <summary>
/// Used to compare two source paths and report tag differences
/// </summary>
public class TagDiffCommand : ICommand
{
private string _arg_src1, _arg_src2;
private string _arg_rulesPath;
private string _arg_outputFile;
private bool _arg_ignoreDefault;
private TagTestType _arg_tagTestType;
public enum ExitCode
{
NoDiff = 0,
DiffFound = 1,
CriticalError = 2
}
enum TagTestType { Equality, Inequality }
public TagDiffCommand(TagDiffCommandOptions opt)
{
_arg_src1 = opt.SourcePath1;
_arg_src2 = opt.SourcePath2;
_arg_rulesPath = opt.CustomRulesPath;
_arg_outputFile = opt.OutputFilePath;
WriteOnce.ConsoleVerbosityLevel arg_consoleVerbosityLevel;
Enum.TryParse(opt.ConsoleVerbosityLevel, true, out arg_consoleVerbosityLevel);
WriteOnce.Verbosity = arg_consoleVerbosityLevel;
if (!Enum.TryParse(opt.TestType, true, out _arg_tagTestType))
throw new ArgumentException("Invalid -t argument value", opt.TestType);
_arg_ignoreDefault = opt.IgnoreDefaultRules;
}
public int Run()
{
WriteOnce.Write("TagDiff command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
//setup output
TextWriter outputWriter;
if (!string.IsNullOrEmpty(_arg_outputFile))
{
outputWriter = File.CreateText(_arg_outputFile);
outputWriter.WriteLine(Program.GetVersionString());
WriteOnce.Writer = outputWriter;
}
if (_arg_src1 == _arg_src2)
{
WriteOnce.Error("Same file passed in for both sources. Test terminated.");
return (int)ExitCode.CriticalError;
}
else if (string.IsNullOrEmpty(_arg_src1) || string.IsNullOrEmpty(_arg_src2))
{
WriteOnce.Error("Required [path1] or [path2] argument missing.");
return (int)ExitCode.CriticalError;
}
//save to quiet analyze cmd
WriteOnce.ConsoleVerbosityLevel saveVerbosity = WriteOnce.Verbosity;
string tmp1 = Path.GetTempFileName();
string tmp2 = Path.GetTempFileName();
AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions { SourcePath = _arg_src1,
OutputFilePath = tmp1,
OutputFileFormat = "json",
CustomRulesPath = _arg_rulesPath,
IgnoreDefaultRules = _arg_ignoreDefault,
SimpleTagsOnly = true,
UniqueTagsOnly = true,
ConsoleVerbosityLevel = "Low" });
AnalyzeCommand cmd2 = new AnalyzeCommand(new AnalyzeCommandOptions
{
SourcePath = _arg_src2,
OutputFilePath = tmp2,
OutputFileFormat = "json",
CustomRulesPath = _arg_rulesPath,
IgnoreDefaultRules = _arg_ignoreDefault,
SimpleTagsOnly = true,
UniqueTagsOnly = true,
ConsoleVerbosityLevel = "Low"
});
//quiet analysis commands
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Low;
AnalyzeCommand.ExitCode result1 = AnalyzeCommand.ExitCode.CriticalError;
AnalyzeCommand.ExitCode result2 = AnalyzeCommand.ExitCode.CriticalError;
result1 = (AnalyzeCommand.ExitCode)cmd1.Run();
result2 = (AnalyzeCommand.ExitCode)cmd2.Run();
WriteOnce.Verbosity = saveVerbosity;
bool equal1 = true;
bool equal2 = true;
if (result1 == AnalyzeCommand.ExitCode.CriticalError)
{
WriteOnce.Error("Critical error processing file " + _arg_src1 + ". Check path.");
return (int)ExitCode.CriticalError;
}
else if (result2 == AnalyzeCommand.ExitCode.CriticalError)
{
WriteOnce.Error("Critical error processing file " + _arg_src2 + ". Check path.");
return (int)ExitCode.CriticalError;
}
else if (result1 == AnalyzeCommand.ExitCode.NoMatches || result2 == AnalyzeCommand.ExitCode.NoMatches)
{
WriteOnce.Error("No tags found in one or both source paths");
return (int)ExitCode.CriticalError;
}
else //assumed (result1&2 == AnalyzeCommand.ExitCode.MatchesFound)
{
string file1TagsJson = File.ReadAllText(tmp1);
string file2TagsJson = File.ReadAllText(tmp2);
var file1Tags = JsonConvert.DeserializeObject<TagsFile[]>(file1TagsJson).First();
var file2Tags = JsonConvert.DeserializeObject<TagsFile[]>(file2TagsJson).First();
WriteOnce.Info("TagDiff Report");
//can't simply compare counts as content may differ; must compare both in directions
//first pass
WriteOnce.Any("[Tags in " + Path.GetFileName(_arg_src1) + " not detected in " + Path.GetFileName(_arg_src2) + "]",
ConsoleColor.White, WriteOnce.ConsoleVerbosityLevel.High);
equal1 = CompareTags(file1Tags.Tags, file2Tags.Tags);
//reverse order for second pass
WriteOnce.Any("[Tags in " + Path.GetFileName(_arg_src2) + " not detected in " + Path.GetFileName(_arg_src1) + "]",
ConsoleColor.White, WriteOnce.ConsoleVerbosityLevel.High);
equal2 = CompareTags(file2Tags.Tags, file1Tags.Tags);
//final
WriteOnce.Any(string.Format("Files were {0} to contain differences.",
equal1 && equal2 ? "not found" : "found"), ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
if (_arg_tagTestType == TagTestType.Inequality)
{
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
equal1 && equal2 ? "failed" : "passed"), (equal1 && equal2) ? ConsoleColor.Red : ConsoleColor.Green);
}
else
{
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
equal1 && equal2 ? "passed" : "failed"), (equal1 && equal2) ? ConsoleColor.Green : ConsoleColor.Red);
}
WriteOnce.Info("Report completed");
}
//cleanup
try
{
File.Delete(tmp1);
File.Delete(tmp2);
}
catch
{
//no action needed;
}
WriteOnce.FlushAll();
return equal1 && equal2 ? (int)ExitCode.NoDiff : (int)ExitCode.DiffFound;
}
bool CompareTags(string[] fileTags1, string[] fileTags2)
{
bool found = true;
//are all tags in file1 found in file2
foreach (string s1 in fileTags1)
{
if (!fileTags2.Contains(s1))
{
found = false;
WriteOnce.Any(s1, ConsoleColor.Yellow, WriteOnce.ConsoleVerbosityLevel.High);
}
}
//none missing
if (found)
WriteOnce.Any("None", ConsoleColor.Yellow, WriteOnce.ConsoleVerbosityLevel.High);
return found;
}
}
}

Просмотреть файл

@ -0,0 +1,190 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using Microsoft.DevSkim;
using Newtonsoft.Json;
namespace Microsoft.AppInspector.CLI.Commands
{
/// <summary>
/// Used to test a specific set of rules were all found in target source; Pass/Fail as well as inverse option to test if a set of rules is not
/// found in source code
/// </summary>
public class TagTestCommand : ICommand
{
enum TagTestType { RulesPresent, RulesNotPresent}
private string _arg_srcPath;
private string _arg_customRulesPath;
private string _arg_outputFile;
private bool _arg_ignoreDefault;
private TagTestType _arg_tagTestType;
public enum ExitCode
{
NoDiff = 0,
DiffFound = 1,
CriticalError = 2
}
/// Compares a set of rules against a source path...
/// Used for both RulesPresent and RulesNotePresent options
/// Focus is pass/fail not detailed comparison output -see Tagdiff for more
public TagTestCommand(TagTestCommandOptions opt)
{
_arg_srcPath = opt.SourcePath;
_arg_customRulesPath = opt.CustomRulesPath;
_arg_outputFile = opt.OutputFilePath;
WriteOnce.ConsoleVerbosityLevel arg_consoleVerbosityLevel;
Enum.TryParse(opt.ConsoleVerbosityLevel, true, out arg_consoleVerbosityLevel);
WriteOnce.Verbosity = arg_consoleVerbosityLevel;
if (string.IsNullOrEmpty(opt.TestType))
_arg_tagTestType = TagTestType.RulesPresent;
else if (!Enum.TryParse(opt.TestType, true, out _arg_tagTestType))
throw new ArgumentException("Invalid -t argument value", opt.TestType);
_arg_ignoreDefault = opt.IgnoreDefaultRules;
if (string.IsNullOrEmpty(opt.CustomRulesPath) && _arg_ignoreDefault)
throw new ArgumentException("--ignore-default-rules enabled, --custom-rules-path required");
}
public int Run()
{
WriteOnce.Write("TagTest command running", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
WriteOnce.NewLine(WriteOnce.ConsoleVerbosityLevel.Low);
//setup output
TextWriter outputWriter;
if (!string.IsNullOrEmpty(_arg_outputFile))
{
outputWriter = File.CreateText(_arg_outputFile);
outputWriter.WriteLine(Program.GetVersionString());
WriteOnce.Writer = outputWriter;
}
//init based on true or false present argument value
bool testSuccess = false;
RuleSet rules = new RuleSet();
#region addrules
//get rules from Rules subfolder to avoid having to pack into one file as a resource
//review if want to change later...
if (!_arg_ignoreDefault)
{
rules.AddDirectory(Helper.GetPath(Helper.AppPath.defaultRules));
}
//add custom rules paths if any specified by caller
if (_arg_customRulesPath != null)
{
if (Directory.Exists(_arg_customRulesPath))
rules.AddDirectory(_arg_customRulesPath);
else
rules.AddFile(_arg_customRulesPath);
}
#endregion
//one file vs ruleset
string tmp1 = Path.GetTempFileName();
WriteOnce.ConsoleVerbosityLevel saveVerbosity = WriteOnce.Verbosity;
WriteOnce.Verbosity = saveVerbosity;
AnalyzeCommand cmd1 = new AnalyzeCommand(new AnalyzeCommandOptions
{
SourcePath = _arg_srcPath,
OutputFilePath = tmp1,
OutputFileFormat = "json",
CustomRulesPath = _arg_customRulesPath,
IgnoreDefaultRules = _arg_ignoreDefault,
SimpleTagsOnly = true,
UniqueTagsOnly = true,
ConsoleVerbosityLevel = "Low"
});
AnalyzeCommand.ExitCode result = AnalyzeCommand.ExitCode.CriticalError;
//quiet analysis commands
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Low;
result = (AnalyzeCommand.ExitCode)cmd1.Run();
WriteOnce.Verbosity = saveVerbosity;
if (result == AnalyzeCommand.ExitCode.CriticalError)
{
WriteOnce.Error("Critical error analyzing source path. Check logs for more.");
return (int)result;
}
else if (result == AnalyzeCommand.ExitCode.NoMatches)
{
WriteOnce.Any(string.Format("Tagtest for [{0}] in source: {1}", _arg_tagTestType.ToString(),
_arg_tagTestType == TagTestType.RulesNotPresent ? "success" : "failed"));
return (int)result;
}
else //assumed (result == AnalyzeCommand.ExitCode.MatchesFound)
{
string file1TagsJson = File.ReadAllText(tmp1);
var file1TagsObj = JsonConvert.DeserializeObject<TagsFile[]>(file1TagsJson);
var file1Tags = file1TagsObj.First(); // here we have a single FileList object
File.Delete(tmp1);
WriteOnce.Info("TestTest Report", WriteOnce.ConsoleVerbosityLevel.High);
bool cancel = false;
foreach (Rule r in rules)
{
//supports both directions by generalizing
string[] testList1 = _arg_tagTestType == TagTestType.RulesNotPresent ?
r.Tags : file1Tags.Tags;
string[] testList2 = _arg_tagTestType == TagTestType.RulesNotPresent ?
file1Tags.Tags : r.Tags;
foreach (string t in testList2)
{
if (TagTest(testList1, t))
{
testSuccess = true;
WriteOnce.Any("Found " + t + " in source.", WriteOnce.ConsoleVerbosityLevel.High);
break;
}
else
{
testSuccess = false;
cancel = true;
WriteOnce.Any("Missing " + t + " in source.", WriteOnce.ConsoleVerbosityLevel.High);
}
}
if (cancel)
break;
}
}
WriteOnce.Any(string.Format("Test for all [{0}] in source: {1}", _arg_tagTestType.ToString(),
testSuccess ? "passed" : "failed"), ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
WriteOnce.FlushAll();
return testSuccess ? (int)ExitCode.NoDiff : (int)ExitCode.DiffFound;
}
bool TagTest(string[] list, string test)
{
if (_arg_tagTestType == TagTestType.RulesNotPresent)
return (!list.Any(v => v.Equals(test)));
else
return (list.Any(v => v.Equals(test)));
}
}
}

Просмотреть файл

@ -0,0 +1,82 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Reflection;
using Microsoft.AppInspector.CLI.Writers;
using Microsoft.DevSkim;
using Microsoft.AppInspector;
namespace Microsoft.AppInspector.CLI.Commands
{
/// <summary>
/// Wraps DevSkim verify for ruleset
/// </summary>
public class VerifyRulesCommand : ICommand
{
public enum ExitCode
{
Verified = 0,
NotVerified = 1,
CriticalError = 2
}
public VerifyRulesCommand(VerifyRulesCommandOptions opt)
{
_arg_RulesPath = opt.CustomRulesPath;
_ignoreDefault = opt.IgnoreDefaultRules;
}
public int Run()
{
WriteOnce.Write("Verify rules command running\n", ConsoleColor.Cyan, WriteOnce.ConsoleVerbosityLevel.Low);
if (String.IsNullOrEmpty(_arg_RulesPath) && !_ignoreDefault)
_arg_RulesPath = Helper.GetPath(Helper.AppPath.defaultRules);
else if (!Directory.Exists(_arg_RulesPath) && !File.Exists(_arg_RulesPath))
{
WriteOnce.Error(string.Format("Error: Not a valid file or directory {0}", _arg_RulesPath));
return (int)ExitCode.CriticalError;
}
//load [each] rules file separately to report out where a failure is happening
IEnumerable<string> fileListing;
fileListing = Directory.EnumerateFiles(_arg_RulesPath, "*.json", SearchOption.AllDirectories);
bool bIssues = false;
foreach (string filename in fileListing)
{
if (Path.GetExtension(filename) == ".json")
{
RuleSet rules = new RuleSet(Program.Logger);
try
{
rules.AddFile(filename);
RuleProcessor processor = new RuleProcessor(false, false, Program.Logger);
}
catch (Exception e)
{
WriteOnce.Any("Rule parsing failed for file: " + filename);
Program.Logger.Debug(e.Message);
bIssues = true;
}
}
}
WriteOnce.Any(string.Format("Verify rules completed {0}", !bIssues ? "successfully" : "with errors."),
ConsoleColor.Cyan);
return bIssues ? (int)ExitCode.NotVerified : (int)ExitCode.Verified;
}
private string _arg_RulesPath;
private bool _ignoreDefault;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
namespace Microsoft.AppInspector.CLI
{
class ErrorMessage
{
public string File { get; set; }
public string Path { get; set; }
public string Message { get; set; }
public string RuleID { get; set; }
public bool Warning { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,75 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.IO;
using System.Globalization;
namespace Microsoft.AppInspector.CLI
{
public class ExceptionLogger
{
public ExceptionLogger()
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
LogException((Exception)e.ExceptionObject);
}
private void LogException(Exception e)
{
string fileName = Write(e);
Console.Error.WriteLine("Critical exception happend. Details dumped into {0}", fileName);
Environment.Exit((int)-1);
}
public string WriteRaw(string rawData)
{
string fileName = "source.ident.log";
FileStream fs = null;
try
{
fs = new FileStream(fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
using (StreamWriter sw = new StreamWriter(fs))
{
fs = null;
sw.WriteLine("Date: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
sw.WriteLine("Platform: " + Environment.OSVersion.VersionString);
sw.WriteLine("Processor count: " + Environment.ProcessorCount);
sw.WriteLine("Memory: " + Environment.WorkingSet);
sw.WriteLine("Culture: " + CultureInfo.CurrentCulture.Name);
if (rawData != null)
sw.WriteLine(rawData);
else
sw.WriteLine("NULL argument was passed to exception logger");
sw.WriteLine(new string('-', 70));
sw.Flush();
}
}
catch
{
fileName = null;
}
finally
{
if (fs != null)
fs.Dispose();
}
return fileName;
}
public string Write(Exception ex)
{
string message = "Message: " + ex.Message + "\r\n";
message += "StackTrace: " + ex.StackTrace;
return WriteRaw(message);
}
}
}

177
AppInspector/Helper.cs Normal file
Просмотреть файл

@ -0,0 +1,177 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
static public class Helper
{
static string _basePath;
public enum AppPath { basePath, defaultRules, defaultLog, htmlTemplates, htmlReport, tagGroupPref, tagCounterPref };
static public string GetPath(AppPath pathType)
{
string result = "";
switch (pathType)
{
case AppPath.basePath:
result = GetBaseAppPath();
break;
case AppPath.defaultLog:
result = Path.Combine(GetBaseAppPath(), "log.txt");
break;
case AppPath.defaultRules:
result = Path.Combine(GetBaseAppPath(), "rules", "default");
break;
case AppPath.htmlTemplates:
result = Path.Combine(GetBaseAppPath(), "htmltemplates");
break;
case AppPath.htmlReport:
result = Path.Combine(GetBaseAppPath(), "htmlreport");
break;
case AppPath.tagGroupPref:
result = Path.Combine(GetBaseAppPath(), "preferences", "tagreportgroups.json");
break;
case AppPath.tagCounterPref:
result = Path.Combine(GetBaseAppPath(), "preferences", "tagcounters.json");
break;
}
return result;
}
static private string GetBaseAppPath()
{
if (!String.IsNullOrEmpty(_basePath))
return _basePath;
_basePath = Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory);
return _basePath;
}
/// <summary>
/// Attempt to map application type tags or file type or language to identify
/// WebApplications, Windows Services, Client Apps, WebServices, Azure Functions etc.
/// </summary>
/// <param name="fileName"></param>
/// <param name="language"></param>
/// <param name="tag"></param>
/// <param name="sample"></param>
static public String DetectSolutionType(string fileName, string language, string tag, string sample)
{
string result = "";
if (tag.Contains("Application.Type"))
{
int lastDot = sample.LastIndexOf(".");
if (-1 != lastDot)
result = sample.Substring(lastDot + 1);
}
else if (tag.Contains("Microsoft.MVC"))
{
result = "WebApplication";
}
else if (tag.Contains("Microsoft.MFC") || tag.Contains(".WinSDK"))
{
result = "WinClient";
}
else
{
///////////first chance
switch (fileName)
{
case "web.config":
result = "WebApplication";
break;
case "app.config":
result = ".NETClient";
break;
case "pom.xml":
case "build.make.xml":
case "build.gradle":
result = "Java";
break;
case "package.json":
result = "Node";
break;
}
if (string.IsNullOrEmpty(result))
{
////////////second chance
switch (Path.GetExtension(fileName))
{
case ".cshtml":
result = "ASP.NET";
break;
case ".htm":
case ".html":
case ".js":
result = "WebApplication";
break;
case "powershell":
result = "Script";
break;
case "shellscript":
result = "Script";
break;
case "wincmdscript":
result = "Script";
break;
}
}
if (string.IsNullOrEmpty(result))
{
///////////third chance
switch (language)
{
case "ruby":
case "perl":
case "php":
result = "WebApplication";
break;
}
}
}
return result;
}
public static void OpenBrowser(string url)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}"));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("BROWSER")))
{
try
{
Process.Start("xdg-open", url);
}
catch (Exception)
{
WriteOnce.Error("Unable to open browser. Open output file directly.");
}
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using Microsoft.DevSkim;
using System.Collections;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Linq;
namespace Microsoft.AppInspector.CLI.Writers
{
public class MatchRecord
{
public string Language { get; set; }
public string Filename { get; set; }
public int Filesize { get; set; }
public string TextSample { get; set; }
public Issue Issue { get; set; }
public string Excerpt { get; set; }
}
}

325
AppInspector/Program.cs Normal file
Просмотреть файл

@ -0,0 +1,325 @@
//Copyright(c) Microsoft Corporation.All rights reserved.
// Licensed under the MIT License.
using System;
using System.Diagnostics;
using CommandLine;
using System.Reflection;
using Microsoft.AppInspector.CLI.Commands;
using NLog;
using NLog.Targets;
using NLog.Config;
using System.Text.RegularExpressions;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
namespace Microsoft.AppInspector.CLI
{
#region CommandLineArgOptions
/// <summary>
/// Command option classes for each command verb
/// </summary>
[Verb("analyze", HelpText = "Inspect source directory/file against defined characteristics")]
public class AnalyzeCommandOptions
{
private bool uniqueTagsOnly;
[Option('s', "source-path", Required = true, HelpText = "Path to source code to inspect (required)")]
public string SourcePath { get; set; }
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
public string OutputFilePath { get; set; }
[Option('f', "output-file-format", Required = false, HelpText = "Output format [html|json|text]", Default = "html")]
public string OutputFileFormat { get; set; }
[Option('e', "text-format", Required = false, HelpText = "Text format specifiers", Default = "Tag:%T,Rule:%N,Ruleid:%R,Confidence:%X,File:%F,Sourcetype:%t,Line:%L,Sample:%m")]
public string TextOutputFormat { get; set; }
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
public string CustomRulesPath { get; set; }
[Option('t', "tag-output-only", Required = false, HelpText = "Output only contains identified tags", Default = false)]
public bool SimpleTagsOnly { get; set; }
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
public bool IgnoreDefaultRules { get; set; }
[Option('u', "unique-tags-only", Required = false, HelpText = "Output only contains unique tag matches", Default = true)]
public bool UniqueTagsOnly
{
get { return uniqueTagsOnly; }
set
{
uniqueTagsOnly = value;
}
}
[Option('c', "confidence-filters", Required = false, HelpText = "Outout only if matching confidence <value>,<value> [high|medium|low]", Default = "high,medium")]
public string ConfidenceFilters { get; set; }
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low]", Default = "medium")]
public string ConsoleVerbosityLevel { get; set; }
#region logoptions
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
public string LogFilePath { get; set; }
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
public string LogFileLevel { get; set; }
#endregion
}
[Verb("tagdiff", HelpText = "Compares unique tag values between two source paths")]
public class TagDiffCommandOptions
{
[Option("src1", Required = true, HelpText = "Source 1 to compare (required)")]
public string SourcePath1 { get; set; }
[Option("src2", Required = true, HelpText = "Source 2 to compare (required")]
public string SourcePath2 { get; set; }
[Option('t', "test-type", Required = false, HelpText = "Type of test to run [equality|inequality]", Default = "equality")]
public string TestType { get; set; }
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
public string CustomRulesPath { get; set; }
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
public bool IgnoreDefaultRules { get; set; }
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
public string OutputFilePath { get; set; }
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low", Default = "medium")]
public string ConsoleVerbosityLevel { get; set; }
#region logoptions
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
public string LogFilePath { get; set; }
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
public string LogFileLevel { get; set; }
#endregion
}
[Verb("tagtest", HelpText = "Test presence of tags in source (compare or verify modes)")]
public class TagTestCommandOptions
{
[Option('s', "source-path", Required = true, HelpText = "Source to test (required)")]
public string SourcePath { get; set; }
[Option('t', "test-type", Required = false, HelpText = "Test to perform [rulespresent|rulesnotpresent] ", Default = "rulespresent")]
public string TestType { get; set; }
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
public string CustomRulesPath { get; set; }
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = true)]
public bool IgnoreDefaultRules { get; set; }
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
public string OutputFilePath { get; set; }
[Option('x', "console-verbosity", Required = false, HelpText = "Console verbosity [high|medium|low", Default = "medium")]
public string ConsoleVerbosityLevel { get; set; }
#region logoptions
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
public string LogFilePath { get; set; }
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
public string LogFileLevel { get; set; }
#endregion
}
[Verb("exporttags", HelpText = "Export unique rule tags")]
public class ExportTagsCommandOptions
{
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
public string CustomRulesPath { get; set; }
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
public bool IgnoreDefaultRules { get; set; }
[Option('o', "output-file-path", Required = false, HelpText = "Path to output file")]
public string OutputFilePath { get; set; }
#region logoptions
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
public string LogFilePath { get; set; }
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
public string LogFileLevel { get; set; }
#endregion
}
[Verb("verifyrules", HelpText = "Verify rules syntax is valid")]
public class VerifyRulesCommandOptions
{
[Option('r', "custom-rules-path", Required = false, HelpText = "Custom rules path")]
public string CustomRulesPath { get; set; }
[Option('i', "ignore-default-rules", Required = false, HelpText = "Ignore default rules bundled with application", Default = false)]
public bool IgnoreDefaultRules { get; set; }
#region logoptions
[Option('l', "log-file-path", Required = false, HelpText = "Log file path")]
public string LogFilePath { get; set; }
[Option('v', "log-file-level", Required = false, HelpText = "Log file level")]
public string LogFileLevel { get; set; }
#endregion
}
#endregion
class Program
{
static bool _uniqueOverRide = true;
public static string GetVersionString()
{
return String.Format("Microsoft Application Inspector {0}", GetVersion());
}
public static string GetVersion()
{
Assembly assembly = Assembly.GetExecutingAssembly();
FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(assembly.Location);
return fileVersionInfo.ProductVersion;
}
static public Logger Logger { get; set; }
static bool ConsoleNoWait { get; set; }
/// <summary>
/// Program entry point which defines command verbs and options to running
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
WriteOnce.Verbosity = WriteOnce.ConsoleVerbosityLevel.Medium;
//TODO had to add work around for very strange behavior from cmdlineparser that will not accept a false from
//the command line; several attempts to force, rename etc. to no avail. This works for now.
if (args.Length > 0 && args[0] == "analyze")
{
for (int i=0;i<args.Length;i++)
{
if (args[i] == "-u" || args[i] == "--unique-tags-only")
_uniqueOverRide = args[i + 1] == "true";
}
}
try
{
WriteOnce.Info(GetVersionString());
var argsResult = Parser.Default.ParseArguments<AnalyzeCommandOptions,
TagDiffCommandOptions,
TagTestCommandOptions,
ExportTagsCommandOptions,
VerifyRulesCommandOptions>(args)
.MapResult(
(AnalyzeCommandOptions opts) => RunAnalyzeCommand(opts),
(TagDiffCommandOptions opts) => RunTagDiffCommand(opts),
(TagTestCommandOptions opts) => RunTagTestCommand(opts),
(ExportTagsCommandOptions opts) => RunExportTagsCommand(opts),
(VerifyRulesCommandOptions opts) => RunVerifyRulesCommand(opts),
errs => 1
);
}
catch (Exception e)
{
WriteOnce.Error("Runtime error encountered. Check log or log filtering options for more.");
WriteOnce.Error($"Runtime error: {e.Message}\n{e.StackTrace}");//no sensitive data expected in output
}
}
private static int RunAnalyzeCommand(AnalyzeCommandOptions opts)
{
opts.UniqueTagsOnly = _uniqueOverRide;
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
return new AnalyzeCommand(opts).Run();
}
private static int RunTagDiffCommand(TagDiffCommandOptions opts)
{
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
return new TagDiffCommand(opts).Run();
}
private static int RunTagTestCommand(TagTestCommandOptions opts)
{
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
return new TagTestCommand(opts).Run();
}
private static int RunExportTagsCommand(ExportTagsCommandOptions opts)
{
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
return new ExportTagsCommand(opts).Run();
}
private static int RunVerifyRulesCommand(VerifyRulesCommandOptions opts)
{
SetupLogging(opts.LogFilePath, opts.LogFileLevel);
return new VerifyRulesCommand(opts).Run();
}
static void SetupLogging(string logFilePath, string logFileLevel)
{
var config = new NLog.Config.LoggingConfiguration();
if (String.IsNullOrEmpty(logFilePath))
{
logFilePath = Helper.GetPath(Helper.AppPath.defaultLog);
//if using default app log path clean up previous for convenience in reading
if (File.Exists(logFilePath))
File.Delete(logFilePath);
}
if (String.IsNullOrEmpty(logFileLevel))
logFileLevel = "ERROR";
using (var fileTarget = new FileTarget()
{
Name = "LogFile",
FileName = logFilePath,
Layout = @"${date:universalTime=true:format=s} ${threadid} ${level:uppercase=true} - ${message}",
ForceMutexConcurrentWrites = true
})
{
config.AddTarget(fileTarget);
config.LoggingRules.Add(new LoggingRule("*", LogLevel.FromString(logFileLevel), fileTarget));
}
LogManager.Configuration = config;
Logger = LogManager.GetCurrentClassLogger();
Logger.Info("["+ DateTime.Now.ToLocalTime() + "] //////////////////////////////////////////////////////////");
WriteOnce.Log = Logger;//allows log to be written to as well as console or output file
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishDir>bin\Release\netcoreapp3.0\publish\</PublishDir>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>

83
AppInspector/Properties/Resources.Designer.cs сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AppInspector.CLI.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AppInspector.CLI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] comments {
get {
object obj = ResourceManager.GetObject("comments", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] languages {
get {
object obj = ResourceManager.GetObject("languages", resourceCulture);
return ((byte[])(obj));
}
}
}
}

Просмотреть файл

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="comments" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\..\Microsoft.DevSkim\Resources\comments.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="languages" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\..\Microsoft.DevSkim\Resources\languages.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Просмотреть файл

@ -0,0 +1,7 @@
{
"profiles": {
"AppInspect..CLI": {
"commandName": "Project"
}
}
}

137
AppInspector/TagInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,137 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Microsoft.DevSkim;
using System.IO;
using System.Linq;
using System.Dynamic;
namespace Microsoft.AppInspector.CLI.Writers
{
/// <summary>
/// Root parent for tag group preferences file
/// </summary>
[Serializable]
public class TagCategory
{
public enum tagInfoType { uniqueTags, allTags };
[JsonProperty(PropertyName = "type")]
public tagInfoType Type;
[JsonProperty(PropertyName = "categoryName")]
public String Name { get; set; }
[JsonProperty(PropertyName = "groups")]
public List<TagGroup> Groups { get; set; }
public TagCategory()
{
Groups = new List<TagGroup>();
}
}
/// <summary>
/// Used to read customizable preference for Profile page e.g. rules\profile\profile.json
/// </summary>
[Serializable]
public class TagGroup
{
[JsonProperty(PropertyName = "title")]
public string Title { get; set; }
[JsonIgnore]
public string IconURL { get; set; }
[JsonProperty(PropertyName = "dataRef")]
public string DataRef { get; set; }
[JsonProperty(PropertyName = "patterns")]
public List<TagSearchPattern> Patterns { get; set; }
public TagGroup()
{
Patterns = new List<TagSearchPattern>();
}
}
[Serializable]
public class TagSearchPattern
{
[JsonProperty(PropertyName = "searchPattern")]
public string SearchPattern { get; set; }
[JsonProperty(PropertyName = "displayName")]
public string DisplayName { get; set; }
[JsonProperty(PropertyName = "detectedIcon")]
public string DetectedIcon { get; set; }
[JsonProperty(PropertyName = "notDetectedIcon")]
public string NotDetectedIcon { get; set; }
[JsonProperty(PropertyName = "detected")]
public bool Detected { get; set; }
}
/// <summary>
/// Primary use is development of lists of tags with specific group or pattern properties in reporting
/// </summary>
public class TagInfo
{
public string Tag { get; set; }
public string ShortTag { get; set; }
[JsonIgnore]
public string StatusIcon { get; set; }
private string _confidence;
public string Confidence
{
get { return _confidence; }
set
{
DevSkim.Confidence test;
try
{
if (Enum.TryParse(value, true, out test))
this._confidence = value;
}
catch (Exception)//control error description
{
throw new Exception("Invalid argument value set attempt for Confidence");
}
}
}
public string Severity { get; set; }
public bool Detected { get; set; }
[JsonIgnore]
public string Msg
{ get { return Detected ? "Not found" : "Confidence"; }
}
}
[Serializable]
public class TagCounter
{
[JsonProperty(PropertyName = "tag")]
public string Tag { get; set; }
[JsonProperty(PropertyName = "displayName")]
public string ShortTag { get; set; }
[JsonProperty(PropertyName = "count")]
public int Count { get; set; }
[JsonProperty(PropertyName = "includeAsMatch")]
public bool IncludeAsMatch { get; set; }
}
[Serializable]
public class TagException
{
[JsonProperty(PropertyName = "tag")]
public string Tag { get; set; }
}
}

128
AppInspector/WriteOnce.cs Normal file
Просмотреть файл

@ -0,0 +1,128 @@
// Copyright(C) Microsoft.All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.IO;
using NLog;
/// <summary>
/// Wraps Console, Output and Log Writes for convenience to write once from calling
/// code to increase readability and for allowing replacement of console print
/// functionality in conjunction logger which may have console configuration enabled
/// Allows a Write once feature and protects code from console/log changes to standard out
/// Use: call to write to console, file output and log in one call OR for log file only
/// output call logger directly
///
/// Note: NLOG is not consistent writing to standard out console making it impossible
/// to predict when it will be visible thus it is largely used for file log output only
/// </summary>
public class WriteOnce
{
public enum ConsoleVerbosityLevel { High, Medium, Low, None }
private static ConsoleColor _infoForeColor = ConsoleColor.Magenta;
private static ConsoleColor _errorForeColor = ConsoleColor.Red;
private static ConsoleColor _generalForeColor = ConsoleColor.Gray;
public static ConsoleVerbosityLevel Verbosity { get; set; }
public static Logger Log {get; set;}
public static TextWriter Writer { get; set; }
public ConsoleColor InfoForeColor { set { _infoForeColor = value; } }
public ConsoleColor ErrorForeColor { set { _errorForeColor = value; } }
public static void Info(string s, ConsoleVerbosityLevel verbosityLevel=ConsoleVerbosityLevel.Medium)
{
if (Log != null && Log.Name != "Console")
Log.Info(s);
if (Writer != null && Writer != Console.Out)
Writer.WriteLine(s);
WriteLine(s, _infoForeColor, verbosityLevel);
}
public static void Any(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
Any(s, _generalForeColor, verbosityLevel);
}
public static void Any(string s, ConsoleColor foreColor, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
if (Log != null && Log.Name != "Console")
Log.Info(s);
if (Writer != null && Writer != Console.Out)
Writer.WriteLine(s);
WriteLine(s, foreColor, verbosityLevel);
}
public static void Error(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
if (Log != null && Log.Name != "Console")
Log.Error(s);
WriteLine(s, _errorForeColor, verbosityLevel);
}
public static void NewLine(ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
if (verbosityLevel >= Verbosity)
Console.WriteLine();
}
public static void Write(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
Write(s, _infoForeColor,verbosityLevel);
}
public static void WriteLine(string s, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
WriteLine(s, _infoForeColor, verbosityLevel);
}
public static void Write(string s, ConsoleColor foreground, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
if (verbosityLevel >= Verbosity)
{
ConsoleColor lastForecolor = Console.ForegroundColor;
Console.ForegroundColor = foreground;
Console.Write(s);
Console.ForegroundColor = lastForecolor;
}
}
public static void WriteLine(string s, ConsoleColor foreground, ConsoleVerbosityLevel verbosityLevel = ConsoleVerbosityLevel.Medium)
{
if (verbosityLevel >= Verbosity)
{
ConsoleColor lastForecolor = Console.ForegroundColor;
Console.ForegroundColor = foreground;
Console.WriteLine(s);
Console.ForegroundColor = lastForecolor;
}
}
public static void FlushAll()
{
if (Writer != null)
{
//cleanup
Writer.Flush();
Writer.Close();
Writer = null;
WriteOnce.WriteLine("See output file if specified. For HTML format option, please see the HTMLOutput folder created.");
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
namespace Microsoft.AppInspector.CLI.Writers
{
public class DummyWriter : Writer
{
public override void WriteApp(AppProfile appCharacteriation)
{
}
public override void FlushAndClose()
{
// This is intentionaly empty
}
}
}

Просмотреть файл

@ -0,0 +1,213 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using HandlebarsDotNet;
namespace Microsoft.AppInspector.CLI.Writers
{
public class HTMLWriter : Writer
{
/// <summary>
/// WriteApp dynamically pulls from the template folder and copies all files to the target report folder
/// making sure to process any "template" named files as needed before compilation by the templating framework
/// </summary>
/// <param name="app"></param>
public override void WriteApp(AppProfile app)
{
string templatesPath = Helper.GetPath(Helper.AppPath.htmlTemplates);
string htmlReportsPath = Helper.GetPath(Helper.AppPath.htmlReport);
IEnumerable<string> files = Directory.EnumerateFiles(templatesPath, "*.*");
//report too unwieldy for single file so place in named directory; create if new
if (!Directory.Exists(htmlReportsPath))
Directory.CreateDirectory(htmlReportsPath);
foreach (string filePath in files)
{
if (!filePath.Contains("template-"))
File.Copy(filePath, Path.Combine(htmlReportsPath, Path.GetFileName(filePath)), true);
else
{
string finalPath = filePath.Replace("template-", "");
ProcessTemplate(filePath, Path.Combine(htmlReportsPath, Path.GetFileName(finalPath)), app);
}
}
//writes out json report for convenience and linking to from report page(s)
String jsonReportPath = Path.Combine(htmlReportsPath, "jsonreport.json");
Writer jsonWriter = WriterFactory.GetWriter("json", jsonReportPath);
jsonWriter.TextWriter = File.CreateText(jsonReportPath);
jsonWriter.WriteApp(app);
jsonWriter.FlushAndClose();
OpenBrowser(Path.Combine(htmlReportsPath, "index.html"));
}
/// <summary>
/// ProcessTemplate will match files with tagcategories to locate the right set of data to replace before
/// final template compilation by the templating framework used
/// </summary>
/// <param name="templateFilePath"></param>
/// <param name="finalFilePath"></param>
/// <param name="app"></param>
private void ProcessTemplate(string templateFilePath, string finalFilePath, AppProfile app)
{
string categoryName = null;
foreach (TagCategory tagCategory in app.TagGroupPreferences)
{
if (templateFilePath.Contains(tagCategory.Name))
{
categoryName = tagCategory.Name;
break;
}
}
string processedTemplate = GetTemplate(templateFilePath, categoryName, app);
CompileTemplate(processedTemplate, finalFilePath, app);
}
/// <summary>
/// Provides feature to allow dynamic creation of tag groups in template before final template compilation
/// Used in profile and composition html pages. If no special processing is required, returns the raw
/// template which is assumed to contain simple template framework compatible keywords or none at all.
/// </summary>
/// <param name="templateFileName"></param>
/// <param name="category"></param>
/// <param name="app"></param>
/// <returns></returns>
string GetTemplate(string templateFileName, string category, AppProfile app)
{
string result = "";
string templateText = File.ReadAllText(templateFileName);
List<TagGroup> tagGroupList = string.IsNullOrEmpty(category) ? null : app.GetCategoryTagGroups(category);
string subSectionStartPattern = "[[subSectionStart]]";
string subSectionEndPattern = "[[subSectionEnd]]";
int istartSection = templateText.IndexOf(subSectionStartPattern);
int iendSection = templateText.IndexOf(subSectionEndPattern);
if (tagGroupList == null || istartSection == -1 || iendSection == -1)
return templateText;
string subSectionTemplate = templateText.Substring(istartSection, iendSection-istartSection+subSectionEndPattern.Length+1);
subSectionTemplate = subSectionTemplate.Replace(subSectionStartPattern, "");
subSectionTemplate = subSectionTemplate.Replace(subSectionEndPattern, "");
//loop through optional sections for group to replace with actual variable names, titles etc.
foreach (TagGroup tagGroup in tagGroupList)
{
result += subSectionTemplate;
int isectionName= result.IndexOf("[[subSectionName]]");
if (-1 != isectionName)
{
result = result.Replace("[[subSectionName]]", tagGroup.Title);
}
int isectionVarRef = result.IndexOf("[[subSectionVarRef]]");
if (-1 != isectionVarRef)
{
result = result.Replace("[[subSectionVarRef]]", "tagGrp" + tagGroup.DataRef);
result = result.Replace("tagGrptagGrp", "tagGrp"); //in case someone thinks to add in profile.json etc.
}
}
//create dup sub template section with start/end and use as revised template the continue compilation
string leftSide = templateText.Substring(0, istartSection);
string rightSide = templateText.Substring(iendSection + subSectionEndPattern.Length);
string finalResult = leftSide + result + rightSide;
return finalResult;
}
private void CompileTemplateSimple(string templateFileName, string outputFileName, AppProfile app)
{
string templateText = File.ReadAllText(templateFileName);
CompileTemplate(templateText, outputFileName, app);
}
private void CompileTemplate(string templateText, string outputFileName, AppProfile app)
{
//add app object for access to various items (TBD if needed in future)
var data = new Dictionary<string, object>()
{
{ "app", app }
};
//now add all list groups
foreach (string outerKey in app.KeyedTagInfoLists.Keys)
data.Add(outerKey, app.KeyedTagInfoLists[outerKey]);
foreach (string outerKey in app.KeyedSortedTagInfoLists.Keys)
data.Add(outerKey, app.KeyedSortedTagInfoLists[outerKey]);
data.Add("selectTagCounters", app.MetaData.TagCounters);
foreach (string outerKey in app.MetaData.KeyedPropertyLists.Keys)
data.Add(outerKey, app.MetaData.KeyedPropertyLists[outerKey]);
TextWriter textWriter = null;
try
{
var template = Handlebars.Compile(templateText);
textWriter = File.CreateText(outputFileName);
textWriter.Write(template(data));
}
catch (Exception ex)
{
WriteOnce.Error("Error creating HTML report");
throw new Exception(ex.Message);
}
finally
{
if (textWriter != null)
{
textWriter.Flush();
textWriter.Close();
}
}
}
public static void OpenBrowser(string url)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}"));
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Process.Start("xdg-open", url);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", url);
}
}
public override void FlushAndClose()
{
TextWriter.Flush();
TextWriter.Close();
}
}
}

Просмотреть файл

@ -0,0 +1,140 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using Microsoft.DevSkim;
namespace Microsoft.AppInspector.CLI.Writers
{
/// <summary>
/// Subset of MatchRecord and Issue properties for json output
/// TODO: look at possible consolidation with MatchRecord...do we need Issue.Rule etc. which are not
/// wanted for json output in their entirety
/// </summary>
[Serializable]
public class MatchItems
{
public MatchItems(MatchRecord matchRecord)
{
FileName = matchRecord.Filename;
SourceType = matchRecord.Language;
StartLocationLine = matchRecord.Issue.StartLocation.Line;
StartLocationColumn = matchRecord.Issue.StartLocation.Column;
EndLocationLine = matchRecord.Issue.EndLocation.Line;
EndLocationColumn = matchRecord.Issue.EndLocation.Column;
BoundaryIndex = matchRecord.Issue.Boundary.Index;
BoundaryLength = matchRecord.Issue.Boundary.Length;
RuleId = matchRecord.Issue.Rule.Id;
Severity = matchRecord.Issue.Rule.Severity.ToString();
RuleName = matchRecord.Issue.Rule.Name;
RuleDescription = matchRecord.Issue.Rule.Description;
PatternConfidence = matchRecord.Issue.Confidence.ToString();
PatternType = matchRecord.Issue.PatternMatch.PatternType.ToString();
MatchingPattern = matchRecord.Issue.PatternMatch.Pattern;
Sample = matchRecord.TextSample;
Excerpt = matchRecord.Excerpt;
Tags = matchRecord.Issue.Rule.Tags;
}
[JsonProperty(PropertyName = "fileName")]
public string FileName { get; set; }
[JsonProperty(PropertyName = "ruleId")]
public string RuleId { get; set; }
[JsonProperty(PropertyName = "ruleName")]
public string RuleName { get; set; }
[JsonProperty(PropertyName = "ruleDescription")]
public string RuleDescription { get; set; }
[JsonProperty(PropertyName = "pattern")]
public string MatchingPattern { get; set; }
[JsonProperty(PropertyName = "type")]
public string PatternType { get; set; }
[JsonProperty(PropertyName = "confidence")]
public string PatternConfidence { get; set; }
[JsonProperty(PropertyName = "severity")]
public string Severity { get; set; }
[JsonProperty(PropertyName = "tags")]
public string[] Tags { get; set; }
[JsonProperty(PropertyName = "sourceType")]
public string SourceType { get; set; }
[JsonProperty(PropertyName = "sample")]
public string Sample { get; set; }
[JsonProperty(PropertyName = "excerpt")]
public string Excerpt { get; set; }
[JsonProperty(PropertyName = "startLocationLine")]
public int StartLocationLine { get; set; }
[JsonProperty(PropertyName = "startLocationColumn")]
public int StartLocationColumn { get; set; }
[JsonProperty(PropertyName = "endLocationLine")]
public int EndLocationLine { get; set; }
[JsonProperty(PropertyName = "endLocationColumn")]
public int EndLocationColumn { get; set; }
[JsonProperty(PropertyName = "boundaryIndex")]
public int BoundaryIndex { get; set; }
[JsonProperty(PropertyName = "boundaryLength")]
public int BoundaryLength { get; set; }
}
/// <summary>
/// Writes in json format
/// Users can select arguments to filter output to 1. only simple tags 2. only matchlist without rollup metadata etc. 3. everything
/// Lists of tagreportgroups are written as well as match list details so users have chose to present the same
/// UI as shown in the HTML report to the level of detail desired...
/// </summary>
public class JsonWriter : Writer
{
List<Dictionary<string, object>> jsonResult = new List<Dictionary<string, object>>();
public override void WriteApp(AppProfile app)
{
// Store the results here temporarily building up a list of items in the desired order etc.
Dictionary<string, object> itemList = new Dictionary<string, object>(); ;
if (app.SimpleTagsOnly)
{
List<string> keys = new List<string>(app.MetaData.UniqueTags);
itemList.Add("tags", keys);
keys.Sort();
}
else
{
if (!app.ExcludeRollup)
itemList.Add("AppProfile", app);
//matches are added this way to avoid output of entire set of MatchItem properties which include full rule/patterns/cond.
List<MatchItems> matches = new List<MatchItems>();
foreach (MatchRecord match in app.MatchList)
{
MatchItems matchItem = new MatchItems(match);
matches.Add(matchItem);
}
itemList.Add("matchDetails", matches);
}
jsonResult.Add(itemList);
}
public override void FlushAndClose()
{
TextWriter.Write(JsonConvert.SerializeObject(jsonResult, Formatting.Indented));
TextWriter.Flush();
TextWriter.Close();
}
}
}

Просмотреть файл

@ -0,0 +1,91 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using DotLiquid;
using DotLiquid.FileSystems;
using Newtonsoft.Json;
using System.Linq;
namespace Microsoft.AppInspector.CLI.Writers
{
public class Random : DotLiquid.Tag
{
private int _max;
public override void Initialize(string tagName, string markup, List<string> tokens)
{
base.Initialize(tagName, markup, tokens);
_max = Convert.ToInt32(markup);
}
}
public class LiquidWriter : Writer
{
/**
* Writes data (defined in `app`) to the HTML template.
*/
public override void WriteApp(AppProfile app)
{
var htmlTemplateText = File.ReadAllText("html/index.html");
Template.FileSystem = new EmbeddedFileSystem(Assembly.GetEntryAssembly(), "AppInspector.CLI.html.partials");
Template.RegisterTag<Random>("random");
RegisterSafeType(typeof(AppProfile));
RegisterSafeType(typeof(AppMetaData));
var htmlTemplate = Template.Parse(htmlTemplateText);
var data = new Dictionary<string, object>();
data["AppProfile"] = app;
//matches are added this way to avoid output of entire set of MatchItem properties which include full rule/patterns/cond.
List<MatchItems> matches = new List<MatchItems>();
foreach (MatchRecord match in app.MatchList)
{
MatchItems matchItem = new MatchItems(match);
matches.Add(matchItem);
}
data["matchDetails"] = matches;
var hashData = new Hash();
hashData["profile"] = app;
hashData["match_details"] = matches;
hashData["json"] = JsonConvert.SerializeObject(data, Formatting.Indented);
hashData["application_version"] = Program.GetVersionString();
var htmlResult = htmlTemplate.Render(hashData);
File.WriteAllText("output.html", htmlResult);
//this.TextWriter.Write(htmlResult);
//writes out json report for convenience and linking to from report page(s)
String jsonReportPath = Path.Combine("output.json");
Writer jsonWriter = WriterFactory.GetWriter("json", jsonReportPath);
jsonWriter.TextWriter = File.CreateText(jsonReportPath);
jsonWriter.WriteApp(app);
jsonWriter.FlushAndClose();
Helper.OpenBrowser("output.html");
}
public override void FlushAndClose()
{
TextWriter.Flush();
TextWriter.Close();
}
private void RegisterSafeType(Type type)
{
Template.RegisterSafeType(type, (t) => t.ToString());
Template.RegisterSafeType(type, type.GetMembers(BindingFlags.Instance).Select((e) => e.Name).ToArray());
}
}
}

Просмотреть файл

@ -0,0 +1,172 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.AppInspector.CLI.Writers
{
public class SimpleTextWriter : Writer
{
readonly int COLUMN_MAX = 80;
public SimpleTextWriter(string formatString)
{
if (string.IsNullOrEmpty(formatString))
_formatString = "Tag:%T,Rule:%N,Ruleid:%R,Confidence:%X,File:%F,Sourcetype:%t,Line:%L,Sample:%m";
else
_formatString = formatString;
}
public override void WriteApp(AppProfile app)
{
//option for tags only vs full match record structure; used tagdiff and tagtest commands
if (app.SimpleTagsOnly)
{
List<string> tags = new List<string>();
foreach (MatchRecord match in app.MatchList)
foreach (string tag in match.Issue.Rule.Tags)
tags.Add(tag);
tags.Sort();
foreach (string tag in tags)
TextWriter.WriteLine(tag);
}
else
{
if (!app.ExcludeRollup)
WriteAppMeta(app);
TextWriter.WriteLine(MakeHeading("Dependencies"));
WriteDependencies(app);
TextWriter.WriteLine(MakeHeading("Match Details"));
foreach (MatchRecord match in app.MatchList)
WriteMatch(match);
}
TextWriter.WriteLine("\nEnd of report");
}
private string StringList (HashSet<string> data)
{
string results="";
foreach (string s in data)
results += s + " ";
return results;
}
private string StringList(SortedDictionary<string,string> data)
{
string results = "";
foreach (string s in data.Values)
results += s + " ";
return results;
}
/// <summary>
/// even out delineator for headings
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
private string MakeHeading(string header)
{
string result = header;
for (int i = header.Length; i < COLUMN_MAX; i++)
result += "-";
return result;
}
public void WriteAppMeta(AppProfile app)
{
//write predefined characteristics
TextWriter.WriteLine(MakeHeading("Project Info"));
TextWriter.WriteLine("Name: {0}", app.MetaData.ApplicationName + " " + app.MetaData.SourceVersion);
TextWriter.WriteLine("Description: {0}", app.MetaData.Description);
TextWriter.WriteLine("Source path: {0}", app.SourcePath);
TextWriter.WriteLine("Authors: {0}", app.MetaData.Authors);
TextWriter.WriteLine("Last Updated: {0}", app.MetaData.LastUpdated);
TextWriter.WriteLine(MakeHeading("Scan Settings"));
TextWriter.WriteLine("AppInspector version: {0}", app.Version);
TextWriter.WriteLine("Rules path: {0}", StringList(app.MetaData.RulePaths));
TextWriter.WriteLine("Run Arguments: {0}", app.Args);
TextWriter.WriteLine("Date scanned: {0}", app.DateScanned);
TextWriter.WriteLine(MakeHeading("Source Info"));
TextWriter.WriteLine("Application type: {0}", StringList(app.MetaData.AppTypes));
TextWriter.WriteLine("Package types: {0}", StringList(app.MetaData.PackageTypes));
TextWriter.WriteLine("File extensions: {0}", StringList(app.MetaData.FileExtensions));
TextWriter.WriteLine(MakeHeading("Detetected Targets"));
TextWriter.WriteLine("Output types: {0}", StringList(app.MetaData.Outputs));
TextWriter.WriteLine("OS Targets: {0}", StringList(app.MetaData.OSTargets));
TextWriter.WriteLine("CPU Targets: {0}", StringList(app.MetaData.CPUTargets));
TextWriter.WriteLine("Cloud targets: {0}", StringList(app.MetaData.CloudTargets));
TextWriter.WriteLine(MakeHeading("Stats"));
TextWriter.WriteLine("Files analyzed: {0}", app.MetaData.FilesAnalyzed);
TextWriter.WriteLine("Files skipped: {0}", app.MetaData.FilesSkipped);
TextWriter.WriteLine("Total files: {0}", app.MetaData.TotalFiles);
TextWriter.WriteLine("Detections: {0} in {1} file(s)", app.MetaData.TotalMatchesCount, app.MetaData.FilesAffected);
TextWriter.WriteLine("Unique detections: {0}", app.MetaData.UniqueMatchesCount);
TextWriter.WriteLine(MakeHeading("Select Counters"));
foreach (TagCounter counter in app.MetaData.TagCounters)
TextWriter.WriteLine("{0} count: {1}", counter.ShortTag, counter.Count);
TextWriter.WriteLine(MakeHeading("Customizable tag groups"));
//iterate through customizable tag group lists
foreach (string tagGroupCategory in app.KeyedTagInfoLists.Keys)
{
List<TagInfo> list = app.KeyedTagInfoLists[tagGroupCategory];
TextWriter.WriteLine(string.Format("[{0}]", tagGroupCategory));
foreach (TagInfo tagInfo in list)
TextWriter.WriteLine("Tag:{0},Detected:{1},Confidence:{2}", tagInfo.Tag, tagInfo.Detected, tagInfo.Confidence);
}
}
public void WriteMatch(MatchRecord match)
{
string output = _formatString.Replace("%F", match.Filename);
output = output.Replace("%t", match.Language);
output = output.Replace("%L", match.Issue.StartLocation.Line.ToString());
output = output.Replace("%C", match.Issue.StartLocation.Column.ToString());
output = output.Replace("%l", match.Issue.EndLocation.Line.ToString());
output = output.Replace("%c", match.Issue.EndLocation.Column.ToString());
output = output.Replace("%I", match.Issue.Boundary.Index.ToString());
output = output.Replace("%i", match.Issue.Boundary.Length.ToString());
output = output.Replace("%R", match.Issue.Rule.Id);
output = output.Replace("%N", match.Issue.Rule.Name);
output = output.Replace("%S", match.Issue.Rule.Severity.ToString());
output = output.Replace("%X", match.Issue.Confidence.ToString());//override rule confidence because of unstructured text vs source
output = output.Replace("%D", match.Issue.Rule.Description);
output = output.Replace("%m", match.TextSample);
output = output.Replace("%T", string.Join(',',match.Issue.Rule.Tags));
TextWriter.WriteLine(output);
}
private void WriteDependencies(AppProfile app)
{
foreach (string s in app.MetaData.UniqueDependencies)
TextWriter.WriteLine(s);
}
public override void FlushAndClose()
{
TextWriter.Flush();
TextWriter.Close();
}
string _formatString;
}
}

Просмотреть файл

@ -0,0 +1,307 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.DevSkim;
namespace Microsoft.AppInspector
{
/// <summary>
/// Class to handle text as a searchable container
/// </summary>
class TextContainer
{
/// <summary>
/// Creates new instance
/// </summary>
/// <param name="content">Text to work with</param>
public TextContainer(string content, string language)
{
_language = language;
_content = content;
_lineEnds = new List<int>(){ 0 };
// Find line end in the text
int pos = 0;
while(pos > -1 && pos < _content.Length)
{
if (++pos < _content.Length)
{
pos = _content.IndexOf('\n', pos);
_lineEnds.Add(pos);
}
}
// Text can end with \n or not
if (_lineEnds[_lineEnds.Count - 1] == -1)
_lineEnds[_lineEnds.Count - 1] = (_content.Length > 0) ? content.Length - 1 : 0;
}
/// <summary>
/// Returns all boundaries matching the pattern
/// </summary>
/// <param name="pattern">Search pattern</param>
/// <returns>List of boundaries</returns>
public List<Boundary> MatchPattern(SearchPattern pattern)
{
return MatchPattern(pattern, _content);
}
/// <summary>
/// Returns all boundaries matching the pattern
/// </summary>
/// <param name="pattern">Search pattern</param>
/// <param name="boundary">Content boundary</param>
/// <param name="searchIn">Search in command</param>
/// <returns></returns>
public bool MatchPattern(SearchPattern pattern, Boundary boundary, SearchCondition condition)
{
bool result = false;
Boundary scope = ParseSearchBoundary(boundary, condition.SearchIn);
string text = _content.Substring(scope.Index, scope.Length);
List<Boundary> macthes = MatchPattern(pattern, text);
if (macthes.Count > 0)
result = true;
return result;
}
/// <summary>
/// Returns location (Line, Column) for given index in text
/// </summary>
/// <param name="index">Position in text</param>
/// <returns>Location</returns>
public Location GetLocation(int index)
{
Location result = new Location();
if (index == 0)
{
result.Line = 1;
result.Column = 1;
}
else
{
for (int i = 0; i < _lineEnds.Count; i++)
{
if (_lineEnds[i] >= index)
{
result.Line = i;
result.Column = index - _lineEnds[i - 1];
break;
}
}
}
return result;
}
/// <summary>
/// Returns boundary for a given index in text
/// </summary>
/// <param name="index">Position in text</param>
/// <returns>Boundary</returns>
public Boundary GetLineBoundary(int index)
{
Boundary result = new Boundary();
for(int i=0; i < _lineEnds.Count; i++)
{
if (_lineEnds[i] >= index)
{
result.Index = (i > 0 && _lineEnds[i - 1] > 0) ? _lineEnds[i - 1] + 1 : 0;
result.Length = _lineEnds[i] - result.Index + 1;
break;
}
}
return result;
}
/// <summary>
/// Return content of the line
/// </summary>
/// <param name="line">Line number</param>
/// <returns>Text</returns>
public string GetLineContent(int line)
{
int index = _lineEnds[line];
Boundary bound = GetLineBoundary(index);
return _content.Substring(bound.Index, bound.Length);
}
/// <summary>
/// Returns all boundaries matching the pattern in a text
/// </summary>
/// <param name="pattern">Search pattern</param>
/// <param name="text">Text</param>
/// <returns>List of boundaries</returns>
private List<Boundary> MatchPattern(SearchPattern pattern, string text)
{
List<Boundary> matchList = new List<Boundary>();
RegexOptions reopt = RegexOptions.None;
if (pattern.Modifiers != null && pattern.Modifiers.Length > 0)
{
reopt |= (pattern.Modifiers.Contains("i")) ? RegexOptions.IgnoreCase : RegexOptions.None;
reopt |= (pattern.Modifiers.Contains("m")) ? RegexOptions.Multiline : RegexOptions.None;
}
Regex patRegx = new Regex(pattern.Pattern, reopt);
MatchCollection matches = patRegx.Matches(text);
if (matches.Count > 0)
{
foreach (Match m in matches)
{
Boundary bound = new Boundary() { Index = m.Index, Length = m.Length };
if (ScopeMatch(pattern, bound, text))
matchList.Add(bound);
}
}
return matchList;
}
/// <summary>
/// Check whether the boundary in a text matches the scope of a search pattern (code, comment etc.)
/// </summary>
/// <param name="pattern">Pattern with scope</param>
/// <param name="boundary">Boundary in a text</param>
/// <param name="text">Text</param>
/// <returns>True if boundary is matching the pattern scope</returns>
private bool ScopeMatch(SearchPattern pattern, Boundary boundary, string text)
{
string prefix = Language.GetCommentPrefix(_language);
string suffix = Language.GetCommentSuffix(_language);
string inline = Language.GetCommentInline(_language);
if (pattern.Scopes.Contains(PatternScope.All) || string.IsNullOrEmpty(prefix))
return true;
bool isInComment = ( IsBetween(text, boundary.Index, prefix, suffix)
|| IsBetween(text, boundary.Index, inline, "\n"));
return !(isInComment && !pattern.Scopes.Contains(PatternScope.Comment));
}
/// <summary>
/// Checks if the index in the string lies between preffix and suffix
/// </summary>
/// <param name="text">Text</param>
/// <param name="index">Index to check</param>
/// <param name="prefix">Prefix</param>
/// <param name="suffix">Suffix</param>
/// <returns>True if the index is between prefix and suffix</returns>
private bool IsBetween(string text, int index, string prefix, string suffix)
{
bool result = false;
string preText = string.Concat(text.Substring(0, index));
int lastPreffix = preText.LastIndexOf(prefix, StringComparison.Ordinal);
if (lastPreffix >= 0)
{
preText = preText.Substring(lastPreffix);
int lastSuffix = preText.IndexOf(suffix, StringComparison.Ordinal);
if (lastSuffix < 0)
result = true;
}
return result;
}
/// <summary>
/// Return boundary defined by line and its offset
/// </summary>
/// <param name="line">Line number</param>
/// <param name="offset">Offset from line number</param>
/// <returns>Boundary</returns>
private int BoundaryByLine(int line, int offset)
{
int index = line + offset;
// We need the begining of the line when going up
if (offset < 0)
index--;
if (index < 0)
index = 0;
if (index >= _lineEnds.Count)
index = _lineEnds.Count - 1;
return _lineEnds[index];
}
/// <summary>
/// Return boundary based on searchIn command and given boundary
/// </summary>
/// <param name="boundary">Relative boundary</param>
/// <param name="searchIn">Search in command</param>
/// <returns>Boundary</returns>
private Boundary ParseSearchBoundary(Boundary boundary, string searchIn)
{
// Default baundary is the fidning line
Boundary result = GetLineBoundary(boundary.Index);
string srch = (string.IsNullOrEmpty(searchIn)) ? string.Empty : searchIn.ToLower();
if (srch == "finding-only")
{
result.Index = boundary.Index;
result.Length = boundary.Length;
}
else if (srch.StartsWith("finding-region"))
{
if (ParseSearchIn(srch, out int[] args))
{
Location loc = GetLocation(boundary.Index);
result.Index = BoundaryByLine(loc.Line, args[0]);
result.Length = BoundaryByLine(loc.Line, args[1]) - result.Index;
}
}
return result;
}
/// <summary>
/// Parse search in command and return arguments
/// </summary>
/// <param name="searchIn">text to ba parsed</param>
/// <param name="args">arguments</param>
/// <returns>True if parsing was succsessful</returns>
private bool ParseSearchIn(string searchIn, out int[] args)
{
bool result = false;
List<int> arglist = new List<int>();
Regex reg = new Regex(".*\\((.*),(.*)\\)");
Match m = reg.Match(searchIn);
if (m.Success)
{
result = true;
for (int i=1; i < m.Groups.Count; i++)
{
if (int.TryParse(m.Groups[i].Value, out int value))
{
arglist.Add(value);
}
else
{
result = false;
break;
}
}
}
args = arglist.ToArray();
return result;
}
private string _content;
private List<int> _lineEnds;
private string _language;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System.IO;
namespace Microsoft.AppInspector.CLI.Writers
{
public abstract class Writer
{
public TextWriter TextWriter { get; set; }
public abstract void WriteApp(AppProfile appCharacteriation);
public abstract void FlushAndClose();
}
}

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
using System;
namespace Microsoft.AppInspector.CLI.Writers
{
public class WriterFactory
{
public static Writer GetWriter(string writerName, string defaultWritter, string format = null)
{
if (string.IsNullOrEmpty(writerName))
writerName = defaultWritter;
if (string.IsNullOrEmpty(writerName))
writerName = "text";
switch (writerName.ToLowerInvariant())
{
case "_dummy":
return new DummyWriter();
case "json":
return new JsonWriter();
case "text":
return new SimpleTextWriter(format);
case "html":
return new LiquidWriter();
//case "sarif":
// return new SarifWriter();
default:
throw new Exception("wrong output");
}
}
}
}

Просмотреть файл

@ -0,0 +1,68 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha256-YLGeXaapI0/5IgZopewRJcFXomhRMlYYjugPLSyNjTY=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css" integrity="sha256-zmfNZmXoNWBMemUOo1XUGFfc0ihGGLYdgtJS3KCr/l0=" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.8/c3.min.css" integrity="sha256-loJlaQZlNV5TexzLFHJ6fGO6PCjUQk4isWOG/7YffC4=" crossorigin="anonymous" />
<link rel="stylesheet" type="text/css" href="html/resources/appinspector.css" />
<title>{{ application_version }}</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-light navbar-lg">
<span class="navbar-brand">
<img src="https://upload.wikimedia.org/wikipedia/commons/4/44/Microsoft_logo.svg" width="32" height="32" class="d-inline-block align-top" alt="">
Application Inspector
</span>
<div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li><a class="nav-button" href="#" data-target="#page__report_overview">Overview</a></li>
<li><a class="nav-button" href="#" data-target="#page__report_summary">Summary</a></li>
<li><a class="nav-button" href="#" data-target="#page__report_profile">Profile</a></li>
<li><a class="nav-button" href="https://github.com/microsoft/AppInspector/wiki" data-target="#page__report_profile" target="_blank" rel="noopener">About</a></li>
</ul>
<ul class="navbar-nav ml-auto" style="margin-right: 80px">
<li>
<a class="nav-button" href="https://github.com/Microsoft/AppInspector" rel="noopener noreferrer">
<i class="fab fa-github" style="font-size: 1.8em; color: #888"></i>
</a>
</li>
</ul>
</div>
</nav>
<main role="main" class="container-fluid">
<div class="row">
<div class="col col-lg-2"></div>
<div class="col" id="page__report_overview">
{% include "report_overview" %}
</div>
<div class="col d-none" id="page__report_summary">
{% include "report_summary" %}
</div>
<div class="col d-none" id="page__report_profile">
{% include "report_profile" %}
</div>
<div class="col col-lg-2"></div>
</div>
</main>
{% include "file_listing" %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.15.0/umd/popper.min.js" integrity="sha256-fTuUgtT7O2rqoImwjrhDgbXTKUwyxxujIMRIK7TbuNU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha256-CjSoeELFOcH0/uxWu6mC/Vlrc1AARqbm/jiiImDGV3s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ace.js" integrity="sha256-CVkji/u32aj2TeC+D13f7scFSIfphw2pmu4LaKWMSY8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-settings_menu.js" integrity="sha256-SL34Lgdp8DbjL/8WzrKeQVoEgfsYV05j2LulsDyWEpI=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-modelist.js" integrity="sha256-Eq83mfVraqpouXYtwjYSEvTt6JM7k1VrhsebwRs06AM=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.6/ext-beautify.js" integrity="sha256-XURxU9F6YJl7wYVNfD4/aztOdXJyQ9vZ/03hyUknaOU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.12.0/d3.min.js" integrity="sha256-+9Mf3cAVmxxudDsr1XwXUeRZFtvdWVYdq5/vcgiYyNU=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.8/c3.min.js" integrity="sha256-N10MWEM8r2dC0bw4GafCShV+f23skko9fL5mIGcGd4A=" crossorigin="anonymous"></script>
<script type="text/javascript" src="html/resources/appinspector.js"></script>
<script type="text/javascript">
let data = {{ json }};
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,28 @@

<div id="file_listing_modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">File Listing</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div style="max-height: 150px; overflow-y:auto; border-bottom: 1px solid #ccc">
<ul style="list-style-type:none; padding-left: 0">
</ul>
</div>
<div style="height: 360px; overflow-y:auto;">
<div id="editor-container" style="margin-top: 5px;">
<div id="editor" style="width: 100%; height: 350px; max-height: 350px;">
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,71 @@
<div class="section">
<h2>Application Inspector Report</h2>
<strong>Welcome to the Microsoft Application Inspector Report.</strong>
This report represents the output for the specified source code for
identified makeup and characteristics. The report can help in validating
purported component objectives by examining source code against identifying
patterns for the detected change, including identifying applicable
security and privacy features. It also facilitates comparing key changes
across versions of components or scanning for specific features.
</div>
<div class="section">
<h5>Why it's different</h5>
Knowing what is in your software is the first step to making choices about
what actions are appropriate for allowing it to be deployed in your or your
customer environment. Unlike a typical source code static analyzer,
AppInspector is judgement free, focusing instead on helping inform security
and other scenarios by surfacing details that might otherwise go unnoticed.
</div>
<div class="section">
<h5>AppInspector Functions</h5>
<table class="table" style="width: auto !important;">
<tr>
<td><i class="fas fa-play"></i></td>
<td>Analyze</td>
<td>Scan source files for characteristics</td>
</tr>
<tr>
<td><i class="fas fa-tag"></i></td>
<td>Tag Test</td>
<td>Test source files for the presence of a specific tag identifier</td>
</tr>
<tr>
<td><i class="far fa-copy"></i></td>
<td>Tag Diff</td>
<td>Compare identified tags between versions</td>
</tr>
<tr>
<td><i class="fas fa-tags"></i></td>
<td style="text-align:left">Tags</td>
<td>Export Tags</td>
</tr>
<tr>
<td><i class="far fa-check-square"></i></td>
<td style="text-align:left">Verify</td>
<td>Verify rules structure</td>
</tr>
</table>
</div>
<div class="section">
<h4>Report Contents</h4>
A set of customizable "Profile" traits of interest are available. Additional tools
include a complete list of all traits detect and the full set of matching records
to pinpoint which rule patterns were triggered located just under the Inspect
menu. Traits are identified as "tags" found in the rule definitions which are
customizable JSON files found under the 'Rules' folder.
</div>
<div class="section">
<a class="btn btn-primary nav-button" role="button" href="#" data-target="#page__report_summary">View Report</a>
</div>
<div class="section">
<small>
For more information, please visit our <a href="https://github.com/Microsoft/AppInspector">GitHub</a> page to review
the AppInspector user guide, documentation, and source code.
</small>
</div>

Просмотреть файл

@ -0,0 +1,292 @@
<div class="section">
<h2>Application Profile</h2>
<div>
This section describes the main characteristics of the appliation
analyzed. Begin exploring by clicking any of the highlighted icons
below. You can also drill into specific characteristics by clicking
on the link shown on the right.
</div>
</div>
<br>
<div class="section">
<div class="container-fluid">
<div class="row">
<div class="col">
<table class="table table-sm" style="width:600px">
<tr>
<td>Select Features</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" title="Authentication" data-target="Authentication">
<i class="fas fa-sign-in-alt"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Authorization" data-target="Authorization">
<i class="fas fa-passport"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Cryptography" data-target="Cryptography">
<i class="fas fa-key"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Media File Parsing" data-target="MediaFileParsing">
<i class="fas fa-photo-video"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Object Deserialization" data-target="Deserialization">
<i class="far fa-object-ungroup"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>General Features</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="\.FileOperation" title="File Operations">
<i class="far fa-edit"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="\.Network" title="Network Communication">
<i class="fas fa-network-wired"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Application Type" data-target="Application\.Type">
<i class="fas fa-dot-circle"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Logging" data-target="Logging">
<i class="fas fa-file"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="HTML Forms" data-target="HTMLForm">
<i class="far fa-address-card"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>Development Frameworks</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Development\.Build" title="Build Tools">
<i class="fas fa-building"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Development\.Framework" title="Development Framework">
<i class="fab fa-dev"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Testing\.Framework" title="Test Framework">
<i class="fas fa-vial"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" title="Content Mngt System" data-target="Framework.\CMS">
<i class="fab fa-wpforms"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Reference\.SocialMedia" title="Social Media">
<i class="fab fa-facebook-square"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Miscellaneous\.OpenSourceLicense" title="Open Source License">
<i class="fas fa-file-contract"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Dependency\.SourceInclude" title="Source Code Inclusion">
<i class="far fa-plus-square"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>Data</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.SQL" title="SQL Commands">
<i class="fas fa-table"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.ORM" title="Object Relational Mapper">
<i class="fab fa-connectdevelop"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.ODBC" title="Object Database Connectivity">
<i class="fas fa-plug"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.DataAccess\.DBMS" title="Database Mngt System">
<i class="fas fa-database"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.DataAccess\..*Azure" title="Azure Data Services">
<i class="fab fa-microsoft"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.(XML|JSON)" title="JSON/XML">
<i class="far fa-file-code"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.Sensitive\.Personal" title="Sensitive/Personal Data">
<i class="fas fa-user-shield"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.Sensitive\.Medical" title="Sensitive/Medical Data">
<i class="fas fa-stethoscope"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.Finance" title="Financial Data">
<i class="fas fa-money-bill"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Data\.Serialization" title="Serialization">
<i class="fas fa-project-diagram"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>OS Integration</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.OS" title="OS Identification">
<i class="fab fa-linux"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="OS\.ACL" title="Access Control">
<i class="fas fa-user-alt-slash"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="OS\.Environment" title="Environment Variables">
<i class="fas fa-times"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="OS\.Process" title="Process Management">
<i class="fas fa-stream"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="OS\.SystemRegistry" title="System Registry">
<i class="fas fa-tree"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="OS\.UserAccount" title="System Accounts">
<i class="fas fa-running"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>Cloud Services</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Microsoft\.Azure" title="Microsoft Azure">
<i class="fab fa-microsoft"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Amazon\.AWS" title="Amazon Web Services">
<i class="fab fa-aws"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Google\.Cloud" title="Google Cloud Platform">
<i class="fab fa-google"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Microsoft\.Office" title="Microsoft Office">
<i class="far fa-file-word"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.Repository" title="Source Code Repository">
<i class="fab fa-github"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.PackageManager" title="Package Manager">
<i class="fas fa-box-open"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Platform\.CloudService\.CI" title="Continuous Integration">
<i class="fas fa-vials"></i>
</a>
</div>
</td>
</tr>
<tr>
<td>Other</td>
<td>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Miscellaneous\.Analytics" title="Analytics Services">
<i class="fas fa-diagnoses"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Miscellaneous\.AdvertisingNetwork" title="Advertising Network">
<i class="fas fa-ad"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="ObfuscatedCode" title="Obfuscated Strings">
<i class="far fa-eye-slash"></i>
</a>
</div>
<div class="grid-1">
<a href="#" class="feature_icon" data-target="Comment\.(Suspicious|Todo)" title="Incomplete Code (TODO)">
<i class="far fa-clock"></i>
</a>
</div>
</td>
</tr>
</table>
</div>
<div class="col">
<div id="features">
<table class="table table-sm table-hover">
<thead>
<tr>
<th>Characteristics</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,90 @@
<div class="section">
<h2>Report Summary</h2>
<div class="small font-weight-bold">
View as
&nbsp; &nbsp;
<a class="btn-link disabled font-weight-bold" href="#">HTML</a>
|
<a href="output.json">JSON</a>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-2">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" href="#project_info" role="tab" data-toggle="tab">Project Info</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#scan_metadata" role="tab" data-toggle="tab">Scan Metadata</a>
</li>
</ul>
</div>
<div class="col">
<div class="tab-content">
<div role="tabpanel" class="tab-pane active show" id="project_info">
<div class="container">
<div class="row">
<div class="col">
<div id="s_pi_analysis_chart"></div>
</div>
<div class="col">
<div id="s_pi_patterns_chart"></div>
</div>
<div class="col">
<div id="s_pi_languages_chart"></div>
</div>
</div>
</div>
<table class="table table-sm">
<tr>
<td class="font-weight-bold">Name</td>
<td id="s_pi_application_name"></td>
</tr>
<tr>
<td class="font-weight-bold">Version</td>
<td id="s_pi_version"></td>
</tr>
<tr>
<td class="font-weight-bold">Description</td>
<td id="s_pi_description"></td>
</tr>
<tr>
<td class="font-weight-bold">Folder</td>
<td id="s_pi_source_path"></td>
</tr>
<tr>
<td class="font-weight-bold">Author(s)</td>
<td id="s_pi_author"></td>
</tr>
<tr>
<td class="font-weight-bold">Analyzed</td>
<td id="s_pi_date_scanned"></td>
</tr>
</table>
</div>
<div role="tabpanel" class="tab-pane" id="scan_metadata">
<table class="table table-sm">
<tr>
<td class="font-weight-bold">Total Files</td>
<td id="s_mt_total_files"></td>
</tr>
<tr>
<td class="font-weight-bold">Files Analyzed</td>
<td id="s_mt_analyzed_files"></td>
</tr>
<tr>
<td class="font-weight-bold">Files Skipped</td>
<td id="s_mt_skipped_files"></td>
</tr>
</table>
</div>
<div role="tabpanel" class="tab-pane" id="profile">ccc</div>
</div>
</div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,105 @@
body {
background-color: #fcfefd !important;
font-family: 'Segoe UI',Roboto,Oxygen-Sans,Ubuntu,Cantarell,'Helvetica Neue',sans-serif;
}
a:hover {
text-decoration: none;
}
.navbar {
background-color: #F3F3F3 !important;
}
.navbar-brand:focus, .navbar-brand:hover {
text-decoration: none !important;
color: #000 !important;
}
.navbar-lg {
min-height: 80px;
border-radius: 0;
padding-top: 0;
padding-left: 0;
padding-right: 0;
padding-bottom: 5px;
}
.navbar-lg .navbar-brand {
margin-left: 80px;
font-size: 24px;
font-weight: bold;
color: #000;
}
.navbar-lg .navbar-nav > li {
margin-left: 15px;
margin-right: 15px;
font-size: 0.90em;
}
.navbar-lg .navbar-nav > li > a {
color: #000;
}
#file_listing_modal div.modal-dialog {
max-width: 70%;
}
/* Report Overview */
div.section {
margin-top: 15px;
margin-bottom: 15px;
}
#page__report_overview table tr:first-child td {
border-top: 0;
}
#page__report_overview table td {
padding: 0.10rem 0.55rem 0.10rem 0.55rem;
}
#page__report_overview table td:first-child {
text-align: center;
color: #888;
}
#page__report_overview table td:nth-child(2) {
text-align: center;
font-weight: bold;
}
#page__report_overview table td:nth-child(3) {
color: #888;
}
/* Report Summary */
.c3-chart-arcs-title {
font-weight: bold;
}
/* Report Profile */
#page__report_profile div.accordion {
padding-bottom: 6px;
border-bottom: 1px solid #0078d4;
}
#page__report_profile div.grid-1 {
width: 32px !important;
display: inline-block;
text-align: center;
margin-left: 6px;
margin-right: 6px;
color: #7FBA00;
font-size: 1.4rem;
}
#page__report_profile table td:nth-child(1) {
font-weight: normal;
font-size: 0.9rem;
vertical-align: middle;
}
#page__report_profile a.disabled {
color: #ccc;
cursor: default;
}

Просмотреть файл

@ -0,0 +1,269 @@
$(document).ready(() => {
// Initialize Bootstrap
$('[data-toggle="popover"]').popover();
$('[data-toggle="tooltip"]').tooltip();
/* Main Navigation Links: These are links that change the
* visible section to something else, specified by the
* `data-target` attribute of the link, which should usually
* be the #div-identifier to be shown.
*/
$('a.nav-button').on('click', (e) => {
let current = $('body').data('visible_section') || '#page__report_overview';
let target = $(e.target).data('target');
if (!!target) {
if (!!current) {
$(current).addClass('d-none');
}
$(target).removeClass('d-none');
$('body').data('visible_section', target);
}
});
$('a.file_listing').on('click', (e) => {
$('#editor-container').addClass('d-none');
$('#file_listing_modal').modal();
alert(1);
})
/*
* When a user clicks on a file listing filename, load the data
* to show into the Ace editor in the popup dialog.
*/
$('#file_listing_modal').on('click', 'a.content-link', (e) => {
const content = $(e.target).data('excerpt');
const startLocationLine = $(e.target).data('startLocationLine');
const editor = ace.edit("editor");
editor.setOption('firstLineNumber', startLocationLine);
editor.getSession().setValue(content);
editor.resize();
editor.scrollToLine(0);
$('editor-container').removeClass('d-none');
});
const templateInsertion = new TemplateInsertion(data);
templateInsertion.processSummaryPage();
templateInsertion.processProfilePage();
});
class TemplateInsertion {
constructor(data) {
this.ap = data.AppProfile;
this.mt = this.ap.MetaData;
this.md = data.matchDetails;
}
processSummaryPage() {
c3.generate({
bindto: '#s_pi_analysis_chart',
size: {
width: 200
},
data: {
columns: [
['Analyzed', this.mt.filesAnalyzed],
['Skipped', this.mt.filesSkipped],
],
type: 'donut'
},
donut: {
title: "Analyzed Files",
label: {
format: function(value) { return value; }
}
}
});
c3.generate({
bindto: '#s_pi_patterns_chart',
size: {
width: 200
},
data: {
columns: [
['Unique Matches', this.mt.uniqueMatchesCount],
['Repeats', this.mt.totalMatchesCount - this.mt.uniqueMatchesCount],
],
type: 'donut'
},
donut: {
title: "Results",
label: {
format: function(value) { return value; }
}
}
});
c3.generate({
bindto: '#s_pi_languages_chart',
size: {
width: 200
},
data: {
columns: Object.entries(this.mt.languages),
type: 'donut'
},
donut: {
title: "Languages",
label: {
format: function(value) { return value; }
}
}
});
$('#s_pi_application_name').html(this.mt.applicationName);
$('#s_pi_version').html(this.mt.sourceVersion);
$('#s_pi_description').html(this.mt.description || 'No description available.');
$('#s_pi_source_path').html(this.ap.sourcePath);
$('#s_pi_author').html(this.mt.authors || 'No author found.');
$('#s_pi_date_scanned').html(this.ap.dateScanned);
}
combineConfidence(a, b) {
if (a && !b) return a;
if (b && !a) return b;
if (!a && !b) return 'Low';
const _a = a.toLowerCase();
const _b = b.toLowerCase();
const map = { 'low': 1, 'medium': 2, 'high': 4 };
if (map[_a] > map[_b]) { return a; }
return b;
}
show_file_listing(e) {
let $_tr = e.target.nodeName == 'TR' ? $(e.target) : $(e.target).closest('tr');
let ruleid = $_tr.find('a').data('ruleid');
let $this = e.data.obj;
$('#file_listing_modal ul').empty();
$('editor-container').addClass('d-none');
const removePrefix = (fn) => {
if (!fn.startsWith($this.ap.sourcePath)) {
return fn;
}
return fn.slice($this.ap.sourcePath.length);
}
for (let match of $this.md) {
let excerpt = atob(match.excerpt || '') || match.sample;
if (match.ruleId === ruleid || match.ruleName === ruleid) {
let $li = $('<li>');
let $a = $('<a>');
$a.addClass('content-link')
.attr('href', '#')
.data('excerpt', excerpt)
.data('startLocationLine', match.startLocationLine - 3)
.text(removePrefix(match.fileName));
$li.append($a);
$('#file_listing_modal ul').append($li);
}
}
$('#file_listing_modal').on('shown.bs.modal', function (e) {
$('a.content-link').first().trigger('click');
});
$('#file_listing_modal').modal();
}
/*
* Builds the Profile page, including event handlers.
*/
processProfilePage() {
// Process each icon with the 'feature_icon' class.
$('a.feature_icon').each((idx, elt) => {
const targetRegexValue = $(elt).data('target');
if (!targetRegexValue) {
$(elt).addClass('disabled'); // Disable icon if no target exists
return;
}
let foundTag = false;
const targetRegex = new RegExp(targetRegexValue, 'i');
// We have a target, treated as a regular expression.
// We're goint to go through all results (this.md) and if it contains
// a tag that matches what we're looking for, we'll keep that icon visible.
search_loop:
for (let match of this.md) {
for (let tag of match.tags) {
if (targetRegex.exec(tag)) {
foundTag = true; // We have at least one match for this icon
break search_loop;
}
}
}
if (!foundTag) {
$(elt).addClass('disabled');
}
});
// Event handler for visible icons
$('a.feature_icon').on('click', (e) => {
const targetRegexValue = $(e.target).closest('a').data('target');
if (!targetRegexValue) {
console.log('Error: No target regular expression. This probably indicates a bug.');
return;
}
const targetRegex = new RegExp(targetRegexValue, 'i');
let identifiedRules = {};
for (let match of this.md) {
for (let tag of match.tags) {
if (targetRegex.exec(tag)) {
identifiedRules[match.ruleName] = this.combineConfidence(identifiedRules[match.ruleName], match.confidence);
break; // Only break out of inner loop, we only need one match per tag set
}
}
}
const $tbody = $('#features table tbody');
$tbody.empty();
// Now we iterate through all of the rules that relate to this icon
for (let [rule, confidence] of Object.entries(identifiedRules)) {
// I'm sorry, this is pretty ugly. If you'd like to clean this up, I'd be
// happy to take a pull request.
let $tr = $('<tr>');
$tr.on('click', 'td', { 'obj': this }, this.show_file_listing);
let $td0 = $('<td>');
let $td0a = $('<a>');
$td0a.attr('href', '#');
$td0a.data('ruleid', rule); // BUG: This should be the rule id, not the name
$td0a.text(rule);
//$td0a.on('click', {'obj': this }, this.show_file_listing);
$td0.append($td0a);
//let $td1 = $('<td>');
//let $td1d = $('<div>');
//$td1d.addClass('progress');
//$td1d.css('width', '120px');
//let $td1dp = $('<div>');
//$td1dp.addClass('progress-bar')
// .addClass('bg-info')
// .attr('role', 'progressbar')
// .css('width', '100%')
// .attr('aria-valuenow', 100)
// .attr('aria-valuemin', 0)
// .attr('aria-valuemax', 100)
// .text('High');
//$td1d.append($td1dp);
//$td1.append($td1d);
$tr.append($td0)
//$tr.append($td1);
$tbody.append($tr);
}
});
}
}

Двоичные данные
AppInspector/htmltemplates/authN-d.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 477 B

Двоичные данные
AppInspector/htmltemplates/authN-n.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 527 B

Двоичные данные
AppInspector/htmltemplates/authZ-d.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 776 B

Двоичные данные
AppInspector/htmltemplates/authZ-n.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 940 B

Двоичные данные
AppInspector/htmltemplates/bar1.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1007 B

10229
AppInspector/htmltemplates/bootstrap.css поставляемый Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Двоичные данные
AppInspector/htmltemplates/crypto-d.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 827 B

Двоичные данные
AppInspector/htmltemplates/crypto-n.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 680 B

Двоичные данные
AppInspector/htmltemplates/desz-d.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 370 B

Двоичные данные
AppInspector/htmltemplates/desz-n.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 339 B

Двоичные данные
AppInspector/htmltemplates/export.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 664 B

Двоичные данные
AppInspector/htmltemplates/medparse-d.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 723 B

Двоичные данные
AppInspector/htmltemplates/medparse-n.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 598 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.1 KiB

Двоичные данные
AppInspector/htmltemplates/rulesverified.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 895 B

Двоичные данные
AppInspector/htmltemplates/scan.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 788 B

Двоичные данные
AppInspector/htmltemplates/tagdiff.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 543 B

Двоичные данные
AppInspector/htmltemplates/tagtest.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 864 B

Просмотреть файл

@ -0,0 +1,124 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<!-- All features -->
<h4>All Match Details</h4>
count={{ app.matchList.Count }} &nbsp; <a href="jsonreport.json">Json Report</a>
<div class="card-columns">
{{ #each app.matchList }}
<div class="card" style="height:400px;overflow-y:scroll;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Match</h5>
<div class="card-text">
<table class="table table-condensed">
<tr>
<td>Rule ID:</td>
<td>{{ this.Issue.Rule.Id }}</td>
</tr>
<tr>
<td>Rule name:</td>
<td>{{ this.Issue.Rule.Name }}</td>
</tr>
<tr>
<td>Rule description:</td>
<td>{{ this.Issue.Rule.Description }}</td>
</tr>
<tr>
<td>File</td>
<td><a href="file:///{{ this.Filename }}" rel="noopener" target="_blank">{{ this.Filename }}</a></td>
</tr>
<tr>
<td>Source type</td>
<td>{{ this.Language }}</td>
</tr>
<tr>
<td>Line number</td>
<td>{{ this.Issue.StartLocation.Line }}</td>
</tr>
<tr>
<td>Tags</td>
<td>{{ this.Issue.Rule.Tags.[0] }}</td>
</tr>
<tr>
<td>Confidence</td>
<td>{{ this.Issue.PatternMatch.Confidence }}</td>
</tr>
<tr>
<td>Pattern Type</td>
<td>{{ this.Issue.PatternMatch.PatternType }}</td>
</tr>
<tr>
<td>Pattern</td>
<td>{{ this.Issue.PatternMatch.Pattern }}</td>
</tr>
<tr>
<td>Text sample</td>
<td>{{ this.TextSample }}</td>
</tr>
</table>
</div>
</div>
</div>
{{#unless @last}} {{/unless}}
{{ /each }}
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,128 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<h4 class="card-title">All Tags Found</h4>
<div>count={{ app.MetaData.UniqueTags.Count }}</div>
<!-- Design Extraction -->
<div class="row section section-design-extraction">
<div class="col-md-12">
<div class="panel panel-primary">
The tags shown represent patterns detected in the inspected source code. <strong>Click</strong>
any of the values for a list of which files the tags were detected in.
<br />
<br />
<div class="panel-body">
{{ #each tagGrpAllTagsByName }}
<a href="#" data-action="popup" data-tag="{{ this.Tag }}"><span class="badge-info">{{ this.Tag }}</span></a>
{{ /each }}
</div>
</div>
</div>
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
$('a[data-action="popup"]').on('click', function () {
var tag = $(this).data('tag');
var html = '';
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
.append($('<td>' + $(elt).data('filename') + '</td>'))
.append($('<td>' + $(elt).data('line') + '</td>'));
$('table#detail-summary tbody').append($row);
});
$('#detail_popup div.details').html('');
$('#detail_popup').modal();
});
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
var id = $(this).data('id');
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
$('#detail_popup div.details').html(excerpt);
});
});
</script>
<div class="d-none">
{{ #each app.matchList }}
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
{{ /each }}
</div>
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detail_popup_label">Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="height: 450px">
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
<table class="table table-sm" id="detail-summary">
<tbody></tbody>
</table>
</div>
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,149 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body style=" background-color: cornflowerblue">
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<h4 style="color:whitesmoke">Composition</h4>
<div class="card-columns">
<div class="card" style="max-height:500px;overflow-y:scroll;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Dependencies</h5>
<div class="card-text">
<ul>
{{ #each strGrpUniqueDependencies }}
<li>{{ this }}</li>
{{ else }}
No items found
{{ /each }}
</ul>
</div>
</div>
</div>
[[subSectionStart]]
<div class="card" style="max-height:400px; overflow-y:scroll; border: 1px solid #6c757d">
<div class="card-body">
<h5 class="card-title">[[subSectionName]]</h5>
<div class="card-text">
<table class="table table-condensed">
{{ #each [[subSectionVarRef]] }}
<tr>
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.ShortTag }}</a></td>
</tr>
{{ else }}
No items found
{{ /each }}
</table>
</div>
</div>
</div>
[[subSectionEnd]]
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
$('a[data-action="popup"]').on('click', function () {
var tag = $(this).data('tag');
var html = '';
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
.append($('<td>' + $(elt).data('filename') + '</td>'))
.append($('<td>' + $(elt).data('line') + '</td>'));
$('table#detail-summary tbody').append($row);
});
$('#detail_popup div.details').html('');
$('#detail_popup').modal();
});
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
var id = $(this).data('id');
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
$('#detail_popup div.details').html(excerpt);
});
});
</script>
<div class="d-none">
{{ #each app.matchList }}
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
{{ /each }}
</div>
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detail_popup_label">Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="height: 450px">
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
<table class="table table-sm" id="detail-summary">
<tbody></tbody>
</table>
</div>
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,123 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector-Home</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<div class="card" style="border:none">
<div class="card-body">
<h5 class="card-title">AppInspector Report</h5>
<div class="card-text">
Welcome to the Microsoft AppInspector <strong>ver. &lt;{{app.Version}}&gt;</strong> Report. This report represents the output for the
specified source code for identified makeup and characteristics. The report can help in validating purported component
objectives by examining sourcecode against identifying patterns for the detected language, including identifying applicable
security and privacy features. It also facilitates comparing key changes across versions of components or scanning for specific features.
</div>
</div>
</div>
<div class="card" style="border:none">
<div class="card-body">
<h5 class="card-title">Why It's Different</h5>
<div class="card-text">
Knowing what is in your software is the first step to making choices about what actions are appropriate for allowing it to be deployed in
your or your customer environment. Unlike a typical source code static analyzer, AppInspector is judgement free, focusing instead on
helping inform security and other scenarios by surfacing details that might otherwise go unnoticed.
</div>
</div>
</div>
<div class="card" style="border:none">
<div class="card-body">
<h5 class="card-title">AppInspector Functions</h5>
<div class="card-text">
<table class="table table-condensed" style="width:620px;">
<tr><td><image src="scan.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Analyze</strong></td><td>Scan source files for characteristics.</td></tr>
<tr><td><image src="tagtest.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>TagTest</strong></td><td>Test source for presence of specified tag subset.</td></tr>
<tr><td><image src="tagdiff.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>TagDiff</strong></td><td>Compare tags between differing source code.</td></tr>
<tr><td><image src="export.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Tags</strong></td><td>Export tags.<td></tr>
<tr><td><image src="rulesverified.png" style="width:25px;height:25px;"></td><td style="width:80px;"><strong>Verify</strong></td><td>Verify tag rules structure.<td></tr>
</table>
</div>
</div>
</div>
<div class="card" style="border:none">
<div class="card-body">
<h5 class="card-title">Report Contents</h5>
<div class="card-text">
A set of customizable "Profile" traits of interest are available. Additional tools include a complete list of all traits detected
and the full set of matching records to pinpoint which rule patterns were triggered located just under the
Inspect menu. Traits are identified as "tags" found in the rule definitions which are customizable json files found under the 'Rules' folder.
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='projecthome.html'">View Report</button>
</div>
</div>
</div>
<div class="card" style="border:none">
<div class="card-body">
<div class="card-text">
See the project site for more at <a href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">https://github.com/Microsoft/AppInspector</a>
</div>
</div>
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,165 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<div class="card-columns">
[[subSectionStart]]
<div class="card" style="height:400px; overflow-y:scroll; border: 1px solid #6c757d">
<div class="card-body">
<h5 class="card-title">[[subSectionName]]</h5>
<div class="card-text">
<table class="table table-condensed">
<tr><td style="width:300px;color:dimgray;"><strong>Tag</strong></td><td style="color:dimgray;"><strong>Detected</strong></td><td style="color:dimgray;text-align:right"><strong>Confidence</strong></td></tr>
{{ #each [[subSectionVarRef]] }}
<tr>
<td style="width:300px;"><img src="{{this.StatusIcon}}" />{{this.ShortTag}}</td>
<td>{{ this.Detected }}</td>
<td style="text-align:right"><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Confidence }}</a></td>
</tr>
{{ else }}
No items found
{{ /each }}
</table>
</div>
</div>
</div>
[[subSectionEnd]]
<div class="card" style="height:400px; overflow-y:scroll; border: 1px solid #6c757d">
<div class="card-body">
<h5 class="card-title">Selected Counters</h5>
<div class="card-text">
<table class="table table-condensed" style="width:auto;">
<tr><td style="width:375px;color:dimgray;"><strong>Tag</strong></td><td style="color:dimgray;"><strong>Count</strong></td></tr>
{{ #each selectTagCounters }}
<tr>
<td style="width:465px;">{{ this.ShortTag }}</td>
<td style="text-align:right">{{ this.Count }}</td>
</tr>
{{ else }}
No items found
{{ /each }}
</table>
</div>
</div>
</div>
<div style="text-align:right">
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='composition.html'">See Composition</button>
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
$('a[data-action="popup"]').on('click', function () {
var tag = $(this).data('tag');
var html = '';
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
var $row = $('<tr data-id="' + $(elt).data('id') + '" style="cursor:pointer;"/>')
.append($('<td>' + $(elt).data('filename') + '</td>'))
.append($('<td>' + $(elt).data('line') + '</td>'));
$('table#detail-summary tbody').append($row);
});
$('#detail_popup div.details').html('');
$('#detail_popup').modal();
});
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
var id = $(this).data('id');
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
$('#detail_popup div.details').html(excerpt);
});
});
</script>
<div class="d-none">
{{ #each app.matchList }}
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags.[0] }}"></div>
{{ /each }}
</div>
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detail_popup_label">Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="height: 450px">
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
<table class="table table-sm" id="detail-summary">
<tbody></tbody>
</table>
</div>
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,239 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector-Home</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<div><img src="bar1.png" style="width:100%;height:30px;" /></div>
<div style="height:3px;"></div>
<div class="card-columns">
<div class="card text-white" style="border: 1px solid gray;scrollbar-face-color:darkseagreen;height:400px;max-height:400px;overflow-y:scroll; background-color: cornflowerblue">
<div class="card-body">
<h5 class="card-title"><strong>Project Info</strong></h5>
<div class="card-text">
<table class="table table-condensed" style="table-layout: fixed; width: 100%">
<tr><td style="width:123px;">Name</td><td>{{ app.MetaData.ApplicationName }}&nbsp;{{ app.MetaData.SourceVersion }}</td></tr>
<tr><td style="width:123px;">Description</td><td style="word-wrap: break-word">{{ app.MetaData.Description }}</td></tr>
<tr><td style="width:123px;">Directory</td><td style="word-wrap: break-word">{{ app.SourcePath }}</td></tr>
<tr><td style="width:123px;">Author(s)</td><td>{{ app.MetaData.Authors }}</td></tr>
<tr><td style="width:123px;">Last Modified</td><td>{{ app.MetaData.LastUpdated }}</td></tr>
</table>
</div>
</div>
</div>
<div class="card" style="height:400px;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Source Info</h5>
<div class="card-text">
<table class="table table-condensed">
<tr>
<td style="width:123px;">Programming Language(s)</td>
<td>
{{ #each app.MetaData.Languages }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td style="width:123px;">Type(s)</td>
<td>
{{ #each app.MetaData.Outputs }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td style="width:123px;">Extensions</td>
<td>
{{ #each app.MetaData.FileExtensions }}
<a href="http://fileinfo.com/extension/{{ this }}" target="_blank" rel="noopener">{{ this }}</a>
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td style="width:123px;">Package Types</td>
<td>
{{ #each strGrpPackageTypes }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="card" style="height:400px;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Stats</h5>
<div class="card-text">
<table class="table table-condensed">
<tr><td>Files Analyzed</td><td style="text-align:right">{{ app.MetaData.FilesAnalyzed }}</td></tr>
<tr><td>Files Skipped</td><td style="text-align:right">{{ app.MetaData.FilesSkipped }}</td></tr>
<tr><td>Total Files</td><td style="text-align:right">{{ app.MetaData.TotalFiles }}</td></tr>
<tr><td>Total Pattern Matches</td><td style="text-align:right">{{ app.MetaData.TotalMatchesCount }}</td></tr>
<tr><td>Unique Pattern Matches</td><td style="text-align:right">{{ app.MetaData.UniqueTags.Count }}</td></tr>
<tr><td>Dependencies</td><td style="text-align:right">{{ app.MetaData.UniqueDependencies.Count }}</td></tr>
</table>
</div>
</div>
</div>
<div class="card" style="height:400px;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Detected Targets</h5>
<div class="card-text">
<table class="table table-condensed">
<tr>
<td>Cloud Platform</td>
<td style="text-align:right">
{{ #each app.MetaData.CloudTargets }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td>Operating System</td>
<td style="text-align:right">
{{ #each app.MetaData.OSTargets }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td>CPU Targets</td>
<td style="text-align:right">
{{ #each app.MetaData.CPUTargets }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="card" style="height:400px;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Scan Settings</h5>
<div class="card-text">
<table class="table table-condensed" style="table-layout: fixed; width: 100%">
<tr><td style="width:123px;">AppInspector</td><td>{{ app.Version }}</td></tr>
<tr>
<td style="width:123px;">Rules Path</td>
<td style="max-width:200px;">
{{ #each strGrpRulePaths }}
{{ this }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td style="width:123px;">Scan Arguments</td>
<td style="word-wrap: break-word">{{ app.Args }}</td>
</tr>
<tr><td style="width:123px;">Date Scanned</td><td>{{ app.DateScanned }}</td></tr>
</table>
</div>
</div>
</div>
<div class="card" style="height:400px;border: 1px solid #6c757d;">
<div class="card-body">
<h5 class="card-title">Build Info</h5>
<div class="card-text">
<table class="table table-condensed">
<tr>
<td>Build Tools</td>
<td style="text-align:right">
{{ #each tagGrpBuildTools }}
{{ this.shortTag }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
<tr>
<td>Testing Tools</td>
<td style="text-align:right">
{{ #each tagGrpTstFrm }}
{{ this.shortTag }}
{{#unless @last}}, {{/unless}}
{{ /each }}
</td>
</tr>
</table>
</div>
</div>
</div>
<div style="text-align:right">
<button type="button" style="background-color:dodgerblue;color:white" onclick="window.location='profile.html'">Continue to Profile</button>
</div>
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,196 @@
<!doctype html>
<!-- Copyright (c) Microsoft Corporation.
Licensed under the MIT License. -->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>AppInpector</title>
<link rel="stylesheet" href="bootstrap.css">
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<img src="Microsoft_logo_-_2012_(vertical).svg.png" />&nbsp;
<a class="navbar-brand" href="index.html">AppInspector</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="projecthome.html">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="profile.html">Profile</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Inspect</a>
<div class="dropdown-menu" aria-labelledby="dropdown01">
<a class="dropdown-item" href="composition.html">Composition</a>
<a class="dropdown-item" href="rankedtags.html">Ranked Tags</a>
<a class="dropdown-item" href="alltags.html">All Tags</a>
<a class="dropdown-item" href="allmatches.html">All Matches</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/Microsoft/AppInspector" target="_blank" rel="noopener">About</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
<button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
</form>
</div>
</nav>
<main role="main" class="container" style="max-width: 100%">
<h4 class="card-title">Unique Sortable Tags</h4>
<div>count={{ app.MetaData.UniqueTags.Count }}</div>
<div class="card-columns">
<div id="divtag" class="card" style="border:none;display:normal">
<div class="card-body">
<div class="card-text">
<table class="table table-condensed" style="border:none; width:500px;">
<tr>
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a>&nbsp;</td>
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a>&nbsp;</td>
</tr>
<tr></tr>
{{ #each tagGrpAllTagsByName }}
<tr>
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
<td>{{ this.Confidence }}</td>
<td>{{ this.Severity }}</td>
</tr>
{{ /each }}
</table>
</div>
</div>
</div>
<div id="divconf" class="card" style="border:none; width:500px;display:none">
<div class="card-body">
<div class="card-text">
<table class="table table-condensed">
<tr>
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a>&nbsp;</td>
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a>&nbsp;</td>
</tr>
{{ #each tagGrpAllTagsByConfidence }}
<tr>
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
<td>{{ this.Confidence }}</td>
<td>{{ this.Severity }}</td>
</tr>
{{ /each }}
</table>
</div>
</div>
</div>
<div id="divsev" class="card" style="border:none; width:500px;display:none">
<div class="card-body">
<div class="card-text">
<table class="table table-condensed">
<tr>
<td><a href="#" onclick="SortbyTags();"><strong>Tag</strong></a></td>
<td><a href="#" onclick="SortbyConfidence();"><strong>Confidence</strong></a>&nbsp;</td>
<td><a href="#" onclick="SortbySeverity();"><strong>Severity</strong></a>&nbsp;</td>
</tr>
{{ #each tagGrpAllTagsBySeverity }}
<tr>
<td><a href="#" data-action="popup" data-tag="{{ this.Tag }}">{{ this.Tag }}</a></td>
<td>{{ this.Confidence }}</td>
<td>{{ this.Severity }}</td>
</tr>
{{ /each }}
</table>
</div>
</div>
</div>
</div>
</main><!-- /.container -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script>
function SortbyConfidence() {
$('#divconf').attr('style', 'display:normal;border:none');
$('#divsev').attr('style', 'display:none');
$('#divtag').attr('style', 'display:none');
}
function SortbySeverity() {
$('#divsev').attr('style', 'display:normal;border:none');
$('#divconf').attr('style', 'display:none');
$('#divtag').attr('style', 'display:none');
}
function SortbyTags() {
$('#divtag').attr('style', 'display:normal;border:none');
$('#divsev').attr('style', 'display:none');
$('#divconf').attr('style', 'display:none');
}
</script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", function () {
$('a[data-action="popup"]').on('click', function () {
var tag = btoa($(this).data('tag'));
var html = '';
$('div[data-tag="' + tag + '"]').each(function (idx, elt) {
var $row = $('<tr data-id="' + $(elt).data('id') + '"/>')
.append($('<td>' + atob($(elt).data('filename')) + '</td>'))
.append($('<td>' + $(elt).data('line') + '</td>'));
$('table#detail-summary tbody').append($row);
});
var snippets = $('div').find('[data-tag="' + tag + '"]').each(function (idx, elt) {
html += atob(elt.innerText);
});
$('#detail_popup div.details').html('');
$('#detail_popup').modal();
});
$('#detail_popup table#detail-summary tbody').on('click', 'tr', function () {
var id = $(this).data('id');
var excerpt = atob($('div[data-id="' + id + '"]').data('excerpt'));
$('#detail_popup div.details').html(excerpt);
});
});
</script>
<div class="d-none">
{{ #each app.matchList }}
<div data-id="{{ this.Issue.Rule.Id }}" data-filename="{{ this.Filename }}" data-line="{{ this.Issue.StartLocation.Line }}" data-excerpt="{{ this.Excerpt }}" data-tag="{{ this.Issue.Rule.Tags[0] }}"></div>
{{ /each }}
</div>
<div class="modal fade" id="detail_popup" tabindex="-1" role="dialog" aria-labelledby="detail_popup_label" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detail_popup_label">Details</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" style="height: 450px">
<div class="summary" style="overflow-y:auto;height:35%;font-size:0.8em;">
<table class="table table-sm" id="detail-summary">
<tbody></tbody>
</table>
</div>
<div class="details" style="white-space:pre;overflow-y:auto;height:65%;font-size:0.75em;font-family:monospace; border-top: 2px solid #444; margin-top: 6px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Open File</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
[
{
"tag": "Metric.Classes.Defined",
"displayName": "Classes",
"includeAsMatch": false
},
{
"tag": "Metric.Functions.Defined",
"displayName": "Functions",
"includeAsMatch": false
},
{
"tag": "Metric.Exception.Caught",
"displayName": "Exceptions",
"includeAsMatch": true
},
{
"tag": "Metric.HTMLForm.Defined",
"displayName": "Forms",
"includeAsMatch": true
},
{
"tag": "Dependency.SourceInclude",
"displayName": "Dependencies",
"includeAsMatch": true
},
{
"tag": "Miscellaneous.CodeHygiene.Comment",
"displayName": "Comments",
"includeAsMatch": true
},
{
"tag": "Metric.Logging.Call",
"displayName": "Logging Calls",
"includeAsMatch": true
}
]

Просмотреть файл

@ -0,0 +1,284 @@
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
[
{
"categoryName": "profile",
"type": "uniqueTags",
"groups": [
{
"title": "Security Basics",
"dataRef": "SDLBasic",
"patterns": [
{
"searchPattern": "Authentication",
"displayName": "Authentication",
"detectedIcon": "authN-d.png",
"notDetectedIcon": "authN-n.png"
},
{
"searchPattern": "Authorization",
"displayName": "Authorization",
"detectedIcon": "authZ-d.png",
"notDetectedIcon": "authZ-n.png"
},
{
"searchPattern": "Cryptography",
"displayName": "Cryptography",
"detectedIcon": "crypto-d.png",
"notDetectedIcon": "crypto-n.png"
},
{
"searchPattern": "Data.Serialization.Deserialization",
"displayName": "ObjectDeserialization",
"detectedIcon": "desz-d.png",
"notDetectedIcon": "desz-n.png"
},
{
"searchPattern": "Data.Media",
"displayName": "MediaParsing",
"detectedIcon": "medparse-d.png",
"notDetectedIcon": "medparse-n.png"
}
]
},
{
"title": "Extended Security",
"dataRef": "ExtendedSDL",
"patterns": [
{
"searchPattern": "Network.Connect",
"displayName": "ExternalNetComms"
},
{
"searchPattern": "FileOperation.Write",
"displayName": "FileWrite"
},
{
"searchPattern": "FileOperation.Delete",
"displayName": "FileDelete"
},
{
"searchPattern": "DynamicExecution",
"displayName": "DynamicExecution"
},
{
"searchPattern": "Data.SensitiveAccount",
"displayName": "Accounts"
},
{
"searchPattern": "Data.Sensitive.Personal",
"displayName": "Personal Data"
},
{
"searchPattern": "OS.ACL.Write",
"displayName": "OSACLWrite"
}
]
},
{
"title": "Features",
"dataRef": "Features",
"patterns": [
{
"searchPattern": "Data.Finance",
"displayName": "FinancialData"
},
{
"searchPattern": "SystemRegistry.Write",
"displayName": "WindowsRegistryWrite"
},
{
"searchPattern": "DataAccess",
"displayName": "DataAccess"
},
{
"searchPattern": "Multiprocessing",
"displayName": "Multi-Threading"
}
]
},
{
"title": "Misc",
"dataRef": "Misc",
"patterns": [
{
"searchPattern": "OSS",
"displayName": "OSS"
},
{
"searchPattern": "SocialMedia",
"displayName": "SocialMediaUse"
},
{
"searchPattern": "Process.Access.Read",
"displayName": "OS Process Scan"
}
]
},
{
"title": "System Access Changes",
"dataRef": "SysAccess",
"patterns": [
{
"searchPattern": "ACL.AppContainer",
"displayName": "ACLImpersonationAppContainer"
},
{
"searchPattern": "ACL.Write",
"displayName": "ACLWrite"
},
{
"searchPattern": "OS.ACL.Permission.Elevated",
"displayName": "ACLElevatedPermission"
},
{
"searchPattern": "Windows.Registry.Security",
"displayName": "WindowsRegistrySecurity"
},
{
"searchPattern": "TokenImpersonation",
"displayName": "ACLImpersonationToken"
},
{
"searchPattern": "System.Userorname.Add",
"displayName": "SystemUserAdded"
},
{
"searchPattern": "Environment.Write",
"displayName": "EnvironmentVarsWrite"
},
{
"searchPattern": "SecurityEventSource",
"displayName": "SecurityEventSource"
},
{
"searchPattern": "Audit.Write",
"displayName": "AuditPermissionsWrite"
},
{
"searchPattern": "System.Token.Write",
"displayName": "SystemTokenWrite"
}
]
}
]
},
{
"categoryName": "composition",
"type": "allTags",
"groups": [
{
"title": "Cryptography",
"dataRef": "Cryptography",
"patterns": [
{
"searchPattern": "Cryptography",
"displayName": "Cryptography"
}
]
},
{
"title": "Content",
"dataRef": "Content",
"patterns": [
{
"searchPattern": "Data.XML",
"displayName": "ProcessesXML"
},
{
"searchPattern": "Data.JSON",
"displayName": "ProcessesJSON"
},
{
"searchPattern": "Data.Media",
"displayName": "ProcessesMedia"
}
]
},
{
"title": "Binary Objects",
"dataRef": "Objects",
"patterns": [
{
"searchPattern": "Component.Adobe.Flash",
"displayName": "FlashObjectUse"
},
{
"searchPattern": "Component.ActiveX",
"displayName": "ActiveXUse"
},
{
"searchPattern": "Component.PDF",
"displayName": "PDFObjectUse"
},
{
"searchPattern": "ObjectType.Media",
"displayName": "MediaObjectUse"
}
]
},
{
"title": "Development Frameworks",
"dataRef": "DevFrameWrks",
"patterns": [
{
"searchPattern": "Development.Framework",
"displayName": "DevelopmentFramework"
}
]
},
{
"title": "Testing Frameworks",
"dataRef": "TestFrameWrks",
"patterns": [
{
"searchPattern": "Testing.Framework",
"displayName": "TestFramework"
}
]
},
{
"title": "Personal Data",
"dataRef": "PII",
"patterns": [
{
"searchPattern": "Data.Sensitive.Personal",
"displayName": "Personal Data"
}
]
},
{
"title": "Social Media",
"dataRef": "SocMedia",
"patterns": [
{
"searchPattern": "SocialMedia",
"displayName": "SocialMedia"
}
]
},
{
"title": "Data Access",
"dataRef": "DataAccess",
"patterns": [
{
"searchPattern": "DataAccess",
"displayName": "DataAccess"
}
]
},
{
"title": "OSS License Types",
"dataRef": "DataAccess",
"patterns": [
{
"searchPattern": "OpenSourceLicense",
"displayName": "OSSLicenseTypes"
}
]
}
]
}
]

Просмотреть файл

@ -0,0 +1,203 @@
[
{
"name": "OS: Dynamic Execution",
"id": "AI034510",
"description": "OS: Dynamic Execution",
"applies_to": [
"objective-c",
"swift"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "stringByEvaluatingJavaScriptFromString",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": "https://developer.apple.com/documentation/uikit/uiwebview/1617963-stringbyevaluatingjavascriptfrom?language=objc"
},
{
"pattern": "evaluateJavaScript",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": "https://developer.apple.com/documentation/webkit/wkwebview/1415017-evaluatejavascript?language=objc"
}
]
},
{
"name": "OS: Dynamic Execution",
"id": "AI034511",
"description": "OS: Dynamic Execution",
"applies_to": [
"javascript",
"ruby",
"javascriptreact"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "\\beval\\(",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "exec(Sync)?\\(",
"type": "substring",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "\\bspawn\\(",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "\\bsystem\\(",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"_comment": ""
},
]
},
{
"name": "OS: Dynamic Execution",
"id": "AI034512",
"description": "OS: Dynamic Execution",
"recommendation": "",
"applies_to": [
"csharp"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "process.start",
"type": "substring",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "xp_cmdshell",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "OS: Dynamic Execution",
"id": "AI034513",
"description": "OS: Dynamic Execution",
"applies_to": [
"powershell"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(iex|invoke-expression).*[.]*webclient",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "(iex|invoke-expression).*[.]*downloadstring",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "OS: Dynamic Execution",
"id": "AI034513",
"description": "OS: Dynamic Execution",
"applies_to": [
"c",
"cpp"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ksh|bash|csh|sh",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "system(",
"type": "substring",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "createprocess|execl|execlp|execlp|execv|execve|execvp|execvpe|execle|fork",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "OS: Dynamic Execution",
"id": "AI034514",
"description": "OS: Dynamic Execution",
"applies_to": [
"java"
],
"tags": [
"OS.Process.DynamicExecution"
],
"severity": "moderate",
"patterns": [
{
"pattern": "Runtime.getRuntime().exec",
"type": "substring",
"scopes": [
"code"
],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,3 @@
line: 1
====
NSString *string1 = [NSString stringWithFormat:@"A string: %@, a float: %1.2f", @"string", 31415.9265];

Просмотреть файл

@ -0,0 +1,93 @@
[
{
"name": "Cryptography: Algorithm Implementation",
"id": "AI053010",
"description": "Cryptography: Algorithm Implementation",
"tags": [
"Cryptography.Implementation"
],
"severity": "important",
"_comment": "Implementing a standard cryptographic algorithm",
"patterns": [
{
"pattern": "5a827999",
"type": "regex-word",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": []
}
]
},
{
"name": "Cryptography: Algorithm Implementation (SHA1)",
"id": "AI053020",
"description": "Cryptography: Algorithm Implementation (SHA1)",
"tags": [
"Cryptography.Implementation.SHA1"
],
"severity": "important",
"patterns": [
{
"pattern": "5a827999",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Cryptography: Algorithm Implementation (MD5)",
"id": "AI053030",
"description": "Cryptography: Algorithm Implementation (MD5)",
"tags": [
"Cryptography.Implementation.MD5"
],
"severity": "important",
"patterns": [
{
"pattern": "242070db",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Cryptography: Algorithm Implementation (SHA-256)",
"id": "AI053040",
"description": "Cryptography: Algorithm Implementation (SHA-256)",
"tags": [
"Cryptography.Implementation.SHA256"
],
"severity": "important",
"patterns": [
{
"pattern": "d807aa98",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Cryptography: Algorithm Implementation (Keccak)",
"id": "AI053050",
"description": "Cryptography: Algorithm Implementation (Keccak)",
"tags": [
"Cryptography.Implementation.SHA256"
],
"severity": "important",
"patterns": [
{
"pattern": "800000000000808A",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
}
]

Просмотреть файл

@ -0,0 +1,54 @@
[
{
"name": "Cryptography: x.509 Certificate",
"id": "AI057510",
"description": "Cryptography: x.509 Certificate",
"tags": [
"Cryptography.x509"
],
"severity": "moderate",
"patterns": [
{
"pattern": "x509|\\.(crt|pem|cer|pfx|csr)|certificate",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "genrsa|-keyout|-x509toreq|signkey",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ ],
"confidence": "high",
"_comment": "Common OpenSSL commands"
}
]
},
{
"name": "Cryptography: x.509 Certificate",
"id": "AI057520",
"description": "Cryptography: x.509 Certificate",
"tags": [
"Cryptography.x509"
],
"severity": "moderate",
"patterns": [
{
"pattern": "x509|\\.(crt|pem|cer)",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,115 @@
[
{
"name": "Cryptography: Encryption",
"id": "AI555500",
"description": "Cryptography: Encryption",
"tags": [
"Cryptography.Encryption"
],
"severity": "moderate",
"patterns": [
{
"pattern": "encrypt|decrypt|cipher|crypt",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Encryption (AES)",
"id": "AI555510",
"description": "Cryptography: Encryption (AES)",
"tags": [
"Cryptography.Encryption.AES"
],
"severity": "moderate",
"patterns": [
{
"pattern": "AES",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "AES-?(128|192|256)",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Encryption (3DES)",
"id": "AI555520",
"description": "Cryptography: Encryption (3DES)",
"tags": [
"Cryptography.Encryption.3DES"
],
"severity": "moderate",
"patterns": [
{
"pattern": "3DES|TripleDES",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Encryption (RC)",
"id": "AI555530",
"description": "Cryptography: Encryption (RC)",
"tags": [
"Cryptography.Encryption.RC"
],
"severity": "moderate",
"patterns": [
{
"pattern": "RC([2456])",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "arc4random",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Encryption: Cipher Mode",
"id": "AP003100",
"description": "Encryption: Cipher Mode",
"tags": [
"Cryptography.Encryption.CipherMode"
],
"severity": "critical",
"_comment": "",
"patterns": [
{
"pattern": "CBC|CTR|ECB|OFB|CFB|CTS|PCBC|GMAC|XCBC|IACBC|IAPM|EAX|OCB|CWC|AEAD|LRW|XEX|XTS|CMC|EME|CBCMAC|OMAC|PMAC",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,34 @@
[
{
"name": "CryptoCurrency",
"id": "AI054500",
"description": "CryptoCurrency",
"tags": [
"Cryptography.Currency"
],
"severity": "moderate",
"patterns": [
{
"pattern": "cardano|ethereum|cryptocurrency",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "miner|ripple|nxt|zcash|tether|ether|btc|monero|markleroot|xmr|eth|p2pool",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "medium"
},
{
"pattern": "(bit|lite|name|peer|doge|grid|prim|vert|tit|pot)coin",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,22 @@
[
{
"name": "Cryptography: Encoding (Base-64)",
"id": "AI054010",
"description": "Cryptography: Encoding (Base-64)",
"applies_to": [
],
"tags": [
"Cryptography.Encoding.Base64"
],
"severity": "moderate",
"patterns": [
{
"pattern": "base64",
"type": "substring",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
}
]

Просмотреть файл

@ -0,0 +1,161 @@
[
{
"name": "Crypographic Library: BouncyCastle",
"id": "AI051000",
"description": "Crypographic Library: BouncyCastle",
"applies_to": [
"csharp",
"java",
"kotlin",
"scala"
],
"tags": [
"Cryptography.Library.BouncyCastle"
],
"severity": "moderate",
"patterns": [
{
"pattern": "bouncycastle|spongycastle",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: mbed TLS",
"id": "AI051010",
"description": "Crypographic Library: mbed TLS",
"applies_to": [
],
"tags": [
"Cryptography.Library.mbedTLS"
],
"severity": "moderate",
"patterns": [
{
"pattern": "mbedtls",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: OpenSSL",
"id": "AI051020",
"description": "Crypographic Library: OpenSSL",
"applies_to": [
],
"tags": [
"Cryptography.Library.OpenSSL"
],
"severity": "moderate",
"patterns": [
{
"pattern": "openssl",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: BoringSSL",
"id": "AI051030",
"description": "Crypographic Library: BoringSSL",
"applies_to": [
],
"tags": [
"Cryptography.Library.BoringSSL"
],
"severity": "moderate",
"patterns": [
{
"pattern": "boringssl",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: LibreSSL",
"id": "AI051040",
"description": "Crypographic Library: LibreSSL",
"applies_to": [
],
"tags": [
"Cryptography.Library.LibreSSL"
],
"severity": "moderate",
"patterns": [
{
"pattern": "libressl",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: Win32",
"id": "AI051100",
"description": "Crypographic Library: Win32",
"applies_to": [
],
"tags": [
"Cryptography.Library.Win32"
],
"severity": "moderate",
"patterns": [
{
"pattern": "\\b(wincrypt|cryptxml|wintrust|dpapi|bcrypt|cryptdlg|ncrypt|cryptxml|ncryptprotect)\\.h",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "i" ]
}
]
},
{
"name": "Crypographic Library: .NET",
"id": "AI051110",
"description": "Crypographic Library: .NET",
"applies_to": [
"c",
"cpp",
"csharp"
],
"tags": [
"Cryptography.Library.NET"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ProtectedData",
"type": "string",
"scopes": [
"code"
],
"modified": [ "i" ],
"_comment": ""
},
{
"pattern": "DPAPI",
"type": "string",
"scopes": [
"code"
],
"modified": [ "i" ],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,102 @@
[
{
"name": "Cryptography: Hash Algorithm Usage",
"id": "AI052000",
"description": "Cryptography: Hash Algorithm Usage",
"tags": [
"Cryptography.HashAlgorithm"
],
"severity": "moderate",
"patterns": [
{
"pattern": "HashAlgorithm|MessageDigest|DigestUtils",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Hash Algorithm Usage (SHA-256)",
"id": "AI052010",
"description": "Cryptography: Hash Algorithm Usage (SHA-256)",
"tags": [
"Cryptography.HashAlgorithm.SHA2"
],
"severity": "moderate",
"patterns": [
{
"pattern": "SHA-?(2|224|256|384|512)",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Hash Algorithm Usage (Legacy)",
"id": "AI052020",
"description": "Cryptography: Hash Algorithm Usage (Legacy)",
"tags": [
"Cryptography.HashAlgorithm.Legacy"
],
"severity": "moderate",
"patterns": [
{
"pattern": "MD2|MD4|MD5|SHA-?0",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Hash Algorithm Usage (SHA-3)",
"id": "AI052030",
"description": "Cryptography: Hash Algorithm Usage (SHA-3)",
"tags": [
"Cryptography.HashAlgorithm.SHA3"
],
"severity": "moderate",
"patterns": [
{
"pattern": "SHA-?3|Keccak",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Hash Algorithm Usage (Misc)",
"id": "AI052040",
"description": "Cryptography: Hash Algorithm Usage (Misc)",
"tags": [
"Cryptography.HashAlgorithm.Misc"
],
"severity": "moderate",
"patterns": [
{
"pattern": "RIPEMD|Blowfish|Twofish|Threefish|Serpent",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,712 @@
[
{
"name": "Detect Cryptography",
"id": "AP003900",
"description": "Detect use of cryptography",
"recommendation": "",
"tags": [
"Inspect.Threatmodel.Cryptography.Infrastructure"
],
"severity": "moderate",
"_comment": "",
"rule_info": "",
"patterns": [
{
"pattern": "SSLCACertificateFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCACertificatePath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCADNRequestFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCADNRequestPath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCARevocationCheck",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCARevocationFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCARevocationPath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCertificateChainFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCertificateFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCertificateKeyFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCipherSuite",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCompression",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLCryptoDevice",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLEngine",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLFIPS",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLHonorCipherOrder",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLInsecureRenegotiation",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPDefaultResponder",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPEnable",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPOverrideResponder",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPProxyURL",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPResponderTimeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPResponseMaxAge",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPResponseTimeSkew",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOCSPUseRequestNonce",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOpenSSLConfCmd",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLOptions",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLPassPhraseDialog",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProtocol",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCACertificateFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCACertificatePath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCARevocationCheck",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCARevocationFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCARevocationPath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCheckPeerCN",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCheckPeerExpire",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCheckPeerName",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyCipherSuite",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyEngine",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyMachineCertificateChainFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyMachineCertificateFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyMachineCertificatePath",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyProtocol",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyVerify",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLProxyVerifyDepth",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLRandomSeed",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLRenegBufferSize",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLRequire",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLRequireSSL",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSessionCache",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSessionCacheTimeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSessionTicketKeyFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSessionTickets",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSRPUnknownUserSeed",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLSRPVerifierFile",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingCache",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingErrorCacheTimeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingFakeTryLater",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingForceURL",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingResponderTimeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingResponseMaxAge",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingResponseTimeSkew",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingReturnResponderErrors",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStaplingStandardCacheTimeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLStrictSNIVHostCheck",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLUserName",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLUseStapling",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLVerifyClient",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "SSLVerifyDepth",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_buffer_size",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_crl",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_dhparam",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_ecdh_curve",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_password_file",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_prefer_server_ciphers",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_protocols",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_session_cache",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_session_ticket_key",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_session_tickets",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_session_timeout",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_stapling",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_stapling_file",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_stapling_responder",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_stapling_verify",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_trusted_certificate",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_verify_client",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
},
{
"pattern": "ssl_verify_depth",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high",
"modifiers": [ "" ],
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,49 @@
[
{
"name": "Cryptography: Key Derivation",
"id": "AI056010",
"description": "Cryptography: Key Derivation",
"tags": [
"Cryptography.KeyDerivation"
],
"severity": "moderate",
"patterns": [
]
},
{
"name": "Cryptography: Key Derivation (PBKDF1)",
"id": "AI056020",
"description": "Cryptography: Key Derivation (PBKDF1)",
"tags": [
"Cryptography.KeyDerivation.PBKDF1"
],
"severity": "moderate",
"patterns": [
{
"pattern": "pbkdf1|PasswordDeriveBytes",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: Key Derivation (PBKDF2)",
"id": "AI056030",
"description": "Cryptography: Key Derivation (PBKDF2)",
"tags": [
"Cryptography.KeyDerivation.PBKDF2"
],
"severity": "moderate",
"patterns": [
{
"pattern": "pbkdf2",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,76 @@
[
{
"name": "Cryptography: SSL/TLS Protocol",
"id": "AI057000",
"description": "Cryptography: SSL/TLS Protocol",
"applies_to": [
"csharp"
],
"tags": [
"Cryptography.Protocol.TLS"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(SSL|TLS)(v)?([123]{1,2})",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Cryptography: SSL/TLS Protocol",
"id": "AI057010",
"description": "Cryptography: SSL/TLS Protocol",
"applies_to": [
"c",
"objective-c",
"swift"
],
"tags": [
"Cryptography.Protocol.TLS"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(kCF|NS)StreamSocketSecurityLevel(None|SSLv2|SSLv3|TLSv1|NegotiatedSSL)",
"type": "regex-word",
"scopes": [ "code" ],
"confidence": "high"
},
{
"pattern": "kSSLProtocol(2|3Only|All|Unknown)",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high"
},
{
"pattern": "k(D)?(SSL|TLS)Protocol(1|1Only|2|3Only|All)",
"type": "regex",
"scopes": [ "code" ],
"confidence": "high"
}
]
},
{
"name": "Cryptography: SSH Protocol",
"id": "AI057110",
"description": "Cryptography: SSH Protocol",
"tags": [
"Cryptography.Protocol.SSH"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ssh",
"type": "regex-word",
"scopes": [ "code" ],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,80 @@
[
{
"name": "Crypgraphy: PRNG",
"id": "AI055020",
"description": "Crypgraphy: PRNG",
"tags": [
"Cryptography.Randomness.PRNG"
],
"applies_to": [
"c",
"cpp"
],
"severity": "critical",
"patterns": [
{
"pattern": "DUAL_EC_DRBG",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
},
{
"pattern": "pseudoRandomBytes",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Crypgraphy: PRNG",
"id": "AI055030",
"description": "Crypgraphy: PRNG",
"tags": [
"Cryptography.Randomness.PRNG"
],
"applies_to": [
"javascript"
],
"severity": "critical",
"patterns": [
{
"pattern": "(pseudo)?randombytes",
"type": "string",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Crypgraphy: PRNG",
"id": "AI055040",
"description": "Crypgraphy: PRNG",
"tags": [
"Cryptography.Randomness.PRNG"
],
"applies_to": [
"java"
],
"severity": "critical",
"patterns": [
{
"pattern": "SecureRandom",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
}
]

Просмотреть файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,260 @@
[
{
"name": "Data: Access (Azure Storage Account)",
"id": "AI068610",
"description": "Data: Access (Azure Storage Account)",
"applies_to": [
"csharp"
],
"tags": [
"Data.DataAccess.Microsoft.Azure.Storage"
],
"severity": "moderate",
"patterns": [
{
"pattern": "CloudStorageAccount",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Data: Access (Azure Storage Account: Blob)",
"id": "AI068611",
"description": "Data: Access (Azure Storage Account: Blob)",
"applies_to": [
"csharp"
],
"tags": [
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
],
"severity": "moderate",
"patterns": [
{
"pattern": "CreateCloudBlobClient|BlobRequestOptions|GetBlockBlobReference|CloudBlockBlob|CloudBlobContainer|BlobContinuationToken|CloudPageBlob",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Data: Access (Azure Storage Account: Blob)",
"id": "AI068612",
"description": "Data: Access (Azure Storage Account: Blob)",
"applies_to": [
"python"
],
"tags": [
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(BlockBlobService|azure)\\.storage\\.blob",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Data: Access (Azure Storage Account: Blob)",
"id": "AI068613",
"description": "Data: Access (Azure Storage Account: Blob)",
"applies_to": [
"javascript"
],
"tags": [
"Data.DataAccess.Microsoft.Azure.Storage.Blob"
],
"severity": "moderate",
"patterns": [
{
"pattern": ".createBlobService",
"type": "string",
"scopes": [
"code"
],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Data: ORM (SQL Alchemy)",
"id": "AI068614",
"description": "Data: ORM (SQL Alchemy)",
"applies_to": [ "python" ],
"tags": [
"Data.DataAccess.ORM.SQLAlchemy"
],
"severity": "moderate",
"patterns": [
{
"pattern": "sqlalchemy",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Data: ORM (Django)",
"id": "AI068615",
"description": "Data: ORM (Django)",
"applies_to": [ "python" ],
"tags": [
"Data.DataAccess.ORM.Django"
],
"severity": "moderate",
"patterns": [
{
"pattern": "django",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Data: DBMS (SQLite)",
"id": "AI068616",
"description": "Data: DBMS (SQLite)",
"applies_to": [ "python" ],
"tags": [
"Data.DataAccess.DBMS.SQLite"
],
"severity": "moderate",
"patterns": [
{
"pattern": "sqlite",
"type": "string",
"scopes": [ "code" ],
"confidence": "high"
}
]
},
{
"name": "Data: DBMS (PostgreSQL)",
"id": "AI068617",
"description": "Data: DBMS (PostgreSQL)",
"applies_to": [],
"tags": [
"Data.DataAccess.DBMS.SQLite"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(pgsql|PG)\\.connect|PG::Connection",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Data: DBMS (PostgreSQL)",
"id": "AI068618",
"description": "Data: DBMS (PostgreSQL)",
"applies_to": [ "python" ],
"tags": [
"Data.DataAccess.DBMS.SQLite"
],
"severity": "moderate",
"patterns": [
{
"pattern": "psycopg2",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Data: DBMS (PostgreSQL)",
"id": "AI068619",
"description": "Data: DBMS (PostgreSQL)",
"applies_to": [ "csharp" ],
"tags": [
"Data.DataAccess.DBMS.SQLite"
],
"severity": "moderate",
"patterns": [
{
"pattern": "npgsql",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Data: ODBC",
"id": "AI068620",
"description": "Data: ODBC",
"applies_to": [ "csharp" ],
"tags": [
"Data.DataAccess.ODBC"
],
"severity": "moderate",
"patterns": [
{
"pattern": "Odbc|OdbcConnection|OdbcCommand|OdbcDataReader",
"type": "regex-word",
"scopes": [ "code" ],
"confidence": "high"
}
]
},
{
"name": "Data: SQL",
"id": "AI068621",
"description": "Data: SQL",
"applies_to": [],
"tags": [
"Data.DataAccess.SQL"
],
"severity": "moderate",
"patterns": [
{
"pattern": "['\\\"](select|insert|delete)\\s.*",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
],
"conditions": [
{
"pattern": {
"pattern": "from|where",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"_comment": ""
},
"search_in": "finding-region(-5,5)",
"negate_finding": false,
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,109 @@
[
{
"name": "Data: Commerce",
"id": "AI068510",
"description": "Data: Commerce",
"tags": [
"Data.Finance"
],
"severity": "moderate",
"patterns": [
{
"pattern": "pci|wallet|fips-140",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "medium"
},
{
"pattern": "paypal|google pay|ebay|google\\.com/pay/api",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "price|shopping chart|payment",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ]
},
{
"pattern": "bigcommerce|shopify|bigcartel|woocommerce|wc_api_client|weebly|3dcart|squarespace|connect\\.squareup\\.com",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "demandware|yocart|opencart|magento|magentohost/api|volusion|vtex|x-vtex-api-appkey|alibaba",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Data: Financial",
"id": "AI068511",
"description": "Data: Financial",
"tags": [
"Data.Finance"
],
"severity": "moderate",
"patterns": [
{
"pattern": "bank\\s*(acct|account)",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "(checking|savings|chk)\\s*(account|acct)",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "income|salary|salaries|financial",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "currency|usd|money|dollar|euro|peso",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "medium",
"_comment": "Currencies"
}
]
},
{
"name": "Data: Financial (Credit Card)",
"id": "AI068512",
"description": "Data: Financial (Credit Card)",
"tags": [
"Data.Finance.CreditCard"
],
"severity": "moderate",
"patterns": [
{
"pattern": "visa|americanexpress|amex|(master|discover|credit|debit)\\s*card",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,39 @@
[
{
"name": "Data: JSON",
"id": "AI068010",
"description": "Data: JSON",
"tags": [
"Data.JSON"
],
"severity": "moderate",
"patterns": [
{
"pattern": "json",
"type": "substring",
"scopes": [
"code"
]
}
]
},
{
"name": "Data: JSON",
"id": "AI068020",
"description": "Data: JSON",
"tags": [
"Data.JSON"
],
"applies_to": [ "csharp" ],
"severity": "moderate",
"patterns": [
{
"pattern": "JavaScriptSerializer",
"type": "string",
"scopes": [
"code"
]
}
]
}
]

Просмотреть файл

@ -0,0 +1,61 @@
[
{
"name": "Data: XML",
"id": "AI068110",
"description": "Data: XML",
"tags": [
"Data.XML"
],
"severity": "moderate",
"patterns": [
{
"pattern": "xml|dom|sax|xpath|xmldom|xelement|xmldocument",
"type": "regex-word",
"scopes": [
"code"
]
}
]
},
{
"name": "Data: XML",
"id": "AI068120",
"description": "Data: XML",
"applies_to": [ "python" ],
"tags": [
"Data.XML"
],
"severity": "moderate",
"patterns": [
{
"pattern": "lxml|etree|ElementTree|minidom|pulldom|xmlrpc",
"type": "regex-word",
"scopes": [
"code"
]
}
]
},
{
"name": "Data: XML",
"id": "AI068130",
"description": "Data: XML",
"applies_to": [ "java" ],
"tags": [
"Data.XML"
],
"severity": "moderate",
"patterns": [
{
"pattern": "jdom2|SAXBuilder",
"type": "regex-word",
"scopes": [
"code"
]
}
]
}
]

Просмотреть файл

@ -0,0 +1,50 @@
[
{
"name": "Data: Embedded Secret (Access Token)",
"id": "AI068310",
"description": "Data: Embedded Secret",
"tags": [
"Data.Sensitive.SensitiveKey"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(secret|pass).*[a-f0-9]{30,}",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "low"
},
{
"pattern": "[\"'][a-f0-9]{30,}[\"']",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"confidence": "low"
}
]
},
{
"name": "Data: Embedded Secret (Access Token)",
"id": "AI068311",
"description": "Data: Embedded Secret",
"tags": [
"Data.Sensitive"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(secret|password|credential|credentials|access_token)\\s*[=:]",
"type": "regex-word",
"scopes": [
"code"
],
"modifiers": [ "i" ]
}
]
}
]

Просмотреть файл

@ -0,0 +1,206 @@
[
{
"name": "Data: Sensitive (Personal Information)",
"id": "AI068400",
"description": "Data: Sensitive (Personal Information)",
"tags": [
"Data.Sensitive.Personal"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(first|last|sur)name",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "medium"
},
{
"pattern": "birthdate|ethnicity|gender|citizenship|nationality|martial|marriage|married|spouce|mother|father|kid|kids",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "medium"
},
{
"pattern": "race|avatar|photo",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "low"
},
{
"pattern": "ssnumber|socialsecurity|nationalid|passport|drvlic|studentID",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "phone|mobilenumber|email|emailaddress|emailaddr",
"type": "regex-word",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "ipaddress|ipaddr",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high"
},
{
"pattern": "geotracking",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "medium"
}
]
},
{
"name": "Data: Sensitive (Personal Information)",
"id": "AI068401",
"description": "Data: Sensitive (Personal Information)",
"tags": [
"Data.Sensitive.Personal"
],
"severity": "moderate",
"patterns": [
{
"pattern": "mobile",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "medium"
}
],
"conditions": [
{
"pattern": {
"pattern": "user|phone|cell|number",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"_comment": ""
},
"search_in": "finding-region(-30,30)",
"negate_finding": false,
"_comment": ""
}
]
},
{
"name": "Data: Sensitive (Medical Information)",
"id": "AI068402",
"description": "Data: Sensitive (Medical Information)",
"tags": [
"Data.Sensitive.Personal"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ssn",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "medium"
}
],
"conditions": [
{
"pattern": {
"pattern": "user",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"_comment": ""
},
"search_in": "finding-region(-40,40)",
"negate_finding": false,
"_comment": ""
}
]
},
{
"name": "Data: Sensitive (Medical Information)",
"id": "AI068403",
"description": "Data: Sensitive (Medical Information)",
"tags": [
"Data.Sensitive.Medical"
],
"severity": "moderate",
"patterns": [
{
"pattern": "medical|insurance|doctor",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "low"
}
]
},
{
"name": "Data: Sensitive",
"id": "AI068404",
"description": "Data: Sensitive",
"tags": [
"Data.Sensitive"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(strictly|highly) confidential",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
},
{
"pattern": "secret",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Data: Sensitive (Account Information)",
"id": "AI068405",
"description": "Data: Sensitive (Account Information)",
"tags": [
"Data.Sensitive.Account"
],
"severity": "moderate",
"patterns": [
{
"pattern": "account|registration|membership|acct|acctnum|accountnum|accountnumber",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
],
"conditions": [
{
"pattern": {
"pattern": "user",
"type": "regex",
"scopes": [
"code"
],
"modifiers": [ "i" ],
"_comment": ""
},
"search_in": "finding-region(-40,40)",
"negate_finding": false,
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,254 @@
[
{
"name": "Data: Serialization",
"id": "AI068210",
"description": "Data: Serialization",
"applies_to": [
"python"
],
"tags": [
"Data.Serialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(de)?serialize",
"type": "regex",
"scopes": [
"code"
],
"confidence": "medium"
}
]
},
{
"name": "Data: Serialization",
"id": "AI068211",
"description": "Data: Serialization",
"applies_to": [
"python"
],
"tags": [
"Data.Serialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "import .*c?pickle",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Serialization",
"id": "AI068212",
"description": "Data: Serialization",
"applies_to": [
"python"
],
"tags": [
"Data.Serialization.Serialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "c?pickle\\.dump",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068213",
"description": "Data: Deserialization",
"applies_to": [
"python"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "c?pickle\\.load",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068214",
"description": "Data: Deserialization",
"applies_to": [
"java"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": ".readObject",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068215",
"description": "Data: Deserialization",
"applies_to": [
"php"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "unserialize(",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068216",
"description": "Data: Deserialization",
"applies_to": [
"ruby"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "(YAML|Syck|Marshal)\\.load",
"type": "regex",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Serialization",
"id": "AI068217",
"description": "Data: Serialization",
"applies_to": [
"csharp"
],
"tags": [
"Data.Serialization.Serialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "SerializeObject",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068218",
"description": "Data: Deserialization",
"applies_to": [
"csharp"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "DeserializeObject",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "PopulateObject",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "TypeNameHandling",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Data: Deserialization",
"id": "AI068219",
"description": "Data: Deserialization",
"applies_to": [
"csharp"
],
"tags": [
"Data.Serialization.Deserialization"
],
"severity": "moderate",
"patterns": [
{
"pattern": "System.Runtime.Serialization",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "BinaryFormatter",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
},
{
"pattern": "TypeNameHandling",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,95 @@
[
{
"name": "Detect Frameworks",
"id": "AP012000",
"description": "Detect well-known frameworks used",
"recommendation": "",
"applies_to": [ "php" ],
"tags": [ "Development.Framework.PHP" ],
"severity": "moderate",
"_comment": "",
"rule_info": "",
"patterns": [
{
"pattern": "Laravel",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Symfony",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "CodeIgniter",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Zend",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Fuelphp",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Slim",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Phalcon",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Aura",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Yii",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
},
{
"pattern": "Cakephp",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,190 @@
[
{
"name": "Development: Build Tool (Maven)",
"id": "AI063010",
"description": "Development: Build Tool (Maven)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Maven" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Maven",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Ant)",
"id": "AI063011",
"description": "Development: Build Tool (Ant)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Ant" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Ant",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Gradle)",
"id": "AI063012",
"description": "Development: Build Tool (Gradle)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Gradle" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Gradle",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Jenkins)",
"id": "AI063013",
"description": "Development: Build Tool (Jenkins)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Jenkins" ],
"severity": "moderate",
"patterns": [
{
"pattern": "jenkins",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (SBT)",
"id": "AI063014",
"description": "Development: Build Tool (SBT)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.SBT" ],
"severity": "moderate",
"patterns": [
{
"pattern": "sbt",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Bamboo)",
"id": "AI063015",
"description": "Development: Build Tool (Bamboo)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Bamboo" ],
"severity": "moderate",
"patterns": [
{
"pattern": "atlassian bamboo",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (TeamCity)",
"id": "AI063016",
"description": "Development: Build Tool (TeamCity)",
"recommendation": "",
"applies_to": [ "java" ],
"tags": [ "Development.Build.TeamCity" ],
"severity": "moderate",
"patterns": [
{
"pattern": "teamcity",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Grape)",
"id": "AI063017",
"description": "Development: Build Tool (Grape)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Grape" ],
"severity": "moderate",
"patterns": [
{
"pattern": "grape",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Ivy)",
"id": "AI063018",
"description": "Development: Build Tool (Ivy)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Ivy" ],
"severity": "moderate",
"patterns": [
{
"pattern": "ivy",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Leiningen)",
"id": "AI063019",
"description": "Development: Build Tool (Leiningen)",
"applies_to": [ "java" ],
"tags": [ "Development.Build.Leiningen" ],
"severity": "moderate",
"patterns": [
{
"pattern": "leiningen",
"type": "string",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
},
{
"name": "Development: Build Tool (Visual Studio)",
"id": "AI063020",
"description": "Development: Build Tool (Studio)",
"applies_to": [ "VSSolution", "VSProject" ],
"tags": [ "Development.Build.VisualStudio" ],
"severity": "moderate",
"patterns": [
{
"pattern": "VisualStudio|Visual Studio",
"type": "regex",
"scopes": [ "code", "comment" ],
"modifiers": [ "i" ],
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,42 @@
[
{
"name": "Development Framework: Standard C Library",
"id": "AI061010",
"description": "Development Framework: Standard C Library",
"recommendation": "",
"applies_to": [ "c" ],
"tags": [ "Development.Framework.StandardCLibrary" ],
"severity": "moderate",
"patterns": [
{
"pattern": "std::",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Boost",
"id": "AI061020",
"description": "Development Framework: Boost",
"recommendation": "",
"applies_to": [ "c" ],
"tags": [ "Development.Framework.StandardCLibrary" ],
"severity": "moderate",
"patterns": [
{
"pattern": "boost::",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
},
{
"pattern": "#include <boost/.*>",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
}
]

Просмотреть файл

@ -0,0 +1,120 @@
[
{
"name": "Component: Adobe Flash",
"id": "AI066010",
"description": "Component: Adobe Flash",
"applies_to": [
"actionscript"
],
"tags": [
"Development.Framework.Component.AdobeFlash"
],
"severity": "moderate",
"patterns": [
{
"pattern": "import flash",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Component: Adobe Flash",
"id": "AI066011",
"description": "Component: Adobe Flash",
"applies_to": [
],
"tags": [
"Development.Framework.Component.AdobeFlash"
],
"severity": "moderate",
"patterns": [
{
"pattern": ".swf",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Component: Active-X",
"id": "AI066012",
"description": "Component: Active-X",
"applies_to": [
"c",
"cpp",
"csharp",
"html"
],
"tags": [
"Development.Framework.Component.ActiveX"
],
"severity": "moderate",
"patterns": [
{
"pattern": "active-?x",
"type": "regex",
"scopes": [
"code",
"comment"
],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Component: COM",
"id": "AI066013",
"description": "Component: COM",
"applies_to": [
"c",
"cpp",
"csharp"
],
"tags": [
"Development.Framework.Component.ActiveX"
],
"severity": "moderate",
"patterns": [
{
"pattern": "CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER|CLSCTX_LOCAL_SERVER|CoCreateInstance",
"type": "regex-word",
"scopes": [
"code"
],
"confidence": "high"
}
]
},
{
"name": "Component: PDF",
"id": "AI066014",
"description": "Component: PDF",
"applies_to": [
"c",
"cpp",
"csharp"
],
"tags": [
"Development.Framework.Component.PDF"
],
"severity": "moderate",
"patterns": [
{
"pattern": "pdf",
"type": "string",
"scopes": [
"code"
],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,306 @@
[
{
"name": "Development Framework: Spring",
"id": "AI062010",
"description": "Development Framework: Spring",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Spring"
],
"severity": "moderate",
"patterns": [
{
"pattern": "springframework",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Hibernate",
"id": "AI062020",
"description": "Development Framework: Hibernate",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Hibernate"
],
"severity": "moderate",
"patterns": [
{
"pattern": "hibernate",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Blade",
"id": "AI062030",
"description": "Development Framework: Blade",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Blade"
],
"severity": "moderate",
"patterns": [
{
"pattern": "blade",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: DropWizard",
"id": "AI062040",
"description": "Development Framework: DropWizard",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.DropWizard"
],
"severity": "moderate",
"patterns": [
{
"pattern": "dropwizard",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: GWT",
"id": "AI062050",
"description": "Development Framework: GWT",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.GWT"
],
"severity": "moderate",
"patterns": [
{
"pattern": "gwt",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: JSF",
"id": "AI062060",
"description": "Development Framework: JSF",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.JSF"
],
"severity": "moderate",
"patterns": [
{
"pattern": "jsf",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: JHipster",
"id": "AI062070",
"description": "Development Framework: JHipster",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.JHipster"
],
"severity": "moderate",
"patterns": [
{
"pattern": "jhipster",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: MyBatis",
"id": "AI062080",
"description": "Development Framework: MyBatis",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.MyBatis"
],
"severity": "moderate",
"patterns": [
{
"pattern": "mybatis",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Play Framework",
"id": "AI062090",
"description": "Development Framework: Play Framework",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.PlayFramework"
],
"severity": "moderate",
"patterns": [
{
"pattern": "import play.",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: PrimeFaces",
"id": "AI062100",
"description": "Development Framework: PrimeFaces",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.PrimeFaces"
],
"severity": "moderate",
"patterns": [
{
"pattern": "primefaces",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Spark",
"id": "AI062110",
"description": "Development Framework: Spark",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Spark"
],
"severity": "moderate",
"patterns": [
{
"pattern": "import spark.",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Apache Struts",
"id": "AI062120",
"description": "Development Framework: Apache Struts",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.ApacheStruts"
],
"severity": "moderate",
"patterns": [
{
"pattern": "struts",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Apache Tapestry",
"id": "AI062130",
"description": "Development Framework: Apache Tapestry",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.ApacheTapestry"
],
"severity": "moderate",
"patterns": [
{
"pattern": "tapestry",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Vaadin",
"id": "AI062140",
"description": "Development Framework: Vaadin",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Vaadin"
],
"severity": "moderate",
"patterns": [
{
"pattern": "vaadin",
"type": "string",
"scopes": [ "code" ],
"modifiers": [],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Vert.x",
"id": "AI062150",
"description": "Development Framework: Vert.x",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Vertx"
],
"severity": "moderate",
"patterns": [
{
"pattern": "vert.x",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Wicket",
"id": "AI062160",
"description": "Development Framework: Wicket",
"applies_to": [ "java" ],
"tags": [
"Development.Framework.Wicket"
],
"severity": "moderate",
"patterns": [
{
"pattern": "wicket",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,238 @@
[
{
"name": "Development Framework: Angular.JS",
"id": "AI061510",
"description": "Development Framework: Angular.JS",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.AngularJS" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Angular",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Vue",
"id": "AI061511",
"description": "Development Framework: Vue",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Vue" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Vue",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: EmberJS",
"id": "AI061512",
"description": "Development Framework: EmberJS",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.EmberJS" ],
"severity": "moderate",
"patterns": [
{
"pattern": "Ember",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Backbone",
"id": "AI061513",
"description": "Development Framework: Backbone",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Backbone" ],
"severity": "moderate",
"patterns": [
{
"pattern": "backbone",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: jQuery",
"id": "AI061514",
"description": "Development Framework: jQuery",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.jQuery" ],
"severity": "moderate",
"patterns": [
{
"pattern": "jquery",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Redux",
"id": "AI061515",
"description": "Development Framework: Redux",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Redux" ],
"severity": "moderate",
"patterns": [
{
"pattern": "redux",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Redux-Saga",
"id": "AI061516",
"description": "Development Framework: Redux-Saga",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Redux-Saga" ],
"severity": "moderate",
"patterns": [
{
"pattern": "redux-saga",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: React",
"id": "AI061517",
"description": "Development Framework: React",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.React" ],
"severity": "moderate",
"patterns": [
{
"pattern": "react",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: RITEWay",
"id": "AI061518",
"description": "Development Framework: RITEWay",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.RITEWay" ],
"severity": "moderate",
"patterns": [
{
"pattern": "riteway",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Meteor",
"id": "AI061519",
"description": "Development Framework: Meteor",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Meteor" ],
"severity": "moderate",
"patterns": [
{
"pattern": "meteor",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Mithril",
"id": "AI061520",
"description": "Development Framework: Mithril",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Mithril" ],
"severity": "moderate",
"patterns": [
{
"pattern": "mithril",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Polymer",
"id": "AI061521",
"description": "Development Framework: Polymer",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Polymer" ],
"severity": "moderate",
"patterns": [
{
"pattern": "polymer",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Aurelia",
"id": "AI061522",
"description": "Development Framework: Aurelia",
"applies_to": [ "javascript" ],
"tags": [ "Development.Framework.Aurelia" ],
"severity": "moderate",
"patterns": [
{
"pattern": "aurelia",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Content Management Framework: Wordpress",
"id": "AI061522",
"description": "Development Framework: Wordpress",
"applies_to": [ "javascript", "html"],
"tags": [ "Development.Framework.CMS.Wordpress" ],
"severity": "moderate",
"patterns": [
{
"pattern": "wordpress",
"type": "string",
"scopes": [ "code", "comment"],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,128 @@
[
{
"name": "Framework: Logging (Log4J)",
"id": "AI068010",
"description": "Framework: Logging (Log4J)",
"applies_to": [
"java"
],
"tags": [
"Development.Framework.Logging.Log4j"
],
"severity": "moderate",
"patterns": [
{
"pattern": "log4j",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Framework: Logging (NLog)",
"id": "AI068011",
"description": "Framework: Logging (NLog)",
"applies_to": [
"csharp"
],
"tags": [
"Development.Framework.Logging.NLog"
],
"severity": "moderate",
"patterns": [
{
"pattern": "nlog",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Framework: Logging (Serilog)",
"id": "AI068012",
"description": "Framework: Logging (Serilog)",
"applies_to": [
"csharp"
],
"tags": [
"Development.Framework.Logging.Serilog"
],
"severity": "moderate",
"patterns": [
{
"pattern": "serilog",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Framework: Logging (log4net)",
"id": "AI068013",
"description": "Framework: Logging (log4net)",
"applies_to": [
"csharp"
],
"tags": [
"Development.Framework.Logging.Log4Net"
],
"severity": "moderate",
"patterns": [
{
"pattern": "log4net",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Framework: Logging (ulog)",
"id": "AI068014",
"description": "Framework: Logging (ulog)",
"applies_to": [
"csharp"
],
"tags": [
"Development.Framework.Logging.ULog"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ulog",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
},
{
"name": "Framework: Logging (Winston)",
"id": "AI068015",
"description": "Framework: Logging (Winston)",
"applies_to": [
"csharp"
],
"tags": [
"Development.Framework.Logging.Winston"
],
"severity": "moderate",
"patterns": [
{
"pattern": "winston",
"type": "string",
"scopes": [ "code" ],
"confidence": "high",
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,140 @@
[
{
"name": "Development Framework: .NET Core",
"id": "AI061211",
"description": "Development Framework: .NET Core",
"applies_to": [ "csharp" ],
"tags": [ "Development.Framework.Microsoft.NETCore" ],
"severity": "moderate",
"patterns": [
{
"pattern": "netcore",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Microsoft MVC",
"id": "AI061212",
"description": "Development Framework: Microsoft MVC",
"applies_to": [ "csharp" ],
"tags": [ "Development.Framework.Microsoft.MVC" ],
"severity": "moderate",
"patterns": [
{
"pattern": "mvc",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
},
{
"pattern": "aspnetcore",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Microsoft WCF",
"id": "AI061213",
"description": "Development Framework: Microsoft WCF",
"applies_to": [ "csharp" ],
"tags": [ "Development.Framework.Microsoft.WCF" ],
"severity": "moderate",
"patterns": [
{
"pattern": "wcf",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Microsoft MFC",
"id": "AI061214",
"description": "Development Framework: Microsoft MFC",
"applies_to": [ "c", "cpp", "csharp" ],
"tags": [ "Development.Framework.Microsoft.MFC" ],
"severity": "moderate",
"patterns": [
{
"pattern": "mfc",
"type": "regex-word",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Microsoft ADO",
"id": "AI061215",
"description": "Development Framework: Microsoft ADO",
"applies_to": [ "csharp" ],
"tags": [ "Development.Framework.Microsoft.ADO" ],
"severity": "moderate",
"patterns": [
{
"pattern": "ado",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ]
}
]
},
{
"name": "Development Framework: Microsoft Linq",
"id": "AI061216",
"description": "Development Framework: Microsoft Linq",
"applies_to": [ "csharp" ],
"tags": [ "Development.Framework.Microsoft.Linq" ],
"severity": "moderate",
"patterns": [
{
"pattern": "linq",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Windows SDK",
"id": "AI061217",
"description": "Development Framework: Windows SDK",
"applies_to": [ "c", "cpp", "csharp" ],
"tags": [ "Development.Framework.Microsoft.WindowsSDK" ],
"severity": "moderate",
"patterns": [
{
"pattern": "winsdk",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Microsoft Active Directory (ADAL)",
"id": "AI061218",
"description": "Development Framework: Microsoft Active Directory (ADAL)",
"tags": [
"Development.Framework.Authentication.Microsoft.ADAL"
],
"severity": "moderate",
"patterns": [
{
"pattern": "ADAL",
"type": "string",
"scopes": [ "code" ],
"_comment": ""
}
]
}
]

Просмотреть файл

@ -0,0 +1,266 @@
[
{
"name": "Development Framework: Django",
"id": "AI062210",
"description": "Development Framework: Django",
"applies_to": [ "python" ],
"tags": [
"Development.Framework.Django"
],
"severity": "moderate",
"patterns": [
{
"pattern": "django",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Pryamid",
"id": "AI062211",
"description": "Development Framework: Pryamid",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Pryamid" ],
"severity": "moderate",
"patterns": [
{
"pattern": "pyramid",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high",
}
]
},
{
"name": "Development Framework: Web2Py",
"id": "AI062212",
"description": "Development Framework: Web2Py",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Web2Py" ],
"severity": "moderate",
"patterns": [
{
"pattern": "web2py",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: CubicWeb",
"id": "AI062213",
"description": "Development Framework: CubicWeb",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.CubicWeb" ],
"severity": "moderate",
"patterns": [
{
"pattern": "cubicweb",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: OWL",
"id": "AI062214",
"description": "Development Framework: OWL",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.OWL" ],
"severity": "moderate",
"patterns": [
{
"pattern": "owlready",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: RDF",
"id": "AI062215",
"description": "Development Framework: RDF",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.RDF" ],
"severity": "moderate",
"patterns": [
{
"pattern": "rdflib",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: RQL",
"id": "AI062216",
"description": "Development Framework: RQL",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.RQL" ],
"severity": "moderate",
"patterns": [
{
"pattern": "rql",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Flask",
"id": "AI062217",
"description": "Development Framework: Flask",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Flask" ],
"severity": "moderate",
"patterns": [
{
"pattern": "flask",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Bottle",
"id": "AI062218",
"description": "Development Framework: Bottle",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Bottle" ],
"severity": "moderate",
"patterns": [
{
"pattern": "bottle",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: CherryPy",
"id": "AI062219",
"description": "Development Framework: CherryPy",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.CherryPy" ],
"severity": "moderate",
"patterns": [
{
"pattern": "cherrypy",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Sanic",
"id": "AI062220",
"description": "Development Framework: Sanic",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Sanic" ],
"severity": "moderate",
"patterns": [
{
"pattern": "sanic",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Tornado",
"id": "AI062221",
"description": "Development Framework: Tornado",
"applies_to": [ "python" ],
"tags": [ "Development.Framework.Tornado" ],
"severity": "moderate",
"patterns": [
{
"pattern": "tornado",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: TurboGears",
"id": "AI062222",
"description": "Development Framework: TurboGears",
"applies_to": [
"python",
"requirements.txt"
],
"tags": [ "Development.Framework.TurboGears" ],
"severity": "moderate",
"patterns": [
{
"pattern": "TGController|TurboGears2",
"type": "regex",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Giotto",
"id": "AI062223",
"description": "Development Framework: Giotto",
"applies_to": [
"python"
],
"tags": [ "Development.Framework.Giotto" ],
"severity": "moderate",
"patterns": [
{
"pattern": "giotto",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Pylons",
"id": "AI062224",
"description": "Development Framework: Pylons",
"applies_to": [
"python"
],
"tags": [ "Development.Framework.Pylons" ],
"severity": "moderate",
"patterns": [
{
"pattern": "pylons",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Просмотреть файл

@ -0,0 +1,36 @@
[
{
"name": "Development Framework: Grails",
"id": "AI061250",
"description": "Development Framework: Grails",
"applies_to": [ "groovy" ],
"tags": [ "Development.Framework.Grails" ],
"severity": "moderate",
"patterns": [
{
"pattern": "grails",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
},
{
"name": "Development Framework: Rails",
"id": "AI061251",
"description": "Development Framework: Rails",
"applies_to": [ "ruby" ],
"tags": [ "Development.Framework.Rails" ],
"severity": "moderate",
"patterns": [
{
"pattern": "rails",
"type": "string",
"scopes": [ "code" ],
"modifiers": [ "i" ],
"confidence": "high"
}
]
}
]

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше