Skip to content

Commit

Permalink
Export to graphml
Browse files Browse the repository at this point in the history
Signed-off-by: Prabhu Subramanian <prabhu@appthreat.com>
  • Loading branch information
prabhu committed Dec 13, 2023
1 parent 333a226 commit 456d934
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 38 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/repotests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ jobs:
./atom.sh usages --remove-atom -o /tmp/py3.atom -l python $GITHUB_WORKSPACE/repotests/DjanGoat -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/py.usages.json
./atom.sh usages --remove-atom -o /tmp/py4.atom -l python $GITHUB_WORKSPACE/repotests/django-DefectDojo -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/py4.usages.json
./atom.sh usages --remove-atom -o /tmp/c3.atom -l c $GITHUB_WORKSPACE/repotests/libexpat -Dlog4j.configurationFile=log4j2.xml --slice-outfile /tmp/c.usages.json
./atom.sh --remove-atom -o /tmp/java-sec-code.atom -l java $GITHUB_WORKSPACE/repotests/java-sec-code -Dlog4j.configurationFile=log4j2.xml --export --export-dir gml_exports
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
JAVA_TOOL_OPTIONS: "-Dfile.encoding=UTF-8"
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Usage: atom [parsedeps|data-flow|usages|reachables] [options] [input]
-l, --language <value> source language
--with-data-deps generate the atom with data-dependencies - defaults to `false`
--remove-atom do not persist the atom file - defaults to `false`
--export-atom export the atom file with data-dependencies to graphml - defaults to `false`
--export-dir <value> export directory. Default: atom-exports
--file-filter <value> the name of the source file to generate slices from. Uses regex.
--method-name-filter <value>
filters in slices that go through specific methods by names. Uses regex.
Expand Down Expand Up @@ -124,6 +126,16 @@ atom usages -o app.atom --slice-outfile usages.json -l java .

