Skip to content
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
18 changes: 18 additions & 0 deletions console/src/main/scala/io/shiftleft/console/scan/ScanPass.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.shiftleft.console.scan

import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.console.Query
import io.shiftleft.passes.{DiffGraph, KeyPoolCreator, ParallelCpgPass}

class ScanPass(cpg: Cpg, queries: List[Query])
extends ParallelCpgPass[Query](cpg,
keyPools = Some(KeyPoolCreator.obtain(queries.size.toLong, 42949672950L).iterator)) {

override def partIterator: Iterator[Query] = queries.iterator

override def runOnPart(query: Query): Iterator[DiffGraph] = {
val diffGraph = DiffGraph.newBuilder
query(cpg).foreach(diffGraph.addNode)
Iterator(diffGraph.build)
}
}
105 changes: 105 additions & 0 deletions console/src/main/scala/io/shiftleft/console/scan/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package io.shiftleft.console

import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.generated.{NodeTypes, nodes}
import overflowdb.traversal._
import io.shiftleft.semanticcpg.language._

package object scan {

implicit class ScannerStarters(val cpg: Cpg) extends AnyVal {
def finding: Traversal[nodes.Finding] =
cpg.graph.nodes(NodeTypes.FINDING).cast[nodes.Finding]
}

implicit class QueryWrapper(q: Query) {

/**
* Obtain list of findings by running query on CPG
* */
def apply(cpg: Cpg): List[nodes.NewFinding] = {
q.f(cpg)
.map(
evidence =>
finding(evidence = evidence,
name = q.name,
author = q.author,
title = q.title,
description = q.description,
score = q.score))
.l
}
}

private object FindingKeys {
val name = "name"
val author = "author"
val title = "title"
val description = "description"
val score = "score"
}

implicit class ScannerFindingStep(val traversal: Traversal[nodes.Finding]) extends AnyRef {

def name: Traversal[String] = traversal.map(_.name)

def author: Traversal[String] = traversal.map(_.author)

def title: Traversal[String] = traversal.map(_.title)

def description: Traversal[String] = traversal.map(_.description)

def score: Traversal[Double] = traversal.map(_.score)

}

implicit class ScannerFindingExtension(val node: nodes.Finding) extends AnyRef {

def name: String = getValue(FindingKeys.name)

def author: String = getValue(FindingKeys.author)

def title: String = getValue(FindingKeys.title)

def description: String = getValue(FindingKeys.description)

def score: Double = getValue(FindingKeys.score).toDouble

protected def getValue(key: String, default: String = ""): String =
node.keyValuePairs.find(_.key == key).map(_.value).getOrElse(default)

}

private def finding(evidence: nodes.StoredNode,
name: String,
author: String,
title: String,
description: String,
score: Double): nodes.NewFinding = {
nodes.NewFinding(
evidence = List(evidence),
keyValuePairs = List(
nodes.NewKeyValuePair(FindingKeys.name, name),
nodes.NewKeyValuePair(FindingKeys.author, author),
nodes.NewKeyValuePair(FindingKeys.title, title),
nodes.NewKeyValuePair(FindingKeys.description, description),
nodes.NewKeyValuePair(FindingKeys.score, score.toString)
)
)
}

/**
* Print human readable list of findings to standard out.
* */
def outputFindings(cpg: Cpg): Unit = {
cpg.finding.sortBy(_.score.toInt).foreach { finding =>
val evidence = finding.evidence.headOption
.map { e =>
s"${e.location.filename}:${e.location.lineNumber.getOrElse(0)}:${e.location.methodFullName}"
}
.getOrElse("")
println(s"Result: ${finding.score} : ${finding.title}: $evidence")
}
}

}