Skip to content
This repository has been archived by the owner on Sep 15, 2021. It is now read-only.

Commit

Permalink
Merge pull request #47 from hmrc/PLATUI-809
Browse files Browse the repository at this point in the history
PLATUI-809 - Introducing scalafmt and format rules. Files in repo for…
  • Loading branch information
vivrichards600 authored Nov 17, 2020
2 parents 40f4a28 + 323e54a commit 63546cb
Show file tree
Hide file tree
Showing 26 changed files with 565 additions and 343 deletions.
44 changes: 44 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
version = 2.7.1
maxColumn = 120
lineEndings = unix
importSelectors = singleLine

project {
git = true
}

align {
preset = most
tokens = [ {code = "=>", owner = "Case|Type.Arg.ByName"}, "=", "<-", "->", "%", "%%", "should", "shouldBe", "shouldEqual", "shouldNot", "must" ]
arrowEnumeratorGenerator = true
openParenCallSite = false
openParenDefnSite = false
}

binPack {
parentConstructors = false
}

continuationIndent {
callSite = 2
defnSite = 2
}

newlines {
penalizeSingleSelectMultiArgList = false
sometimesBeforeColonInMethodReturnType = true
}

rewrite {
rules = [RedundantBraces, RedundantParens, AsciiSortImports]
redundantBraces {
maxLines = 100
includeUnitMethods = true
stringInterpolation = true
}
}

spaces {
inImportCurlyBraces = false
beforeContextBoundColon = Never
}
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ If a scanner is not listed in this config, then the alerts for this scanner will

Be sure to update this configuration when new scanners are added to ZAP.


