Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Decoupling Project Analysis from Risk Score Check #12

Merged
merged 6 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ This plugin internally applies the [CycloneDX Gradle plugin](https://github.com/

The plugin offers several tasks:

- `runDepTrackWorkflow`: Runs `generateSbom`, `uploadSbom`, `generateVex`, `uploadVex` and `riskScore` tasks for CI/CD.
- `createProject`: Creates a Project
- `generateSbom`: Generates the SBOM (Runs "cyclonedxBom" from [cyclonedx-gradle-plugin](https://github.com/CycloneDX/cyclonedx-gradle-plugin) under the hood)
- `uploadSbom`: Uploads SBOM file.
- `generateVex`: Generates VEX file.
- `uploadVex`: Uploads VEX file.
- `analyzeProject`: Triggers Vulnerability Analysis on a specific project
- `riskScore`: Gets risk score. If the risk score is higher than the specified value, the task will fail.
- `getOutdatedDependencies`: Gets outdated dependencies.
- `getSuppressedVuln`: Gets suppressed vulnerabilities.
- `riskScore`: Gets risk score. If the risk score is higher than the specified value, the task will fail.
- `runDepTrackWorkflow`: Runs `generateSbom`, `uploadSbom`, `generateVex` and `uploadVex` tasks for CI/CD.

### Task Configuration

Expand Down Expand Up @@ -72,6 +73,14 @@ Each task requires certain inputs which are to be specified in your `build.gradl
- `timeout`: *Optional* - If specified, the task will wait for the risk score to be calculated. Default: 0 seconds
- `maxRiskScore`: *Optional* - If specified, the task will fail if the risk score is higher than the specified value.

#### analyzeProject

- `url`: Dependency Track API URL
- `apiKey`: Dependency Track API KEY
- `projectUUID`: *Optional* - You need to set UUID or projectName and projectVersion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the logic here UUID || (projectName && projectVersion) or is it (UUID && projectVersion) || (projectName && projectVersion)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's "UUID || (projectName && projectVersion)"

- `projectName`: *Optional* - You need to set UUID or projectName and projectVersion
- `projectVersion`: *Optional* - You need to set UUID or projectName and projectVersion

#### getOutdatedDependencies

- `url`: Dependency Track API URL
Expand Down
15 changes: 12 additions & 3 deletions src/main/kotlin/com/liftric/dtcp/DepTrackCompanionPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ class DepTrackCompanionPlugin : Plugin<Project> {
task.dependsOn(generateVex)
}

val analyzeProject = project.tasks.register("analyzeProject", AnalyzeProjectTask::class.java) { task ->
task.group = taskGroup
task.description = "Triggers Vulnerability Analysis on a specific project\n"
task.apiKey.set(extension.apiKey)
task.url.set(extension.url)
task.projectUUID.set(extension.projectUUID)
task.projectName.set(extension.projectName)
task.projectVersion.set(extension.projectVersion)
}

val riskScore = project.tasks.register("riskScore", RiskScoreTask::class.java) { task ->
task.group = taskGroup
task.description = "Get Risk Score"
Expand All @@ -90,14 +100,13 @@ class DepTrackCompanionPlugin : Plugin<Project> {
task.projectName.set(extension.projectName)
task.projectVersion.set(extension.projectVersion)
task.riskScore.set(extension.riskScoreData)
task.mustRunAfter(uploadVex)
}

project.tasks.register("runDepTrackWorkflow") { task ->
task.group = taskGroup
task.description =
"Runs uploadSbom, generateVex and uploadVex for CI/CD"
task.dependsOn(generateSbom, uploadSbom, generateVex, uploadVex, riskScore)
"Runs generateSbom, uploadSbom, generateVex, uploadVex for CI/CD integration"
task.dependsOn(generateSbom, uploadSbom, generateVex, uploadVex)
}

project.tasks.register("getOutdatedDependencies", GetOutdatedDependenciesTask::class.java) { task ->
Expand Down
53 changes: 53 additions & 0 deletions src/main/kotlin/com/liftric/dtcp/tasks/AnalyzeProjectTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.liftric.dtcp.tasks

import com.liftric.dtcp.service.DependencyTrack
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Optional

abstract class AnalyzeProjectTask : DefaultTask() {
@get:Input
abstract val apiKey: Property<String>

@get:Input
abstract val url: Property<String>

@get:Input
@get:Optional
abstract val projectUUID: Property<String>

@get:Input
@get:Optional
abstract val projectName: Property<String>

@get:Input
@get:Optional
abstract val projectVersion: Property<String>

@TaskAction
fun analyzeProjectTask() {
val apiKeyValue = apiKey.get()
val urlValue = url.get()

val projectUUIDValue = projectUUID.orNull
val projectNameValue = projectName.orNull
val projectVersionValue = projectVersion.orNull

val dt = DependencyTrack(apiKeyValue, urlValue)

val uuid = when {
projectUUIDValue != null -> projectUUIDValue
projectNameValue != null && projectVersionValue != null -> dt.getProject(
projectNameValue,
projectVersionValue
).uuid

else -> throw GradleException("Either projectUUID or projectName and projectVersion must be set")
}

dt.analyzeProjectFindings(uuid)
}
}
20 changes: 10 additions & 10 deletions src/main/kotlin/com/liftric/dtcp/tasks/RiskScoreTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import kotlin.time.Duration
import kotlin.time.ExperimentalTime

abstract class RiskScoreTask : DefaultTask() {
Expand Down Expand Up @@ -42,18 +41,18 @@ abstract class RiskScoreTask : DefaultTask() {
fun riskScoreTask() {
val apiKeyValue = apiKey.get()
val urlValue = url.get()
val projectUUIDValue = projectUUID.orNull
val projectNameValue = projectName.orNull
val projectVersionValue = projectVersion.orNull
val riskScoreValue = riskScore.orNull

if (riskScoreValue == null) {
logger.info("Skipping risk score calculation")
return
}

val projectUUIDValue = projectUUID.orNull
val projectNameValue = projectName.orNull
val projectVersionValue = projectVersion.orNull

val maxRiskScore = riskScoreValue.maxRiskScore.orNull
val timeout = riskScoreValue.timeout.getOrElse(Duration.ZERO)
val timeout = riskScoreValue.timeout.orNull

val dt = DependencyTrack(apiKeyValue, urlValue)

Expand All @@ -67,10 +66,11 @@ abstract class RiskScoreTask : DefaultTask() {
else -> throw GradleException("Either projectUUID or projectName and projectVersion must be set")
}

dt.analyzeProjectFindings(uuid)
logger.info("Reanalyse triggered, waiting $timeout for analysis to finish")
runBlocking {
delay(timeout)
if (timeout != null) {
runBlocking {
logger.info("waiting $timeout before getting risk score")
delay(timeout)
}
}

val updatedProject = dt.getProject(uuid)
Expand Down
Loading