Initial commit
This commit is contained in:
110
.gitignore
vendored
Normal file
110
.gitignore
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
|
||||
# Created by https://www.gitignore.io/api/gradle,intellij+all
|
||||
# Edit at https://www.gitignore.io/?templates=gradle,intellij+all
|
||||
|
||||
### Intellij+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij+all Patch ###
|
||||
# Ignores the whole .idea folder and all .iml files
|
||||
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
|
||||
|
||||
.idea/
|
||||
|
||||
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
|
||||
|
||||
*.iml
|
||||
modules.xml
|
||||
.idea/misc.xml
|
||||
*.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
.idea/sonarlint
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
|
||||
# gradle/wrapper/gradle-wrapper.properties
|
||||
|
||||
### Gradle Patch ###
|
||||
**/build/
|
||||
|
||||
# End of https://www.gitignore.io/api/gradle,intellij+all
|
||||
34
CHANGES
Normal file
34
CHANGES
Normal file
@@ -0,0 +1,34 @@
|
||||
Changelog
|
||||
|
||||
=========
|
||||
|
||||
Verson 1.1.3
|
||||
|
||||
- deps add gson
|
||||
- feature add Renderer
|
||||
- test add Unittests
|
||||
|
||||
Version 1.1.2
|
||||
|
||||
- feature default BUILD FAIL when found vulnerable
|
||||
|
||||
Version 1.1.1
|
||||
|
||||
- feature BUILD FAILED when found vulnerable && parameter support
|
||||
|
||||
Version 1.1.0
|
||||
|
||||
- feature add projectType param, support Maven & Android project
|
||||
|
||||
Version 1.0.2
|
||||
|
||||
- feature warning detail add title and cve
|
||||
|
||||
Version 1.0.1
|
||||
|
||||
- feature add onlyProvenance parameter
|
||||
- feature add http timeout
|
||||
|
||||
Version 1.0.0
|
||||
|
||||
- Init
|
||||
13
LICENSE
Normal file
13
LICENSE
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright 2020 momosecurity.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
73
README.md
Normal file
73
README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# MOSEC-GRADLE-PLUGIN
|
||||
|
||||
用于检测gradle项目的第三方依赖组件是否存在安全漏洞。
|
||||
|
||||
该项目灵感来自 [snyk-gradle-plugin](https://github.com/snyk/snyk-gradle-plugin.git) 。
|
||||
|
||||
## 版本支持
|
||||
|
||||
Gradle >= 3.0
|
||||
|
||||
## 安装
|
||||
|
||||
向顶层build.gradle中增加如下配置
|
||||
```groovy
|
||||
// file: build.gradle
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url "https://raw.github.com/momosecurity/mosec-gradle-plugin/master/mvn-repo/" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.immomo.momosec:mosec-gradle-plugin:1.1.3'
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'mosec'
|
||||
}
|
||||
```
|
||||
|
||||
## 使用
|
||||
|
||||
首先运行 [MOSEC-X-PLUGIN Backend](https://github.com/momosecurity/mosec-x-plugin-backend.git)
|
||||
|
||||
#### 命令行使用
|
||||
|
||||
```shell script
|
||||
# 对于所有projects,Maven项目
|
||||
> MOSEC_ENDPOINT=http://127.0.0.1:9000/api/plugin \
|
||||
./gradlew --no-parallel \
|
||||
mosec -PprojectType=Maven -PonlyProvenance=true
|
||||
|
||||
# 对于单个project (如 demo),Maven项目
|
||||
> MOSEC_ENDPOINT=http://127.0.0.1:9000/api/plugin \
|
||||
./gradlew --no-parallel \
|
||||
:demo:mosec -PprojectType=Maven -PonlyProvenance=true
|
||||
|
||||
# 对于 Android 项目,使用 confAttr 参数
|
||||
> MOSEC_ENDPOINT=http://127.0.0.1:9000/api/plugin \
|
||||
./gradlew --no-parallel \
|
||||
mosec -PprojectType=Android -PconfAttr=buildtype:release -PonlyProvenance=true
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
#### Intellij 远程调试 Gradle 插件
|
||||
|
||||
1.将mosec-gradle-plugin安装至本地仓库
|
||||
|
||||
2.git clone mosec-gradle-plugin
|
||||
|
||||
3.Intellij 中新建 Remote Configuration 并填入如下信息
|
||||
|
||||

|
||||
|
||||
4.在另一个gradle工程中执行如下命令
|
||||
|
||||
```shell script
|
||||
> ./gradlew --no-parallel --no-daemon mosec -Dorg.gradle.debug=true
|
||||
```
|
||||
|
||||
5.回到Intellij中,下断点,开始Debug
|
||||
43
build.gradle
Normal file
43
build.gradle
Normal file
@@ -0,0 +1,43 @@
|
||||
plugins {
|
||||
id 'groovy'
|
||||
id 'maven'
|
||||
}
|
||||
|
||||
group 'com.immomo.momosec'
|
||||
version '1.1.3'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile gradleApi()
|
||||
compile localGroovy()
|
||||
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
|
||||
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.10'
|
||||
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.28.2'
|
||||
testImplementation gradleTestKit()
|
||||
}
|
||||
|
||||
// local maven repo install
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
pom.groupId = "$project.group"
|
||||
pom.artifactId = "$project.name"
|
||||
pom.version = "$project.version"
|
||||
}
|
||||
}
|
||||
|
||||
// remote private maven repo deploy
|
||||
uploadArchives {
|
||||
repositories.mavenDeployer {
|
||||
repository(url: "file://mvn-repo")
|
||||
|
||||
pom.groupId = "$project.group"
|
||||
pom.artifactId = "$project.name"
|
||||
pom.version = "$project.version"
|
||||
}
|
||||
}
|
||||
2
gradle.properties
Normal file
2
gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
||||
NEXUS_USERNAME=
|
||||
NEXUS_PASSWORD=
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Tue May 26 14:27:38 CST 2020
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
172
gradlew
vendored
Executable file
172
gradlew
vendored
Executable file
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
84
gradlew.bat
vendored
Normal file
84
gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
63a54e2e32ae94d5efdd5d474a47fae5
|
||||
@@ -0,0 +1 @@
|
||||
f28f856789fbe4385c027d4f26ed8ab8c7e746f0
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.immomo.momosec</groupId>
|
||||
<artifactId>mosec-gradle-plugin</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.10</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>2.28.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
e092d0c7163e87bb55fabe6ae4fe2bf0
|
||||
@@ -0,0 +1 @@
|
||||
6fbbb8db08cec3acd0ba30c14503e01b59f184bb
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<groupId>com.immomo.momosec</groupId>
|
||||
<artifactId>mosec-gradle-plugin</artifactId>
|
||||
<versioning>
|
||||
<release>1.1.3</release>
|
||||
<versions>
|
||||
<version>1.1.3</version>
|
||||
</versions>
|
||||
<lastUpdated>20200728045957</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
@@ -0,0 +1 @@
|
||||
cee7d6bf5c0a3d11b4d432fcacf1b8ab
|
||||
@@ -0,0 +1 @@
|
||||
64fb6c894314270126bbdcc2975fcfd86e194878
|
||||
2
settings.gradle
Normal file
2
settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
||||
rootProject.name = 'mosec-gradle-plugin'
|
||||
|
||||
126
src/main/groovy/com/immomo/momosec/gradle/plugins/Mosec.groovy
Normal file
126
src/main/groovy/com/immomo/momosec/gradle/plugins/Mosec.groovy
Normal file
@@ -0,0 +1,126 @@
|
||||
package com.immomo.momosec.gradle.plugins
|
||||
|
||||
import com.immomo.momosec.gradle.plugins.exceptions.NetworkErrorException
|
||||
import groovy.json.JsonOutput
|
||||
import org.apache.http.HttpEntity
|
||||
import org.apache.http.HttpResponse
|
||||
import org.apache.http.client.HttpClient
|
||||
import org.apache.http.client.methods.HttpPost
|
||||
import org.apache.http.entity.StringEntity
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
class Mosec implements Plugin<Project> {
|
||||
|
||||
/**
|
||||
* https://developer.android.com/studio/build/dependencies#variant_aware
|
||||
* -PconfAttr=buildtype:debug,usage:java-runtime
|
||||
*/
|
||||
private List confAttrSpec = null
|
||||
|
||||
/**
|
||||
* 过滤configuration
|
||||
* -Pconfiguration=confNameRegex or -Pconfiguration=spcificConfName
|
||||
*/
|
||||
private String confNameFilter = ".*"
|
||||
|
||||
/**
|
||||
* 威胁等级 [High|Medium|Low]
|
||||
*/
|
||||
private String severityLevel = 'High'
|
||||
|
||||
/**
|
||||
* 仅检查直接依赖
|
||||
*/
|
||||
private Boolean onlyProvenance = false
|
||||
|
||||
/**
|
||||
* 发现漏洞即编译失败
|
||||
*/
|
||||
private Boolean failOnVuln = true
|
||||
|
||||
/**
|
||||
* 项目类型 [Maven|Android]
|
||||
* 决定了使用的检索漏洞库
|
||||
*/
|
||||
private String projectType = 'Android'
|
||||
private def allowProjectType = ['Maven', 'Android']
|
||||
|
||||
/**
|
||||
* 上报API
|
||||
*/
|
||||
private String endpoint
|
||||
|
||||
|
||||
@Override
|
||||
void apply(Project project) {
|
||||
project.task('mosec').doLast {
|
||||
|
||||
if (project.hasProperty('projectType')) {
|
||||
projectType = project.property('projectType').toString()
|
||||
|
||||
if (!allowProjectType.contains(projectType)) {
|
||||
throw new Exception(Constants.ERROR_ON_PROJECT_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
if (project.hasProperty('endpoint')) {
|
||||
endpoint = project.property('endpoint').toString()
|
||||
}
|
||||
|
||||
def endpoint_env = System.getenv(Constants.MOSEC_ENDPOINT_ENV)
|
||||
if (endpoint_env != null) {
|
||||
endpoint = endpoint_env
|
||||
}
|
||||
|
||||
if (endpoint == null) {
|
||||
throw new RuntimeException(Constants.ERROR_ON_NULL_ENDPOINT)
|
||||
}
|
||||
|
||||
if (project.hasProperty('confAttr')) {
|
||||
confAttrSpec = project.property('confAttr').toString().toLowerCase().split(',').collect { it.split(':') }
|
||||
}
|
||||
|
||||
if (project.hasProperty('configuration')) {
|
||||
confNameFilter = String.format("%s", project.property('configuration').toString().toLowerCase())
|
||||
}
|
||||
|
||||
if (project.hasProperty('severityLevel')) {
|
||||
severityLevel = project.property('severityLevel')
|
||||
}
|
||||
|
||||
if (project.hasProperty('onlyProvenance')) {
|
||||
onlyProvenance = new Boolean(project.property('onlyProvenance').toString())
|
||||
}
|
||||
|
||||
if (project.hasProperty('failOnVuln')) {
|
||||
failOnVuln = new Boolean(project.property('failOnVuln').toString())
|
||||
}
|
||||
|
||||
ProjectDependencyCollector collector = new ProjectDependencyCollector(project, confAttrSpec, confNameFilter, onlyProvenance)
|
||||
Map depsTree = collector.collect()
|
||||
|
||||
if (depsTree == null) { return }
|
||||
|
||||
depsTree['type'] = projectType
|
||||
depsTree['language'] = Constants.PROJECT_LANGUAGE
|
||||
depsTree['severityLevel'] = severityLevel
|
||||
|
||||
HttpPost request = new HttpPost(endpoint)
|
||||
request.addHeader("Content-Type", Constants.CONTENT_TYPE_JSON)
|
||||
HttpEntity entity = new StringEntity(JsonOutput.toJson(depsTree))
|
||||
request.setEntity(entity)
|
||||
|
||||
HttpClientHelper httpClientHelper = new HttpClientHelper()
|
||||
HttpClient client = httpClientHelper.buildHttpClient()
|
||||
HttpResponse response = client.execute(request)
|
||||
|
||||
if (response.getStatusLine().getStatusCode() >= 400) {
|
||||
throw new NetworkErrorException(response.getStatusLine().getReasonPhrase())
|
||||
}
|
||||
|
||||
Renderer renderer = new Renderer(project.logger, failOnVuln)
|
||||
renderer.renderResponse(response.getEntity().getContent())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.immomo.momosec.gradle.plugins
|
||||
|
||||
import groovy.json.JsonOutput
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ResolvedDependency
|
||||
import org.gradle.api.attributes.Attribute
|
||||
|
||||
class ProjectDependencyCollector {
|
||||
|
||||
private final Project project
|
||||
private final List confAttrSpec
|
||||
private final String confNameFilter
|
||||
private final Boolean onlyProvenance
|
||||
|
||||
private final MosecLogHelper logHelper = new MosecLogHelper()
|
||||
|
||||
private final def mosecMergedDepsConf = 'mosecMergedDepsConf'
|
||||
|
||||
ProjectDependencyCollector(Project project, List confAttrSpec, String confNameFilter, Boolean onlyProvenance) {
|
||||
this.project = project
|
||||
this.confAttrSpec = confAttrSpec
|
||||
this.confNameFilter = confNameFilter
|
||||
this.onlyProvenance = onlyProvenance
|
||||
}
|
||||
|
||||
def collect() {
|
||||
def projName = project.name
|
||||
def projVersion = project.version
|
||||
def logger = project.logger
|
||||
|
||||
logger.info logHelper.strongInfo('MOSEC: ') + 'task is executing via doLast on ' + projName
|
||||
|
||||
def depsTree = [
|
||||
'name': projName,
|
||||
'version': projVersion,
|
||||
'from': [projName + '@' + projVersion],
|
||||
'dependencies': [:],
|
||||
]
|
||||
|
||||
Map<Attribute<?>, Set<?>> allConfigurationAttributes = new HashMap<>()
|
||||
Map<String, Set<String>> attributesAsStrings = new HashMap<>()
|
||||
project.allprojects.each { proj ->
|
||||
proj.configurations.findAll({
|
||||
it.name != mosecMergedDepsConf &&
|
||||
it.name =~ confNameFilter &&
|
||||
matchesAttributeFilter.call(it)
|
||||
}).each { conf ->
|
||||
if (!conf.hasProperty('attributes')) {
|
||||
// Gradle before version 3 does not support attributes
|
||||
return
|
||||
}
|
||||
def attrs = conf.attributes
|
||||
attrs.keySet().each({ attr ->
|
||||
def value = attrs.getAttribute(attr as Attribute<Object>)
|
||||
if (!allConfigurationAttributes.containsKey(attr)) {
|
||||
allConfigurationAttributes[attr] = new HashSet()
|
||||
attributesAsStrings[attr.name] = new HashSet()
|
||||
}
|
||||
allConfigurationAttributes[attr].add(value)
|
||||
attributesAsStrings[attr.name].add(value.toString())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug 'MOSEC: JSON Attr ' + JsonOutput.toJson(attributesAsStrings)
|
||||
|
||||
def mosecConf = null
|
||||
def mergeableConfs = project.configurations.findAll({it.name != mosecMergedDepsConf && it.name =~ confNameFilter})
|
||||
|
||||
if (confAttrSpec != null) {
|
||||
mergeableConfs = mergeableConfs.findAll(matchesAttributeFilter)
|
||||
}
|
||||
|
||||
if (mergeableConfs.size() == 0 && project.configurations.size() > 0) {
|
||||
throw new RuntimeException('MOSEC: Matching configurations not found: ' + confNameFilter +
|
||||
', availabie configurations for project ' + project + ': ' +
|
||||
project.configurations.collect({ it.name }))
|
||||
} else if (mergeableConfs.size() == 1) {
|
||||
mosecConf = mergeableConfs.first()
|
||||
} else if (mergeableConfs.size() > 1) {
|
||||
logger.info logHelper.strongInfo('MOSEC: ') + 'constructing merged configuration from ' + mergeableConfs.collect({conf -> conf.name})
|
||||
mosecConf = project.configurations.create(mosecMergedDepsConf)
|
||||
|
||||
mergeableConfs.each { mosecConf.extendsFrom(it) }
|
||||
|
||||
if (mosecConf.hasProperty('attributes')) {
|
||||
allConfigurationAttributes.each({ attr, valueSet ->
|
||||
if (valueSet.size() == 1) {
|
||||
mosecConf.attributes.attribute(attr, valueSet.head())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (mosecConf != null) {
|
||||
logger.info logHelper.strongInfo('MOSEC: ') + 'resolving configuration ' + mosecConf.name
|
||||
|
||||
Set<ResolvedDependency> gradleDeps = mosecConf.resolvedConfiguration.firstLevelModuleDependencies
|
||||
|
||||
logger.debug 'MOSEC: converting dependency graph to DepTree'
|
||||
|
||||
ArrayList<String> from = new ArrayList<String>(){{ add(projName + '@' + projVersion) }}
|
||||
depsTree['dependencies'] = depsToDict.call(gradleDeps, from, onlyProvenance)
|
||||
simplifyDeps.call(depsTree)
|
||||
|
||||
logger.debug 'MOSEC: depsTree ' + JsonOutput.prettyPrint(JsonOutput.toJson(depsTree))
|
||||
return depsTree
|
||||
} else {
|
||||
logger.error('MOSEC: no configuration found.')
|
||||
}
|
||||
}
|
||||
|
||||
def depsToDict = { Set<ResolvedDependency> deps, ArrayList<String> currentChain, Boolean onlyProvenance ->
|
||||
def res = [:]
|
||||
deps.each { d ->
|
||||
def depName = d.moduleGroup + ':' + d.moduleName
|
||||
def depNameVersion = depName + '@' + d.moduleVersion
|
||||
|
||||
if (!currentChain.contains(depNameVersion)) {
|
||||
currentChain.add(depNameVersion)
|
||||
def row = ['name': depName, 'version': d.moduleVersion, 'from': currentChain.clone()]
|
||||
def subDeps = [:]
|
||||
if (!onlyProvenance) {
|
||||
subDeps = depsToDict.call(d.children, currentChain, onlyProvenance)
|
||||
}
|
||||
currentChain.remove(depNameVersion)
|
||||
if (subDeps.size() > 0) {
|
||||
row['dependencies'] = subDeps
|
||||
} else {
|
||||
row['dependencies'] = [:]
|
||||
}
|
||||
res[depName] = row
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
def simplifyDeps = { deps ->
|
||||
def q = [] as Queue
|
||||
def s = new HashSet<String>()
|
||||
|
||||
q.add(deps)
|
||||
|
||||
def elem = [:]
|
||||
while ( (elem = q.poll()) != null) {
|
||||
def removeNames = []
|
||||
elem['dependencies'].each { name, d ->
|
||||
def depFull = d['name'] + '@' + d['version']
|
||||
if (s.contains(depFull)) {
|
||||
removeNames.add(name)
|
||||
return
|
||||
}
|
||||
s.add(depFull as String)
|
||||
q.add(d)
|
||||
}
|
||||
|
||||
removeNames.each {name ->
|
||||
elem['dependencies'].remove(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def matchesAttributeFilter = {Configuration conf ->
|
||||
if (!conf.hasProperty('attributes')) {
|
||||
// Gradle before version 3 does not support attributes
|
||||
return true
|
||||
}
|
||||
def matches = true
|
||||
def attrs = conf.attributes
|
||||
attrs.keySet().each({ attr ->
|
||||
def attrValueAsString = attrs.getAttribute(attr as Attribute<Object>).toString().toLowerCase()
|
||||
for(String[] keyValueFilter : confAttrSpec) {
|
||||
if (attr.name.toLowerCase().contains(keyValueFilter[0])
|
||||
&& attrValueAsString != keyValueFilter[1]) {
|
||||
matches = false
|
||||
}
|
||||
}
|
||||
})
|
||||
return matches
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.immomo.momosec.gradle.plugins;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String ERROR_ON_PROJECT_TYPE = "Project type not allow. Use [Maven | Android].";
|
||||
|
||||
public static final String ERROR_ON_VULNERABLE = "Dependency Vulnerable Found!";
|
||||
|
||||
public static final String ERROR_ON_API = "API return data format error.";
|
||||
|
||||
public static final String ERROR_ON_NULL_ENDPOINT = "API endpoint not setting. Setting by MOSEC_ENDPOINT env.";
|
||||
|
||||
public static final String CONTENT_TYPE_JSON = "application/json";
|
||||
|
||||
public static final String PROJECT_LANGUAGE = "java";
|
||||
|
||||
public static final String MOSEC_ENDPOINT_ENV = "MOSEC_ENDPOINT";
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.immomo.momosec.gradle.plugins;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.LaxRedirectStrategy;
|
||||
|
||||
public class HttpClientHelper {
|
||||
|
||||
private final int timeout = 15 * 1000;
|
||||
|
||||
public HttpClient buildHttpClient() {
|
||||
RequestConfig config = RequestConfig.custom()
|
||||
.setConnectTimeout(timeout)
|
||||
.setConnectionRequestTimeout(timeout)
|
||||
.setSocketTimeout(timeout)
|
||||
.build();
|
||||
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create()
|
||||
.setDefaultRequestConfig(config)
|
||||
.setRedirectStrategy(new LaxRedirectStrategy())
|
||||
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE);
|
||||
return httpClientBuilder.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.immomo.momosec.gradle.plugins;
|
||||
|
||||
public class MosecLogHelper {
|
||||
private static final String YELLOW = "\033[1;33m";
|
||||
private static final String LIGHT_RED = "\033[1;31m";
|
||||
private static final String LIGHT_GREEN = "\033[1;32m";
|
||||
|
||||
private static final String CANCEL_COLOR = "\033[0m";
|
||||
|
||||
public String strongWarning(String content) {
|
||||
return YELLOW + content + CANCEL_COLOR;
|
||||
}
|
||||
|
||||
public String strongError(String content) {
|
||||
return LIGHT_RED + content + CANCEL_COLOR;
|
||||
}
|
||||
|
||||
public String strongInfo(String content) {
|
||||
return LIGHT_GREEN + content + CANCEL_COLOR;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.immomo.momosec.gradle.plugins;
|
||||
|
||||
import com.immomo.momosec.gradle.plugins.exceptions.FoundVulnerableException;
|
||||
import com.immomo.momosec.gradle.plugins.exceptions.NetworkErrorException;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
public class Renderer {
|
||||
|
||||
private final MosecLogHelper logHelper = new MosecLogHelper();
|
||||
|
||||
private final Logger log;
|
||||
private final Boolean failOnVuln;
|
||||
|
||||
public Renderer(Logger log, Boolean failOnVuln) {
|
||||
this.log = log;
|
||||
this.failOnVuln = failOnVuln;
|
||||
}
|
||||
|
||||
public void renderResponse(InputStream in) {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject responseJson;
|
||||
try {
|
||||
responseJson = parser.parse(new BufferedReader(new InputStreamReader(in))).getAsJsonObject();
|
||||
} catch (Exception e) {
|
||||
throw new NetworkErrorException(Constants.ERROR_ON_API);
|
||||
}
|
||||
|
||||
if(responseJson.get("ok") != null && responseJson.get("ok").getAsBoolean()) {
|
||||
String ok = "✓ Tested %s dependencies, no vulnerable found.";
|
||||
getLog().warn(logHelper.strongInfo(String.format(ok, responseJson.get("dependencyCount").getAsString())));
|
||||
} else if (responseJson.get("vulnerabilities") != null) {
|
||||
JsonArray vulns = (JsonArray) responseJson.get("vulnerabilities");
|
||||
|
||||
for (JsonElement vuln : vulns) {
|
||||
printSingleVuln(vuln.getAsJsonObject());
|
||||
}
|
||||
|
||||
String fail = "Tested %s dependencies, found %d vulnerable pathes.";
|
||||
getLog().warn(logHelper.strongWarning(String.format(fail, responseJson.get("dependencyCount").getAsString(), vulns.size())));
|
||||
if (Boolean.TRUE.equals(failOnVuln)) {
|
||||
throw new FoundVulnerableException(Constants.ERROR_ON_VULNERABLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void printSingleVuln(JsonObject vuln) {
|
||||
String vulnWarn = "✗ %s severity (%s - %s) found on %s@%s";
|
||||
getLog().warn(logHelper.strongError(String.format(vulnWarn,
|
||||
vuln.get("severity").getAsString(),
|
||||
vuln.get("title").getAsString(),
|
||||
vuln.get("cve").getAsString(),
|
||||
vuln.get("packageName").getAsString(),
|
||||
vuln.get("version").getAsString()
|
||||
)));
|
||||
if(vuln.get("from") != null) {
|
||||
JsonArray fromArr = vuln.get("from").getAsJsonArray();
|
||||
StringBuilder fromStrb = new StringBuilder();
|
||||
for(int i = 0; i < fromArr.size(); i++) {
|
||||
fromStrb.append(fromArr.get(i).getAsString());
|
||||
fromStrb.append(" > ");
|
||||
}
|
||||
getLog().warn(String.format("- Path: %s" ,fromStrb.substring(0, fromStrb.length() - 3)));
|
||||
}
|
||||
if (vuln.get("target_version").getAsJsonArray().size() >= 0) {
|
||||
getLog().warn(logHelper.strongInfo(String.format("! Fix version %s", vuln.get("target_version").getAsJsonArray())));
|
||||
}
|
||||
getLog().warn("");
|
||||
}
|
||||
|
||||
private Logger getLog() {
|
||||
return log;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.immomo.momosec.gradle.plugins.exceptions;
|
||||
|
||||
public class FoundVulnerableException extends RuntimeException {
|
||||
|
||||
public FoundVulnerableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.immomo.momosec.gradle.plugins.exceptions;
|
||||
|
||||
public class NetworkErrorException extends RuntimeException {
|
||||
|
||||
public NetworkErrorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
implementation-class=com.immomo.momosec.gradle.plugins.Mosec
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.immomo.momosec.gradle.plugins
|
||||
|
||||
import com.immomo.momosec.gradle.plugins.stubs.MyConfiguration
|
||||
import com.immomo.momosec.gradle.plugins.stubs.MyResolvedDependency
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.ConfigurationContainer
|
||||
import org.gradle.api.artifacts.ResolvedConfiguration
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
|
||||
import static org.mockito.Mockito.*
|
||||
|
||||
class TestProjectDependencyCollector {
|
||||
|
||||
private final Project project = mock(Project.class)
|
||||
|
||||
@Test
|
||||
void collectTest() {
|
||||
def spyLog = spy(mock(Logger.class))
|
||||
def confNameFilter = /.*/
|
||||
def spyCollector = spy(new ProjectDependencyCollector(project, null, confNameFilter, true))
|
||||
def confContainer = mock(ConfigurationContainer.class)
|
||||
|
||||
// for spy log
|
||||
doNothing().when(spyLog).info(anyString())
|
||||
doNothing().when(spyLog).debug(anyString())
|
||||
doNothing().when(spyLog).warn(anyString())
|
||||
doNothing().when(spyLog).error(anyString())
|
||||
|
||||
// for project.configuration.findAll
|
||||
def spyConf = spy(new MyConfiguration())
|
||||
doReturn([spyConf].toSet()).when(confContainer).findAll(any(Closure.class))
|
||||
|
||||
// for mosecConf.resolvedConfiguration.firstLevelModuleDependencies
|
||||
def resolvedConf = mock(ResolvedConfiguration.class)
|
||||
doReturn(resolvedConf).when(spyConf).getResolvedConfiguration()
|
||||
|
||||
def parent = new MyResolvedDependency('com.study.parent', 'parent', '1.0.0')
|
||||
parent.setChildren(new MyResolvedDependency('com.study.child', 'child', '1.0.0'))
|
||||
doReturn(parent.getChildren()).when(resolvedConf).getFirstLevelModuleDependencies()
|
||||
|
||||
// for spy project
|
||||
doReturn('com.study.parent:parent').when(project).getName()
|
||||
doReturn('1.0.0').when(project).getVersion()
|
||||
doReturn(spyLog).when(project).getLogger()
|
||||
doReturn([project].toSet()).when(project).getAllprojects()
|
||||
doReturn(confContainer).when(project).getConfigurations()
|
||||
|
||||
def depsTree = spyCollector.collect()
|
||||
|
||||
verify(spyCollector, times(1)).collect()
|
||||
verify(project, times(1)).getAllprojects()
|
||||
verify(project, atLeastOnce()).getConfigurations()
|
||||
verify(spyConf, times(1)).getResolvedConfiguration()
|
||||
verify(resolvedConf, times(1)).getFirstLevelModuleDependencies()
|
||||
Assert.assertEquals('com.study.parent:parent', depsTree.get('name'))
|
||||
Assert.assertEquals('1.0.0', depsTree.get('version'))
|
||||
Assert.assertEquals(2,
|
||||
(((depsTree.get('dependencies') as Map)
|
||||
.get('com.study.child:child') as Map)
|
||||
.get('from') as List)
|
||||
.size())
|
||||
}
|
||||
|
||||
@Test
|
||||
void depsToDictTest() {
|
||||
def parent = new MyResolvedDependency('com.study.parent', 'parent', '1.0.0')
|
||||
def child = new MyResolvedDependency('com.study.child', 'child', '1.0.0')
|
||||
def child_child = new MyResolvedDependency('com.study.child_child', 'child_child', '1.0.0')
|
||||
|
||||
parent.setChildren(child)
|
||||
child.setChildren(child_child)
|
||||
|
||||
child_child.setParent(child)
|
||||
child.setParent(parent)
|
||||
|
||||
def collector = new ProjectDependencyCollector(project, null, null, true)
|
||||
def chain = ['com.study.parent:parent@1.0.0']
|
||||
|
||||
def childOnlyProvenanceDepsTree = collector.depsToDict.call(parent.getChildren(), chain as ArrayList, true)
|
||||
def expectChildOnlyProvenanceTree = [
|
||||
'com.study.child:child': [
|
||||
'name': 'com.study.child:child',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child:child@1.0.0'],
|
||||
'dependencies': [:]
|
||||
]
|
||||
]
|
||||
Assert.assertEquals(expectChildOnlyProvenanceTree, childOnlyProvenanceDepsTree)
|
||||
|
||||
def childNotOnlyProvenanceDepsTree = collector.depsToDict.call(parent.getChildren(), chain as ArrayList, false)
|
||||
def expectChildNotOnlyProvenanceTree = [
|
||||
'com.study.child:child': [
|
||||
'name': 'com.study.child:child',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child:child@1.0.0'],
|
||||
'dependencies': [
|
||||
'com.study.child_child:child_child': [
|
||||
'name': 'com.study.child_child:child_child',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child:child@1.0.0', 'com.study.child_child:child_child@1.0.0'],
|
||||
'dependencies': [:]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
Assert.assertEquals(expectChildNotOnlyProvenanceTree, childNotOnlyProvenanceDepsTree)
|
||||
}
|
||||
|
||||
@Test
|
||||
void simplifyDepsTest() {
|
||||
def depsTree = [
|
||||
'name': 'com.study.parent:parent',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0'],
|
||||
'dependencies': [
|
||||
'com.study.child1:child1': [
|
||||
'name': 'com.study.child1:child1',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child1:child1@1.0.0'],
|
||||
'dependencies': [:]
|
||||
],
|
||||
'com.study.child2:child2': [
|
||||
'name': 'com.study.child2:child2',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child2:child2@1.0.0'],
|
||||
'dependencies': [
|
||||
'com.study.child1:child1': [
|
||||
'name': 'com.study.child1:child1',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child2:child2@1.0.0', 'com.study.child1:child1@1.0.0'],
|
||||
'dependencies': [:]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
def expectDepsTree = [
|
||||
'name': 'com.study.parent:parent',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0'],
|
||||
'dependencies': [
|
||||
'com.study.child1:child1': [
|
||||
'name': 'com.study.child1:child1',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child1:child1@1.0.0'],
|
||||
'dependencies': [:]
|
||||
],
|
||||
'com.study.child2:child2': [
|
||||
'name': 'com.study.child2:child2',
|
||||
'version': '1.0.0',
|
||||
'from': ['com.study.parent:parent@1.0.0', 'com.study.child2:child2@1.0.0'],
|
||||
'dependencies': [:]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
def collector = new ProjectDependencyCollector(project, null, null, true)
|
||||
collector.simplifyDeps.call(depsTree)
|
||||
|
||||
Assert.assertEquals(expectDepsTree, depsTree)
|
||||
}
|
||||
|
||||
@Test
|
||||
void matchesAttributeFilter() {
|
||||
def match
|
||||
def conf = new MyConfiguration() // has usage:java-runtime attributes
|
||||
|
||||
String matchAttrSpec = "usage:java-runtime"
|
||||
def collector = new ProjectDependencyCollector(project, matchAttrSpec.split(',').collect{ it.split(':') }, null, true)
|
||||
match = collector.matchesAttributeFilter.call(conf)
|
||||
Assert.assertTrue(match)
|
||||
|
||||
String notMatchAttrSpec = "usage:imnotexist"
|
||||
def collectorWithWrongAttrSpec = new ProjectDependencyCollector(project, notMatchAttrSpec.split(',').collect{ it.split(':') }, null, true)
|
||||
match = collectorWithWrongAttrSpec.matchesAttributeFilter.call(conf)
|
||||
Assert.assertFalse(match)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
package com.immomo.momosec.gradle.plugins.stubs;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.artifacts.*;
|
||||
import org.gradle.api.attributes.Attribute;
|
||||
import org.gradle.api.attributes.AttributeContainer;
|
||||
import org.gradle.api.attributes.Usage;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.internal.attributes.DefaultImmutableAttributesFactory;
|
||||
import org.gradle.api.specs.Spec;
|
||||
import org.gradle.api.tasks.TaskDependency;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MyConfiguration implements Configuration {
|
||||
@Override
|
||||
public ResolutionStrategy getResolutionStrategy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolutionStrategy(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration resolutionStrategy(Action<? super ResolutionStrategy> action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration setVisible(boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Configuration> getExtendsFrom() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration setExtendsFrom(Iterable<Configuration> iterable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration extendsFrom(Configuration... configurations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTransitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration setTransitive(boolean b) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration setDescription(@Nullable String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Configuration> getHierarchy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> resolve() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> files(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> files(Spec<? super Dependency> spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> files(Dependency... dependencies) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection fileCollection(Spec<? super Dependency> spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection fileCollection(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection fileCollection(Dependency... dependencies) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedConfiguration getResolvedConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUploadTaskName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskDependency getBuildDependencies() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskDependency getTaskDependencyFromProjectDependency(boolean b, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencySet getDependencies() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencySet getAllDependencies() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyConstraintSet getDependencyConstraints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyConstraintSet getAllDependencyConstraints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublishArtifactSet getArtifacts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PublishArtifactSet getAllArtifacts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ExcludeRule> getExcludeRules() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration exclude(Map<String, String> map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration defaultDependencies(Action<? super DependencySet> action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration withDependencies(Action<? super DependencySet> action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Configuration> getAll() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvableDependencies getIncoming() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationPublications getOutgoing() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoing(Action<? super ConfigurationPublications> action) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copy() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copyRecursive() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copy(Spec<? super Dependency> spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copyRecursive(Spec<? super Dependency> spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copy(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration copyRecursive(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCanBeConsumed(boolean b) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanBeConsumed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCanBeResolved(boolean b) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanBeResolved() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration attributes(Action<? super AttributeContainer> action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeContainer getAttributes() {
|
||||
DefaultImmutableAttributesFactory attributesFactory = new DefaultImmutableAttributesFactory(null, null);
|
||||
|
||||
AttributeContainer attrContainer = attributesFactory.mutable();
|
||||
attrContainer.attribute(Attribute.of("usage", String.class), Usage.JAVA_RUNTIME);
|
||||
return attrContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getSingleFile() throws IllegalStateException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<File> getFiles() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(File file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAsPath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection plus(FileCollection fileCollection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection minus(FileCollection fileCollection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection filter(Closure closure) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileCollection filter(Spec<? super File> spec) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTree getAsFileTree() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToAntBuilder(Object o, String s, AntType antType) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addToAntBuilder(Object o, String s) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<File> iterator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.immomo.momosec.gradle.plugins.stubs;
|
||||
|
||||
import org.gradle.api.artifacts.ResolvedArtifact;
|
||||
import org.gradle.api.artifacts.ResolvedDependency;
|
||||
import org.gradle.api.artifacts.ResolvedModuleVersion;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class MyResolvedDependency implements ResolvedDependency {
|
||||
private String group;
|
||||
private String name;
|
||||
private String version;
|
||||
private Set<ResolvedDependency> children = new HashSet<>();
|
||||
private Set<ResolvedDependency> parent = new HashSet<>();
|
||||
|
||||
public MyResolvedDependency(String group, String name, String version) {
|
||||
this.group = group;
|
||||
this.name = name;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getModuleVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfiguration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResolvedModuleVersion getModule() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedDependency> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public void setChildren(ResolvedDependency dependency) {
|
||||
this.children.add(dependency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedDependency> getParents() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public void setParent(ResolvedDependency dependency) {
|
||||
this.parent.add(dependency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedArtifact> getModuleArtifacts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedArtifact> getAllModuleArtifacts() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedArtifact> getParentArtifacts(ResolvedDependency resolvedDependency) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedArtifact> getArtifacts(ResolvedDependency resolvedDependency) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResolvedArtifact> getAllArtifacts(ResolvedDependency resolvedDependency) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.immomo.momosec.gradle.plugins;
|
||||
|
||||
import com.immomo.momosec.gradle.plugins.exceptions.FoundVulnerableException;
|
||||
import com.immomo.momosec.gradle.plugins.exceptions.NetworkErrorException;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.junit.*;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
public class TestRenderer {
|
||||
|
||||
@Rule
|
||||
public ExpectedException exceptionRule = ExpectedException.none();
|
||||
|
||||
private final Logger log = mock(Logger.class);
|
||||
private final Logger spyLog = Mockito.spy(log);
|
||||
private final MosecLogHelper logHelper = new MosecLogHelper();
|
||||
|
||||
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
|
||||
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
|
||||
private final PrintStream originalOut = System.out;
|
||||
private final PrintStream originalErr = System.err;
|
||||
|
||||
private final String no_vulnerable_response =
|
||||
"{" +
|
||||
" \"ok\": true," +
|
||||
" \"dependencyCount\": 3" +
|
||||
"}";
|
||||
|
||||
private final String vulnerable_response =
|
||||
"{" +
|
||||
" \"ok\": false," +
|
||||
" \"dependencyCount\": 3," +
|
||||
" \"vulnerabilities\": [{" +
|
||||
" \"severity\": \"High\"," +
|
||||
" \"title\": \"Fake Vulnerable\"," +
|
||||
" \"cve\": \"CVE-0001-0001\"," +
|
||||
" \"packageName\": \"com.study.foo:bar\"," +
|
||||
" \"version\": \"1.0.0\"," +
|
||||
" \"target_version\": [\"1.1\"]" +
|
||||
" }]" +
|
||||
"}";
|
||||
|
||||
@Before
|
||||
public void setUpStreams() {
|
||||
System.setOut(new PrintStream(outContent));
|
||||
System.setErr(new PrintStream(errContent));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void mockLog() {
|
||||
doAnswer(invocation -> {
|
||||
System.out.println((String)invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(spyLog).info(anyString());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
System.out.println((String)invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(spyLog).debug(anyString());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
System.out.println((String)invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(spyLog).warn(anyString());
|
||||
|
||||
doAnswer(invocation -> {
|
||||
System.out.println((String)invocation.getArgument(0));
|
||||
return null;
|
||||
}).when(spyLog).error(anyString());
|
||||
}
|
||||
|
||||
@After
|
||||
public void restoreStreams() {
|
||||
System.setOut(originalOut);
|
||||
System.setErr(originalErr);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderResponseTest_ErrorJson() throws Exception {
|
||||
exceptionRule.expect(NetworkErrorException.class);
|
||||
exceptionRule.expectMessage(Constants.ERROR_ON_API);
|
||||
|
||||
Renderer renderer = new Renderer(log, true);
|
||||
renderer.renderResponse(new ByteArrayInputStream("_".getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderResponseTest_NotFoundVuln() throws Exception {
|
||||
Renderer renderer = new Renderer(spyLog, true);
|
||||
renderer.renderResponse(new ByteArrayInputStream(no_vulnerable_response.getBytes()));
|
||||
|
||||
String expect = logHelper.strongInfo("✓ Tested 3 dependencies, no vulnerable found.") + "\n";
|
||||
Assert.assertEquals(expect, outContent.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderResponseTest_FoundVulnWithFailOnVuln() throws Exception {
|
||||
exceptionRule.expect(FoundVulnerableException.class);
|
||||
exceptionRule.expectMessage(Constants.ERROR_ON_VULNERABLE);
|
||||
|
||||
Renderer renderer = new Renderer(log, true);
|
||||
renderer.renderResponse(new ByteArrayInputStream(vulnerable_response.getBytes()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void renderResponseTest_FoundVulnWithoutFailOnVuln() throws Exception {
|
||||
Renderer renderer = new Renderer(spyLog, false);
|
||||
renderer.renderResponse(new ByteArrayInputStream(vulnerable_response.getBytes()));
|
||||
|
||||
String expect =
|
||||
logHelper.strongError("✗ High severity (Fake Vulnerable - CVE-0001-0001) found on com.study.foo:bar@1.0.0") + "\n" +
|
||||
logHelper.strongInfo("! Fix version [\"1.1\"]") + "\n" +
|
||||
"\n" +
|
||||
logHelper.strongWarning("Tested 3 dependencies, found 1 vulnerable pathes.") + "\n";
|
||||
Assert.assertEquals(expect, outContent.toString());
|
||||
}
|
||||
|
||||
}
|
||||
BIN
static/remote-configuration.jpg
Normal file
BIN
static/remote-configuration.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Reference in New Issue
Block a user