### Formatting code
This library uses [Scalafmt](https://scalameta.org/scalafmt/), a code formatter for Scala. The formatting rules configured for this repository are defined within [.scalafmt.conf](.scalafmt.conf). Prior to checking in any changes to this repository, please make sure all files are formatted correctly.

To apply formatting to this repository using the configured rules in [.scalafmt.conf](.scalafmt.conf) execute:

```
sbt scalafmtAll
```

To check files have been formatted as expected execute:

```
sbt scalafmtCheckAll scalafmtSbtCheck
```

### Issues
Please raise any issues or feedback [here](issues/)

Expand Down
14 changes: 7 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ import uk.gov.hmrc.versioning.SbtGitVersioning
val appName = "zap-automation"

val compileDependencies = Seq(
"com.typesafe.play" %% "play-ahc-ws-standalone" % "1.1.9",
"com.typesafe.play" %% "play-json" % "2.6.13",
"org.slf4j" % "slf4j-api" % "1.7.25",
"org.slf4j" % "slf4j-simple" % "1.7.25",
"org.scalatest" %% "scalatest" % "3.0.3",
"org.pegdown" % "pegdown" % "1.6.0",
"com.typesafe.play" %% "play-ahc-ws-standalone" % "1.1.9",
"com.typesafe.play" %% "play-json" % "2.6.13",
"org.slf4j" % "slf4j-api" % "1.7.25",
"org.slf4j" % "slf4j-simple" % "1.7.25",
"org.scalatest" %% "scalatest" % "3.0.3",
"org.pegdown" % "pegdown" % "1.6.0",
// force dependencies due to security flaws found in jackson-databind < 2.9.x using XRay
"com.fasterxml.jackson.core" % "jackson-core" % "2.9.7",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.9.7",
Expand All @@ -37,7 +37,7 @@ val compileDependencies = Seq(
)

val testDependencies = Seq(
"org.mockito" % "mockito-all" % "1.10.19" % "test"
"org.mockito" % "mockito-all" % "1.10.19" % "test"
)

lazy val zapAutomation = Project(appName, file("."))
Expand Down
7 changes: 5 additions & 2 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
resolvers += Resolver.url("hmrc-sbt-plugin-releases",
url("https://dl.bintray.com/hmrc/sbt-plugin-releases"))(Resolver.ivyStylePatterns)
resolvers += Resolver.url("hmrc-sbt-plugin-releases", url("https://dl.bintray.com/hmrc/sbt-plugin-releases"))(
Resolver.ivyStylePatterns
)

resolvers += "HMRC Releases" at "https://dl.bintray.com/hmrc/releases"

Expand All @@ -12,3 +13,5 @@ addSbtPlugin("uk.gov.hmrc" % "sbt-git-versioning" % "2.1.0")
addSbtPlugin("uk.gov.hmrc" % "sbt-artifactory" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-twirl" % "1.3.8")

addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.0")
8 changes: 4 additions & 4 deletions src/main/scala/uk/gov/hmrc/zap/HealthCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@ trait HealthCheck {
val httpClient: HttpClient = WsClient

def healthCheck(localHostUrl: String): Unit = {
val localHostRegex = "http:\\/\\/localhost:\\d+".r
val localHostRegex = "http:\\/\\/localhost:\\d+".r
val healthCheckHost = localHostRegex.findFirstIn(localHostUrl).get
val healthCheckUrl = s"$healthCheckHost/ping/ping"
val healthCheckUrl = s"$healthCheckHost/ping/ping"

log.info(s"Performing health check for the test URL with: $healthCheckUrl")

val (status, _) = httpClient.get(healthCheckHost, "/ping/ping")

status match {
case 200 => ()
case _ => throw ZapException(s"Health check failed for test URL: $healthCheckUrl with status:$status")
case _ => throw ZapException(s"Health check failed for test URL: $healthCheckUrl with status:$status")
}
}
}
}
1 change: 0 additions & 1 deletion src/main/scala/uk/gov/hmrc/zap/ZapException.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,3 @@ case class PassiveScanException(message: String) extends Exception(message)
case class ActiveScanException(message: String) extends Exception(message)

case class ZapAlertException(message: String) extends Exception(message)

18 changes: 12 additions & 6 deletions src/main/scala/uk/gov/hmrc/zap/ZapReport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,28 @@ import uk.gov.hmrc.zap.logger.ZapLogger._

object ZapReport {

def generateHtmlReport(zapReport: ZapReport): String = {
def generateHtmlReport(zapReport: ZapReport): String =
report.html.index(zapReport).toString()
}

def writeToFile(report: String): Unit = {
val directory: File = new File("target/zap-reports")
if (!directory.exists()) {
directory.mkdir()
}
val file: File = new File(s"${directory.getAbsolutePath}/ZapReport.html")
val writer = new BufferedWriter(new FileWriter(file))
val file: File = new File(s"${directory.getAbsolutePath}/ZapReport.html")
val writer = new BufferedWriter(new FileWriter(file))
writer.write(report)
writer.close()
log.info(s"HTML Report generated: file://${file.getAbsolutePath}")
}
}

case class ZapReport(relevantAlerts: List[ZapAlert], failureThreshold: String, passiveScanStatus: ScanStatus,spiderScanStatus: ScanStatus,
activeScanStatus: ScanStatus, missingScanners: List[Scanner], zapVersion: String)
case class ZapReport(
relevantAlerts: List[ZapAlert],
failureThreshold: String,
passiveScanStatus: ScanStatus,
spiderScanStatus: ScanStatus,
activeScanStatus: ScanStatus,
missingScanners: List[Scanner],
zapVersion: String
)
24 changes: 15 additions & 9 deletions src/main/scala/uk/gov/hmrc/zap/ZapTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ trait ZapTest extends BeforeAndAfterAll with HealthCheck with ZapOrchestrator {
val zapConfiguration: ZapConfiguration

protected lazy val zapClient = new ZapClient(zapConfiguration)
protected lazy val zapSetup = new ZapSetUp(zapClient)
protected lazy val zapScan = new ZapScan(zapClient)
protected lazy val zapSetup = new ZapSetUp(zapClient)
protected lazy val zapScan = new ZapScan(zapClient)
protected lazy val zapAlerts = new ZapAlerts(zapClient)

implicit lazy val zapContext: ZapContext = zapSetup.initialize()
Expand All @@ -43,8 +43,9 @@ trait ZapTest extends BeforeAndAfterAll with HealthCheck with ZapOrchestrator {

zapScan.passiveScanStatus match {
case ScanNotCompleted => throw PassiveScanException("Passive Scan did not complete within configured duration.")
case UrlsNotCaptured => throw PassiveScanException("The testUrl was not proxied via ZAP. Please check your test proxy configuration.")
case _ =>
case UrlsNotCaptured =>
throw PassiveScanException("The testUrl was not proxied via ZAP. Please check your test proxy configuration.")
case _ =>
}

zapSetup.setConnectionTimeout()
Expand All @@ -58,17 +59,23 @@ trait ZapTest extends BeforeAndAfterAll with HealthCheck with ZapOrchestrator {

if (zapConfiguration.debugTearDown) {
new ZapTearDown(zapClient).removeZapSetup
}
else {
} else {
log.debug("Skipping Tear Down")
}
}

private def createTestReport(): Unit = {
lazy val zapVersion = zapSetup.findZapVersion

val zapReport = ZapReport(relevantAlerts.sortBy {_.severityScore()}, zapConfiguration.failureThreshold, zapScan.passiveScanStatus,
zapScan.spiderRunStatus, zapScan.activeScanStatus, zapSetup.checkMissingScanners, zapVersion)
val zapReport = ZapReport(
relevantAlerts.sortBy(_.severityScore()),
zapConfiguration.failureThreshold,
zapScan.passiveScanStatus,
zapScan.spiderRunStatus,
zapScan.activeScanStatus,
zapSetup.checkMissingScanners,
zapVersion
)

writeToFile(generateHtmlReport(zapReport))
}
Expand Down Expand Up @@ -102,5 +109,4 @@ trait ZapOrchestrator {
}
}


}
9 changes: 6 additions & 3 deletions src/main/scala/uk/gov/hmrc/zap/ZapTestStatus.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ object ZapTestStatus {
def isTestSucceeded(relevantAlerts: List[ZapAlert], failureThreshold: String): Boolean = {

val failingAlerts = failureThreshold match {
case "High" => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational" || zapAlert.risk == "Low" || zapAlert.risk == "Medium")
case "High" =>
relevantAlerts.filterNot(zapAlert =>
zapAlert.risk == "Informational" || zapAlert.risk == "Low" || zapAlert.risk == "Medium"
)
case "Medium" => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational" || zapAlert.risk == "Low")
case "Low" => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational")
case _ => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational")
case "Low" => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational")
case _ => relevantAlerts.filterNot(zapAlert => zapAlert.risk == "Informational")
}
failingAlerts.isEmpty
}
Expand Down
77 changes: 33 additions & 44 deletions src/main/scala/uk/gov/hmrc/zap/api/ZapAlerts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,29 @@ class ZapAlerts(zapClient: ZapClient) {
}
}

def parsedAlerts: List[ZapAlert] = {
def parsedAlerts: List[ZapAlert] =
if (alertUrlsToReport.isEmpty)
getAlerts()
else
alertUrlsToReport.flatMap(getAlerts)
}

def applyRiskLevel(alert: ZapAlert): ZapAlert = {
val customRiskLevels: List[Config] = zapConfiguration.customRiskConf

customRiskLevels.find({riskInfo => alert.pluginId == riskInfo.getString("pluginId")}) match {
customRiskLevels.find(riskInfo => alert.pluginId == riskInfo.getString("pluginId")) match {
case Some(riskInfo) => alert.modifyRisk(riskInfo.getString("risk"))
case None => alert
case None => alert
}
}

private def getAlerts(baseUrl: String = ""): List[ZapAlert] = {
val response: String = callZapApi("/json/alert/view/alerts", "baseurl" -> baseUrl)
val jsonResponse = Json.parse(response)
val jsonResponse = Json.parse(response)
(jsonResponse \ "alerts").as[List[ZapAlert]]
}

def alertsToIgnore(): List[ZapAlertFilter] = {
val listOfAlerts: List[Config] = zapConfiguration.alertsToIgnore
val listOfAlerts: List[Config] = zapConfiguration.alertsToIgnore
val listBuffer: ListBuffer[ZapAlertFilter] = new ListBuffer[ZapAlertFilter]

listOfAlerts.foreach { af: Config =>
Expand All @@ -73,55 +72,45 @@ class ZapAlerts(zapClient: ZapClient) {
}
}

case class ZapAlert(other: String = "",
method: String = "",
evidence: String = "",
pluginId: String = "",
cweid: String,
confidence: String = "",
wascid: String = "",
description: String = "",
messageId: String = "",
url: String,
reference: String = "",
solution: String = "",
alert: String = "",
param: String = "",
attack: String = "",
name: String = "",
risk: String = "",
id: String = "") {

def riskShortName():String = {
case class ZapAlert(
other: String = "",
method: String = "",
evidence: String = "",
pluginId: String = "",
cweid: String,
confidence: String = "",
wascid: String = "",
description: String = "",
messageId: String = "",
url: String,
reference: String = "",
solution: String = "",
alert: String = "",
param: String = "",
attack: String = "",
name: String = "",
risk: String = "",
id: String = ""
) {

def riskShortName(): String =
if (risk == "Informational") "Info"
else risk
}

def references(): List[String] = {
def references(): List[String] =
reference.split("\\n").toList
}

def severityScore(): String = {
def severityScore(): String =
s"${riskCodes(risk)}-${confidenceCodes(confidence)}"
}

val riskCodes = Map("High"->"1",
"Medium"->"2",
"Low"->"3",
"Informational"->"4")
val riskCodes = Map("High" -> "1", "Medium" -> "2", "Low" -> "3", "Informational" -> "4")

val confidenceCodes = Map("High"->"1",
"Medium"->"2",
"Low"->"3")
val confidenceCodes = Map("High" -> "1", "Medium" -> "2", "Low" -> "3")

def modifyRisk(newRisk: String): ZapAlert = this.copy(risk = newRisk)
def modifyRisk(newRisk: String): ZapAlert = this.copy(risk = newRisk)
}


case class ZapAlertFilter(cweid: String, url: String) {
def matches(zapAlert: ZapAlert): Boolean = {
def matches(zapAlert: ZapAlert): Boolean =
zapAlert.url.matches(url) && zapAlert.cweid.equals(cweid)
}
}


Loading

0 comments on commit 63546cb

Please sign in to comment.