mirror of
https://github.com/ysoftdevs/odc-analyzer.git
synced 2026-03-21 08:39:42 +01:00
Make ODC installation fixed during a single scan. As a result, one can atomically swap symlinks without affecting ongoing scans.
This commit is contained in:
@@ -25,14 +25,23 @@ case class OdcConfig(odcPath: String, extraArgs: Seq[String] = Seq(), workingDir
|
|||||||
|
|
||||||
case class SingleLibraryScanResult(mainDependencies: Seq[GroupedDependency], transitiveDependencies: Seq[GroupedDependency], includesTransitive: Boolean, limitationsOption: Option[String])
|
case class SingleLibraryScanResult(mainDependencies: Seq[GroupedDependency], transitiveDependencies: Seq[GroupedDependency], includesTransitive: Boolean, limitationsOption: Option[String])
|
||||||
|
|
||||||
|
class OdcInstallation(odcPath: Path){
|
||||||
|
private def suffix = if(SystemUtils.IS_OS_WINDOWS) "bat" else "sh"
|
||||||
|
def odcBin = odcPath.resolve("bin").resolve("dependency-check."+suffix).toFile.getAbsolutePath
|
||||||
|
def odcVersion: String = {
|
||||||
|
import sys.process._
|
||||||
|
Seq(odcBin, "--version").!!.trim.reverse.takeWhile(_!=' ').reverse
|
||||||
|
}
|
||||||
|
def pluginFiles: Seq[File] = odcPath.resolve("plugins").toFile.listFiles().toSeq
|
||||||
|
}
|
||||||
|
|
||||||
class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbConnectionConfig)(implicit application: Application){
|
class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbConnectionConfig)(implicit application: Application){
|
||||||
private implicit val executionContext: ExecutionContext = Akka.system.dispatchers.lookup("contexts.odc-workers")
|
private implicit val executionContext: ExecutionContext = Akka.system.dispatchers.lookup("contexts.odc-workers")
|
||||||
private def suffix = if(SystemUtils.IS_OS_WINDOWS) "bat" else "sh"
|
|
||||||
private def odcBin = new File(new File(odcConfig.odcPath), "bin"+separatorChar+"dependency-check."+suffix).getAbsolutePath
|
|
||||||
private def mavenBin = "mvn"
|
private def mavenBin = "mvn"
|
||||||
private def nugetBin = "nuget"
|
private def nugetBin = "nuget"
|
||||||
private val OutputFormat = "XML"
|
private val OutputFormat = "XML"
|
||||||
private val DependencyNotFoundPrefix = "[ERROR] Failed to execute goal on project odc-adhoc-project: Could not resolve dependencies for project com.ysoft:odc-adhoc-project:jar:1.0-SNAPSHOT: Could not find artifact "
|
private val DependencyNotFoundPrefix = "[ERROR] Failed to execute goal on project odc-adhoc-project: Could not resolve dependencies for project com.ysoft:odc-adhoc-project:jar:1.0-SNAPSHOT: Could not find artifact "
|
||||||
|
private def resolveOdcInstallation = new OdcInstallation(Paths.get(odcConfig.odcPath).toRealPath()) // makes the path fixed, so it does not switch versions when a symlink is changed
|
||||||
|
|
||||||
private def mavenLogChecks(log: String) = {
|
private def mavenLogChecks(log: String) = {
|
||||||
if(log.lines contains "[INFO] No dependencies were identified that could be analyzed by dependency-check"){
|
if(log.lines contains "[INFO] No dependencies were identified that could be analyzed by dependency-check"){
|
||||||
@@ -48,7 +57,7 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
createOdcCommand = createMavenOdcCommand,
|
createOdcCommand = createMavenOdcCommand,
|
||||||
isMainLibraryOption = Some(_.identifiers.exists(id => id.identifierType == "maven" && id.name == s"$groupId:$artifactId:$version")),
|
isMainLibraryOption = Some(_.identifiers.exists(id => id.identifierType == "maven" && id.name == s"$groupId:$artifactId:$version")),
|
||||||
logChecks = mavenLogChecks
|
logChecks = mavenLogChecks
|
||||||
){ dir =>
|
){ (odcInstallation, dir) =>
|
||||||
val pomXml = <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
val pomXml = <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.ysoft</groupId>
|
<groupId>com.ysoft</groupId>
|
||||||
@@ -70,7 +79,7 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
{pluginFiles.map{x =>
|
{odcInstallation.pluginFiles.map{x =>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.ysoft</groupId>
|
<groupId>com.ysoft</groupId>
|
||||||
<artifactId>ad-hoc-artifact-{UUID.randomUUID().toString}</artifactId>
|
<artifactId>ad-hoc-artifact-{UUID.randomUUID().toString}</artifactId>
|
||||||
@@ -103,7 +112,7 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
),
|
),
|
||||||
enableMultipleMainLibraries = true,
|
enableMultipleMainLibraries = true,
|
||||||
limitations = Some("Scans for .NET libraries usually contain multiple DLL variants of the same library, because multiple targets (e.g., .NETFramework 4.0, .NETFramework 4.5, .NETStandard 1.0, Portable Class Library, …) are scanned.")
|
limitations = Some("Scans for .NET libraries usually contain multiple DLL variants of the same library, because multiple targets (e.g., .NETFramework 4.0, .NETFramework 4.5, .NETStandard 1.0, Portable Class Library, …) are scanned.")
|
||||||
){dir =>
|
){(_, dir) =>
|
||||||
val packagesConfig = <packages>
|
val packagesConfig = <packages>
|
||||||
<package id={packageName} version={version} />
|
<package id={packageName} version={version} />
|
||||||
</packages>
|
</packages>
|
||||||
@@ -143,21 +152,22 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def scanInternal(
|
private def scanInternal(
|
||||||
createOdcCommand: (String, Path, String) => Seq[String] = createStandardOdcCommand,
|
createOdcCommand: (OdcInstallation, String, Path, String) => Seq[String] = createStandardOdcCommand,
|
||||||
isMainLibraryOption: Option[AbstractDependency => Boolean],
|
isMainLibraryOption: Option[AbstractDependency => Boolean],
|
||||||
logChecks: String => Unit = s => (),
|
logChecks: String => Unit = s => (),
|
||||||
enableMultipleMainLibraries: Boolean = false,
|
enableMultipleMainLibraries: Boolean = false,
|
||||||
limitations: Option[String] = None
|
limitations: Option[String] = None
|
||||||
)(
|
)(
|
||||||
f: Path => Unit
|
f: (OdcInstallation, Path) => Unit
|
||||||
): Future[SingleLibraryScanResult] = Future{
|
): Future[SingleLibraryScanResult] = Future{
|
||||||
withTmpDir { scanDir =>
|
withTmpDir { scanDir =>
|
||||||
|
val odcInstallation = resolveOdcInstallation
|
||||||
val scandirPrefix = s"$scanDir$separatorChar"
|
val scandirPrefix = s"$scanDir$separatorChar"
|
||||||
val reportFilename = s"${scandirPrefix}report.xml"
|
val reportFilename = s"${scandirPrefix}report.xml"
|
||||||
val path = scanDir.resolve("scanned-dir")
|
val path = scanDir.resolve("scanned-dir")
|
||||||
Files.createDirectory(path)
|
Files.createDirectory(path)
|
||||||
f(path)
|
f(odcInstallation, path)
|
||||||
val cmd: Seq[String] = createOdcCommand(scandirPrefix, path, reportFilename)
|
val cmd: Seq[String] = createOdcCommand(odcInstallation, scandirPrefix, path, reportFilename)
|
||||||
val process = new ProcessBuilder(cmd: _*).
|
val process = new ProcessBuilder(cmd: _*).
|
||||||
directory(new File(odcConfig.workingDirectory)).
|
directory(new File(odcConfig.workingDirectory)).
|
||||||
redirectErrorStream(true).
|
redirectErrorStream(true).
|
||||||
@@ -198,18 +208,11 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def odcVersion: String = {
|
private def createHintfulOdcCommand(odcInstallation: OdcInstallation, scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
||||||
import sys.process._
|
|
||||||
Seq(odcBin, "--version").!!.trim.reverse.takeWhile(_!=' ').reverse
|
|
||||||
}
|
|
||||||
|
|
||||||
private def pluginFiles: Seq[File] = new File(new File(odcConfig.odcPath), "plugins").listFiles().toSeq
|
|
||||||
|
|
||||||
private def createHintfulOdcCommand(scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
|
||||||
val newPropertyFile = s"${scandirPrefix}odc.properties"
|
val newPropertyFile = s"${scandirPrefix}odc.properties"
|
||||||
createModifiedProps(newPropertyFile, Map("hints.file" -> s"${scandirPrefix}hints.xml"))
|
createModifiedProps(newPropertyFile, Map("hints.file" -> s"${scandirPrefix}hints.xml"))
|
||||||
val cmdBase = Seq(
|
val cmdBase = Seq(
|
||||||
odcBin,
|
odcInstallation.odcBin,
|
||||||
"-s", path.toString,
|
"-s", path.toString,
|
||||||
"--project", "AdHocProject",
|
"--project", "AdHocProject",
|
||||||
"--noupdate",
|
"--noupdate",
|
||||||
@@ -242,11 +245,11 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createStandardOdcCommand(scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
private def createStandardOdcCommand(odcInstallation: OdcInstallation, scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
||||||
val newPropertyFile = s"${scandirPrefix}odc.properties"
|
val newPropertyFile = s"${scandirPrefix}odc.properties"
|
||||||
createModifiedProps(newPropertyFile)
|
createModifiedProps(newPropertyFile)
|
||||||
val cmdBase = Seq(
|
val cmdBase = Seq(
|
||||||
odcBin,
|
odcInstallation.odcBin,
|
||||||
"-s", path.toString,
|
"-s", path.toString,
|
||||||
"--project", "AdHocProject",
|
"--project", "AdHocProject",
|
||||||
"--noupdate",
|
"--noupdate",
|
||||||
@@ -258,13 +261,13 @@ class OdcService @Inject() (odcConfig: OdcConfig, odcDbConnectionConfig: OdcDbCo
|
|||||||
cmdBase ++ odcConfig.extraArgs
|
cmdBase ++ odcConfig.extraArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createMavenOdcCommand(scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
private def createMavenOdcCommand(odcInstallation: OdcInstallation, scandirPrefix: String, path: Path, reportFilename: String): Seq[String] = {
|
||||||
val cmdBase = Seq(
|
val cmdBase = Seq(
|
||||||
mavenBin,
|
mavenBin,
|
||||||
"--file", s"${path}${separatorChar}pom.xml",
|
"--file", s"${path}${separatorChar}pom.xml",
|
||||||
"-X",
|
"-X",
|
||||||
"-U", // force update
|
"-U", // force update
|
||||||
s"org.owasp:dependency-check-maven:$odcVersion:check",
|
s"org.owasp:dependency-check-maven:${odcInstallation.odcVersion}:check",
|
||||||
"-Dautoupdate=false",
|
"-Dautoupdate=false",
|
||||||
s"-Dformat=$OutputFormat",
|
s"-Dformat=$OutputFormat",
|
||||||
s"-DlogFile=${scandirPrefix}verbose.log",
|
s"-DlogFile=${scandirPrefix}verbose.log",
|
||||||
|
|||||||
Reference in New Issue
Block a user