Learn more about [slices](./specification/docs/slices.md) or view some [samples](https://github.com/AppThreat/atom-samples)

### Export atom to graphml

It is possible to export each method along with data dependencies in an atom to graphml format. Simply pass `--export` to enable this feature.

```shell
atom -o app.atom -l java --export --export-dir <export dir> <path to application>
```

The resulting graphml files could be imported into [Neo4j](https://neo4j.com/labs/apoc/4.1/import/graphml/) or NetworkX for further analysis.

## Languages supported

- C/C++ (Requires Java 17 or above)
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name := "atom"
ThisBuild / organization := "io.appthreat"
ThisBuild / version := "1.7.2"
ThisBuild / version := "1.7.3"
ThisBuild / scalaVersion := "3.3.1"

val chenVersion = "1.0.6"
Expand Down
35 changes: 30 additions & 5 deletions src/main/scala/io/appthreat/atom/Atom.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package io.appthreat.atom

import better.files.File
import io.appthreat.atom.dataflows.{DataFlowGraph, OssDataFlow, OssDataFlowOptions}
import io.appthreat.atom.frontends.clike.C2Atom
import io.appthreat.atom.parsedeps.parseDependencies
import io.appthreat.atom.passes.{SafeJSTypeRecoveryPass, TypeHintPass}
import io.appthreat.atom.slicing.*
import io.appthreat.atom.frontends.clike.C2Atom
import io.appthreat.c2cpg.{C2Cpg, Config as CConfig}
import io.appthreat.javasrc2cpg.{JavaSrc2Cpg, Config as JavaConfig}
import io.appthreat.jimple2cpg.{Jimple2Cpg, Config as JimpleConfig}
Expand All @@ -28,16 +28,16 @@ import io.appthreat.pysrc2cpg.{
import io.appthreat.x2cpg.passes.base.AstLinkerPass
import io.appthreat.x2cpg.passes.frontend.XTypeRecoveryConfig
import io.appthreat.x2cpg.passes.taggers.{CdxPass, ChennaiTagsPass, EasyTagsPass}
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.codepropertygraph.cpgloading.CpgLoaderConfig
import io.shiftleft.codepropertygraph.generated.Languages
import io.shiftleft.codepropertygraph.generated.{Cpg, Languages}
import io.shiftleft.semanticcpg.language.*
import io.shiftleft.semanticcpg.layers.LayerCreatorContext
import scopt.OptionParser

import java.nio.charset.Charset
import java.util.Locale
import scala.language.postfixOps
import scala.util.{Try, Failure, Properties, Success}
import scala.util.{Failure, Properties, Success, Try}

object Atom:

Expand All @@ -49,6 +49,7 @@ object Atom:
val DEFAULT_MAX_DEFS: Int = 2000
val FRAMEWORK_INPUT_TAG: String = "framework-input"
val FRAMEWORK_OUTPUT_TAG: String = "framework-output"
val DEFAULT_EXPORT_DIR: String = "atom-exports"
private val TYPE_PROPAGATION_ITERATIONS = 1
private val MAVEN_JAR_PATH: File = File.home / ".m2" / "repository"
private val GRADLE_JAR_PATH: File = File.home / ".gradle" / "caches" / "modules-2" / "files-2.1"
Expand Down Expand Up @@ -121,6 +122,21 @@ object Atom:
case config: AtomConfig => config.withRemoveAtom(true)
case _ => c
)
opt[Unit]("export-atom")
.text("export the atom file with data-dependencies to graphml - defaults to `false`")
.action((_, c) =>
c match
case config: AtomConfig =>
config.withExportAtom(true).withDataDependencies(true)
case _ => c
)
opt[String]("export-dir")
.text(s"export directory. Default: $DEFAULT_EXPORT_DIR")
.action((x, c) =>
c match
case config: AtomConfig => config.withExportDir(x)
case _ => c
)
opt[String]("file-filter")
.text(s"the name of the source file to generate slices from. Uses regex.")
.action((x, c) => c.withFileFilter(Option(x)))
Expand Down Expand Up @@ -288,6 +304,11 @@ object Atom:

try
migrateAtomConfigToSliceConfig(config) match
case x: AtomConfig if config.exportAtom =>
println(s"Exporting the atom to ${x.exportDir}")
ag.method.filterNot(_.name.startsWith("<")).filterNot(
_.name.startsWith("lambda")
).gml(x.exportDir)
case _: DataFlowConfig =>
val dataFlowSlice = sliceCpg(ag).collect { case x: DataFlowSlice => x }
val atomDataFlowSliceJson =
Expand All @@ -304,6 +325,7 @@ object Atom:
case Left(err) => return Left(err)
case Right(slice) => saveSlice(x.outputSliceFile, Option(slice))
case _ =>
end match
Right("Atom sliced successfully")
catch
case err: Throwable if err.getMessage == null =>
Expand Down Expand Up @@ -477,7 +499,10 @@ object Atom:
// Should we reuse or create the atom
def getOrCreateAtom =
config match
case _: AtomUsagesConfig if config.outputAtomFile.exists() =>
case x: AtomConfig
if (x.isInstanceOf[
AtomUsagesConfig
] || config.exportAtom) && config.outputAtomFile.exists() =>
config.withRemoveAtom(false)
try
loadFromOdb(outputAtomFile)
Expand Down
10 changes: 10 additions & 0 deletions src/main/scala/io/appthreat/atom/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ package object atom:
var dataDeps: Boolean = false
var removeAtom: Boolean = false
var maxNumDef: Int = DEFAULT_MAX_DEFS
var exportAtom: Boolean = false
var exportDir: String = DEFAULT_EXPORT_DIR

def withOutputAtomFile(x: File): AtomConfig =
this.outputAtomFile = x
Expand All @@ -32,6 +34,14 @@ package object atom:
this.removeAtom = x
this

def withExportAtom(x: Boolean): AtomConfig =
this.exportAtom = x
this

def withExportDir(x: String): AtomConfig =
this.exportDir = x
this

def withMaxNumDef(x: Int): AtomConfig =
this.maxNumDef = x
this
Expand Down
56 changes: 28 additions & 28 deletions wrapper/nodejs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions wrapper/nodejs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@appthreat/atom",
"version": "1.7.2",
"version": "1.7.3",
"description": "Create atom (⚛) representation for your application, packages and libraries",
"exports": "./index.js",
"type": "module",
Expand All @@ -9,12 +9,12 @@
"lint": "eslint *.mjs *.js"
},
"dependencies": {
"@babel/parser": "^7.23.5",
"typescript": "^5.3.2",
"@babel/parser": "^7.23.6",
"typescript": "^5.3.3",
"yargs": "^17.7.2"
},
"devDependencies": {
"eslint": "^8.54.0"
"eslint": "^8.55.0"
},
"bin": {
"atom": "./index.js",
Expand Down

0 comments on commit 456d934

Please sign in to comment.