diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/404.html b/404.html new file mode 100644 index 000000000..4cdd45309 --- /dev/null +++ b/404.html @@ -0,0 +1 @@ +
Info
Codyze is currently being redesigned. For the documentation for the legacy version of Codyze, please look here .
Security is hard and implementing it correctly is even harder. Luckily, there are well-established and battle-proven libraries available that do the heavy lifting of security functions such as authentication, logging or encryption. But even when using these libraries in application code, developers run the risk of making subtle errors which may undermine the security of their application. This is where Codyze helps. By integrating it into an IDE or CI pipeline, developers can analyze their source code while programming and check if they are using libraries in a correct or in an insecure way.
In contrast to many other static analysis tools, Codyze directly analyzes the source code and does not require a compiler tool-chain. It can thus even analyze incomplete source code and tolerate small syntax errors.
Codyze is based on a "Code Property Graph", which represents the source code as a graph and adds semantic information to support the analysis. This representation can be used in two ways:
Codyze checks source code for the correct usage of libraries. It is an addition to generic static analysis tools such as Sonarqube, Frama-C, or the Checker Framework and specifically verifies that libraries are used as originally intended by their developers.
Library developers write rules for their library in specification languages supported by Codyze.
Developers verify their code against rules of modelled libraries using Codyze.
Integrators of open source components may want to verify these components using the automated analysis of Codyze or by manually searching the code for critical patterns.
The goal of the redesign is to make Codyze more maintainable and easier extendable. This introduced a lot of changes compared to the legacy version.
The core functionalities of Codyze were separated from the executable part which makes it possible to use Codyze as a library.
We introduced the concept of Executors which are responsible for evaluating rules of a specific specification language. Through Executors, Codyze can verify rules written in different specification languages and utilize their advantages as long as there is an Executor for them.
We are also working on a new specification language Coko which comes with Codyze.
Additionally, we reorganized the code in Codyze to be able to handle multiple projects with their own configurations with only one Codyze instance. This, for example, allows switching between projects in an IDE without losing the context of any analysis and should better support LSP mode.
Codyze provides a built-in domain specific language, Coko, which can be used to define policies for Codyze.
Coko policies can be split into two parts:
When modeling a library, you will typically start by describing its classes or functions and then write rules.
Coko is defined as a custom Kotlin scripting language. It serves as an API to write source code queries in a declarative way. The rules written in Coko are executed to construct the queries for the used backend.
The concept of Coko is that the API is modelled through classes and functions. These classes and functions are used to declare rules, which Codyze then evaluates. Coko is, therefore, in its concept more similar to a domain specific language and only uses the Kotlin scripting technology to load the policies into Codyze. However, as a Kotlin script can contain any valid Kotlin code, it is also possible to execute arbitrary Kotlin code with Coko. It is currently not possible to prevent this, but all Coko scripts that are available on our website and GitHub repository are validated by us to prevent any misuse. For more information about custom Kotlin scripting languages, please refer to the Kotlin documentation and the respective Kotlin KEEP .
Syntax highlighting and code completion are available for Coko in any IDE that provides these for Kotlin.
The syntax of Coko is the same as the syntax of Kotlin. For writing Coko policies you will need to know how to create classes, interfaces and functions in Kotlin. Please refer to the Kotlin Documentation for an overview.
Coko also uses the concept of type-safe builders . Type-safe builders allow you to build objects in a semi-declarative way similar to markup languages. They can be seen as a special syntax for nesting the construction of objects. They will be explained in detail in the parts of Coko that use them.
To evaluate rules for an API, Coko needs an understanding of the components of the API, such as classes or functions. In Coko these components are modelled through interfaces, classes and a class called Op
.
Ops
are the basic building blocks for writing policies in Coko. With Ops
you can model and group functions of the API that serve a similar functionality. They are also a way to define queries to the Codyze backend for finding calls to these functions. Each Op
object is one query to the backend.
There are currently two types of Ops
, FunctionOps
for modelling functions and ConstructorOps
for modelling constructors in object-oriented languages. They are both built with type-safe builders. The following sections will explain the builders for each Op
type.
The function op()
is the start for building FunctionOps
. Within the block of op()
the fully qualified name of the functions you want to model can be specified as a string. In the block of the fully qualified name the arguments to function can be defined. They serve as a filter for the query. Only calls to the function with the same number of arguments with the same value at each position will be found by the query.
In signature
it is also possible to specify unordered arguments. These are arguments, that should somehow be passed to the function calls we want to find, but it is not important, in which position they are passed.
op {
+ "my.fully.qualified.name" { // (1)!
+ signature(5..10) // (2)!
+ signature(".*one.*") // (3)!
+ signature(0..5, listOf("one", "two")) // (4)!
+ signature() // (5)!
+ }
+
+ "my.other.fully.qualified.name" { // (6)!
+ signature { // (7)!
+ - ".*" // (8)!
+ -7 // (9)!
+ }
+ signature(arrayOf(4)) { // (10)!
+ - 123
+ }
+ }
+}
+
my.fully.qualified.name
that have as only argument a number between 5 and 10.my.fully.qualified.name
that have a string as only argument that contains "one", for example my.fully.qualified.name("tone")
.my.fully.qualified.name
that have a number between 0 and 5 as first argument and as second argument either the string "one" or "two".my.fully.qualified.name
where no arguments were passed.signature
function can also invoke a type-safe builder.signature
the arguments are listed using -
.-
is optional.signature
. In this example, the unordered argument is 4.The function of the builder for ConstructorOps
is constructor()
. The fully qualified name of the class is the first argument. In the block of constructor()
you can specify the arguments to the constructor like for the FunctionOp
. They serve the same purpose as for FunctionOps
.
constructor("my.fully.qualified.MyClass") { // (1)!
+ signature() // (2)!
+}
+
my.fully.qualified.MyClass
.ConstructorOps
, because the name of the constructor is clear. Arguments in Ops
are used to filter calls of a function based on the arguments that are given to the calls. In Coko there are a few special argument types that help with the filtering.
The first type is the Wildcard
object. If the Wildcard
object is given as an argument to Op
, the filter will allow any kind of value in the same argument position of the function calls.
The second type is null
. It can be used to signify that the given arguments should be filtered out of the query. This type will be helpful when constructing Op
templates with Coko functions.
Another special type are ParameterGroups
. They are a filter to express that the argument at the position should be composed of multiple values. An example would be if the argument is a string that should contain multiple strings, for example foo("Start string" + 12 + "End string")
. This can be modeled with ParameterGroups
. Coko offers the DSL function group
, in which these values can be specified.
The last types are the Type
class and the ParamWithType
class. The Type
class is used to filter the type of the arguments. The fully qualified name of the type must be given ParamWithType
combines the filter for the value with the filter for the type.
op {
+ "my.fully.qualified.name" {
+ signature(Wildcard) // (1)!
+ signature(Wildcard, 2) // (2)!
+ signature(null, 1) // (3)!
+ signature(
+ group {
+ - "Start string .*"
+ - 12
+ } // (4)!
+ )
+ signature(Type("java.util.List")) // (5)!
+ signature(1.0 withType "java.lang.Float") // (6)!
+ }
+}
+
my.fully.qualified.name
that have one argument.my.fully.qualified.name
with two arguments and where the second argument is 2.my.fully.qualified.name
with two arguments and where the second argument is 1.my.fully.qualified.name
with one argument. The argument must contain both "Start string"
and the number 12. An example would be my.fully.qualified.name("Start string with the number " + 12)
.my.fully.qualified.name
with one argument which must be of type java.util.List
1.my.fully.qualified.name
with one argument which has the value 1.0 and has the type java.lang.Float
1.Since each Op
is interpreted by Codyze as one query for function calls to the backend, it would be helpful to have templates for Ops
that find calls to the same function but with different filters. This can be achieved with functions in Coko. The parameters of these functions in Coko can be used to pass the specific values to the filter.
fun add(
+ element: Any, // (1)!
+ index: Any? // (2)!
+) = op {
+ "java.util.List.add" {
+ signature(element)
+ signature(index withType "int", element) // (3)!
+ }
+}
+
List.add
in Java is a generic method, so the type of element
is not static. However, it is recommended to use Any
even if the type of the value is static since you might want to pass one of the special argument types like Wildcard
.index
is nullable, so it is also possible to filter for calls where no index is given. The type is Any?
to be able to pass Wildcard
as well. index
. If the reference to a Coko function is used for order
rules, all parameters must have a nullable type. Coko invokes them with dummy arguments and uses internal functions to query for all calls to the modelled function regardless of the specified signatures.
A goal of Coko is to make rules more reusable. Aside from specific rules of an API, there might be some general policies that should be followed for all API that provide similar functionality. An example would be that all actions executed on a database should be logged. Instead of writing the corresponding rule for all combinations of database and logging APIs, one might want to combine this into one reusable rule.
This reusability is achieved through interfaces. In Coko interfaces and their functions describe the functionalities that a group of APIs has in common. Rules can thus be written on a more conceptual level.
When Coko encounters rules using a Coko interface as a parameter, it will use one of the available classes implementing the interface as argument to evaluate the rule. Currently, it uses the first class it finds, however, we will implement an algorithm in the future which will try to find the implementation that fits the best for the analyzed code.
interface Logging {
+ fun log(message: Any?, vararg args: Any?): Op
+}
+
+class JavaLogging: Logging {
+ override fun log(message: Any?, vararg args: Any?): Op =
+ op {
+ "java.util.logging.Logger.info" {
+ signature {
+ group {
+ - message
+ args.forEach { - it }
+ }
+ }
+ }
+ }
+}
+
+class PythonLogging: Logging {
+ override fun log(message: Any?, vararg args: Any?): Op =
+ op {
+ "logging.info" {
+ signature(args) { // (1)!
+ - message
+ }
+ }
+ }
+}
+
args
, just that they appear somewhere as arguments for the call.Classes in Coko model the actual components of an API. They can implement interfaces or just be normal classes. With classes, API functions can be grouped
For APIs written in object-oriented languages it might be sensible to create a Coko class for each class in the API.
Rules in Coko describe how an API should be used. They are functions that are annotated with the @Rule
annotation.
In the @Rule
annotation you can specify metadata about the rule such as the description of the rule. The metadata will be used for describing the findings in the SARIF output.
If the rule requires some instance of a model, they can be specified as parameters to the rule function.
Each Coko rule must return an implementation of the Evaluator
interface, which Codyze can use to evaluate the rule. Coko provides some common evaluators which will be explained in the following sections. The example model will be used for explaining the evaluators.
class Foo {
+ fun constructor() = constructor("Foo") {
+ signature()
+ }
+
+ fun first(i: Any?) = op {
+ definition("Foo.first") {
+ signature(i)
+ }
+ }
+
+ fun second(s: Any?) = op {
+ definition("Foo.second") {
+ signature(s)
+ }
+ }
+}
+
+class Bar {
+ fun second() = op {
+ definition("Bar.second") {
+ signature()
+ }
+ }
+}
+
The only
evaluator checks if all calls to an Op
are only called with the specified arguments. Therefore, it takes one Op
as argument.
@Rule
+fun `only calls to first with 1 allowed`(foo: Foo) =
+ only(foo.first(1))
+
The order
evaluator checks if functions related to an object are called in the correct order. It takes two arguments, the baseNodes
and the order. The baseNodes
are the function calls that are the start of the order. Usually, this is either the constructor of a class or some kind of initialization function.
To construct the order, Coko provides a type-safe builder. Within the builder, the order is specified as a regular expression.
The "alphabet" of the order regex is:
Op
written as <object>::<FunctionName>
or ::<FunctionName>
Ops
themselves.If all calls to a modelled function should be considered for the order regardless of the specified signatures, please use the first option. When passing Ops
, only functions that match the used signature and argument are considered valid.
The builder provides a set of functions that allow you to add quantifiers to the regex or group them.
Function | Regex | Description |
---|---|---|
or | | | Represents a choice, either the first or the second expression has to be matched |
set | [] | Represents multiple choices, one expression in it has to be matched |
maybe | * | Matches an expression zero or more times |
some | + | Matches an expression one or more times |
option | ? | Matches an expression zero or one time |
count(n) | {n } | Matches an expression exactly n times |
atLeast(min) | {min ,} | Matches an expression at least min times |
between(min, max) | {min , max } | Matches an expression at least min and at most max times |
@Rule
+fun `order of Foo`(foo: Foo) =
+ order(foo.constructor()/* (2)! */) { // (1)!
+ - foo.first(...) // (3)!
+ maybe(foo::second) // (4)!
+ }
+
Op
returned from foo.constructor
will be used as query for the function calls that are the starting point for evaluating the order.Op
returned by foo.first(...)
for the order.foo.second()
for the order. No filter will be applied. The followedBy
evaluator works similarly like the implication in logic. It takes two Ops
and specifies that if the first Op
is called then the second Op
must be called as well. Compared to the order
evaluator, followedBy
is more flexible because Ops
from different models can be connected.
@Rule
+fun `if first then second`(foo: Foo, bar: Bar) =
+ foo.first(Wildcard) followedBy bar.second()
+
The never
evaluator is used to specify that calls to an Op
with the specified arguments are forbidden. It takes one Op
as argument.
When running in command line interface (CLI) mode, Codyze can be used to automatically check a code base against a set of rules given in a supported specification language like Coko. Below are short exemplary calls to start codyze in command line interface mode. ./
refers to the top-level directory of the repository. However, for the Gradle arguments ./
refers to the directory of the project, which is codyze-cli
.
executor
/backend
. To find what arguments each executor
/backend
accept, use the --help
argument: To show the available executors
use:
To show the arguments accepted by an executor and the available backend
s use:
To show the arguments accepted by a backend
use:
The repository contains examples which you can use to test Codyze. Below are the commands to call Codyze on these examples.
./gradlew :codyze-cli:run --args="runCoko --spec ../codyze-specification-languages/coko/coko-dsl/src/test/resources/model.codyze.kts --spec ../codyze-specification-languages/coko/coko-dsl/src/test/resources/javaimpl.codyze.kts cokoCpg -s ../codyze-specification-languages/coko/coko-dsl/src/test/resources/java/Main.java"
+
This configures Codyze
to use the 'coko' executor and the 'cokoCpg' backend. You will see the result printed to the console and a findings.sarif
files is generated in the codyze-cli
folder. The spec files contain a single rule, which checks that every change to a database is logged. The sample Java file adheres to the rule, so there should be no issues in the result.
The CLI mode is a perfect candidate for integration in CI/CD processes, such as GitHub Actions. The following file can be used as an example so set up a compliance check for Java-based applications using GitHub Actions:
name: build
+
+on:
+ - push
+
+env:
+ CODYZE_VERSION: "2.1.1"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-java@v3
+ with:
+ distribution: "temurin"
+ java-version: "17"
+ - name: Install Codyze
+ run: |
+ wget "https://github.com/Fraunhofer-AISEC/codyze/releases/download/v${CODYZE_VERSION}/codyze-${CODYZE_VERSION}.zip" && unzip codyze-${CODYZE_VERSION}.zip
+ - name: Check compliance
+ run: |
+ codyze-${CODYZE_VERSION}/bin/codyze <arguments>
+
There are two ways of configuring Codyze, through command line options or a configuration file.
If both are present, the command line options take precedence over the configuration file. For list and map type options, the data from the configuration file can be overwritten if the normal option (e.g. --option-name
) is used. To append the data from the command line to the one from the configuration file, use the additions
option (e.g. --option-name-additions
)
The configurations can also be defined with a JSON configuration file. Use the option --config=<filepath>
to specify the path to the config file. The configuration from ./codyze.json
will always be loaded if no other file is specified.
Relative paths in the configuration file are resolved relative to the configuration file location.
The configuration structure separates the options by subcommand as seen below.
{
+ "good-findings": false,
+ "runCoko": {
+ "spec": "./model.codyze.kts",
+ "cokoCpg": {
+ "source": "./Main.java"
+ }
+ }
+}
+
good-findings
argument belongs to Codyze, the spec
argument belongs to the runCoko
subcommand and the source
argument belongs to the cokoCpg
subcommand. The value of the option is taken from the object which corresponds to the subcommand used for the execution. An exemplary configuration file can also be found in the GitHub repository . This is a list of all available configurations, their descriptions and their respective name. The names are the same for the configuration file and the CLI options.
./
denotes the working directory in which Codyze was started.
Key | Value | Description | Default Value |
---|---|---|---|
output | Path | The path to write the results file to. | [./] |
output-format | String | Format in which the analysis results are returned. | sarif |
good-findings | Boolean | Enable/Disable output of "positive" findings which indicate correct implementations. | true |
pedantic | Boolean | Activates pedantic analysis mode. In this mode, Codyze analyzes all given specification files and report all findings. | false |
Key | Value | Description | Default Value |
---|---|---|---|
spec | Path[] | Paths to CoKo rule files. | [./] |
disabled-specs | Path[] | The specified files will be excluded from being parsed and processed. | [] |
disabled-spec-rules | String[] | Rules that will be ignored by the analysis. | [] |
Key | Value | Description | Default Value |
---|---|---|---|
source | Path[] | Path to the to be analyzed files or directories. | [./] |
disabled-source | Path[] | Path to files or directories which should not be analyzed. Symbolic links are not followed when filtering out these paths. | [] |
additional-language | String[] | Specify programming languages of files to be analyzed (full names). | [] |
unity | boolean | Only relevant for C++. A unity build refers to a build that consolidates all translation units into a single one, which has the advantage that header files are only processed once, adding far less duplicate nodes to the graph. | false |
type-system-in-frontend | boolean | If false, the type listener system is only activated once the frontends are done building the initial AST structure. This avoids errors where the type of a node may depend on the order in which the source files have been parsed. | true |
default-passes | boolean | Adds all default passes in cpg (1. FilenameMapper, 2. TypeHierarchyResolver, 3. ImportResolver, 4. VariableUsageResolver, 5. CallResolver, 6. EvaluationOrderGraphPass, 7. TypeResolver). | true |
passes | String[] | Register these passes to be executed in the specified order. Please specify the passes with their fully qualified name. | [] |
debug-parser | boolean | Enables debug output generation for the cpg parser. | false |
disable-cleanup | boolean | Switch off cleaning up TypeManager memory after analysis, set to true only for testing. | false |
code-in-nodes | boolean | Should the code of a node be shown as parameter in the node. | false |
annotations | boolean | Enables processing annotations or annotation-like elements. | false |
fail-on-error | boolean | Should parser/translation fail on parse/resolving errors (true) or try to continue in a best-effort manner (false). | false |
symbols | Map | Definition of additional symbols. | {} |
parallel-frontends | boolean | If true, the ASTs for the source files are parsed in parallel, but the passes afterwards will still run in a single thread. This speeds up initial parsing but makes sure that further graph enrichment algorithms remain correct. | false |
match-comments-to-nodes | boolean | Controls whether the CPG frontend shall use a heuristic matching of comments found in the source file to match them to the closest AST node and save it in the comment property. | false |
analyze-includes | boolean | Enables parsing of include files. If includePaths are given, the parser will resolve symbols/templates from these in include but not load their parse tree. | false |
includes | Path[] | Paths containing include files. | [] |
enabled-includes | Path[] | If includes is not empty, only the specified files will be parsed and processed in the cpg, unless it is a part of the disabled list, in which it will be ignored. | [] |
disabled-includes | Path[] | If includes is not empty, the specified includes files will be excluded from being parsed and processed in the cpg. The disabled list entries always take priority over the enabled list entries. | [] |
Clone the source code for Codyze from the project's GitHub repository .
./gradlew :codyze-cli:installDist
codyze-cli/build/install/codyze-cli
You can also use the Gradle run task ./gradlew :codyze-cli:run
to directly run Codyze. This will print the help message and return an error.
Arguments can be passed with the --args
option.
Note
All following example calls in this documentation will assume that the source code was cloned and use the exact file structure. If you want to test Codyze with these calls, please clone the repository.
bin\codyze.bat
(Windows) or bin/codyze
(Mac, Linux)We're also offering Codyze as a container image. You can find an image with the latest release in the project's container registry .
Codyze can be integrated into multiple IDEs to automatically scan your code for errors.
The Codyze plugin can be installed from an Eclipse update site. It has been tested against Eclipse 2019-12 and later.
Help
->Install New Software...
Add...
to add a new update siteChoose a name and enter the location https://codyze.s3.eu-central-1.amazonaws.com/codyze-eclipse-plugin/ (note that this is an Eclipse update site URL and not suited to open with a web browser)
Choose and install Codyze Code Analyzer
Once installed, configure the Eclipse plugin to use the local LSP server:
Go to Windows->Preferences->Codyze Code Analysis and configure the path to the analysis server binary
If the configuration is correct, .java
and .cpp
files will be automatically scanned when they are saved. Any errors found by Codyze will be highlighted as problems. If Codyze verifies that an API is correctly used, it will mark the line with a hint.
LSP Support
plugin. Restart IntelliJ.Settings
-> Language Server Protocol
-> Server Definitions
Add a new server definition of type Executable
for extension java
and navigate to your local codyze-<version>/bin/codyze
script.
If everything works as intended, you should see a green circle in your IntelliJ status bar, indicating that the connection to the language server was successful.
The Codyze plugin can be installed from the Visual Studio 2019 Marketplace
If you prefer installing the plugin from the release page, proceed as follows:
On startup, the plugin will ask you for the path to Codyze and to the mark files you want to use. If everythings checks out, the plugin will automatically start an instance of Codyze when a solution is opened. It will then scan .cpp
files when opened or saved and highlight potential problems.
To adjust the path to Codyze, the mark files or change the command line arguments used for Codyze, in Visual Studio go to Tools
-> Options...
-> Codyze Plugin
-> Codyze Settings
.
We build a Visual Studio Code plugin of Codyze for every new version. You can download a bundled *.vsix
plugin from the release page of Codyze .
Codyze offers an LSP mode. You can user the LSP mode to integrate Codyze into any IDE or text editor with support for LSP. You need to look up the recommended approach for your favorite IDE or text editor.
Once you know, how to configure an LSP tool, you need to start Codyze in LSP mode, i.e. codyze-v2 -l
in Codyze v2 or codyze lsp
in Codyze v3. Please refer to the configuration page.
The CliktCommand to add the plain cpg backend to the codyze-cli.
The CliktCommand to add the cokoCpg backend to the codyze-cli.
Returns a list of CallExpressions with the matching fqn (fully-qualified name) and fulfilling predicate.
Returns a list of ConstructExpressions with the matching classFqn and fulfilling predicate.
Checks if there's a data flow path from "this" to that.
If this is a String, we evaluate it as a regex.
If this is a Collection, we check if at least one of the elements flows to that
If this is a Node, we use the DFG of the CPG.
Checks if there's a data flow path from "this" to any of the elements in that.
If this is a String, we evaluate it as a regex.
If this is a Collection, we check if at least one of the elements flows to that
If this is a Node, we use the DFG of the CPG.
Get all Nodes that are associated with this Op and fulfill the Signatures of the Definitions.
Returns a list of MemberExpressions with the matching something.
Checks if the CallExpression matches the signature specified with parameters. Returns false if there are nulls in parameters,
specifies the order of the parameters of the function.
If a parameter is a Type object, the function will check if the argument has the same type.
If a parameter is a ParamWithType object, the function will check if the argument has the same type and if the Any object flows to the argument
specifies if the function has a variable number of arguments at the end which are not important to the analysis
Returns a list of ValueDeclarations with the matching fqn.
Returns a list of ValueDeclarations with the matching name.
Get all Nodes that are associated with this Op and fulfill the Signatures of the Definitions.
Returns a list of MemberExpressions with the matching something.
Checks if the CallExpression matches the signature specified with parameters. Returns false if there are nulls in parameters,
Returns a list of ValueDeclarations with the matching name.
Returns a list of ValueDeclarations with the matching fqn.
CPG Evaluator to evaluate Coko order expressions.
CPG Evaluator to evaluate Coko order expressions.
Contains the functionality which is executed if the DFA terminated in an accepting state for the given base. This means that all required statements have been executed for base so far. The fsm holds the execution trace found by the analysis.
Collects a finding if the node makes an operation which violates the desired order.
Collects the finding in the AnalysisContext because the DFA finished analyzing the function but the base did not terminate in an accepting state (i.e., some operations are missing).
Codyze-specific implementation of the DFAOrderEvaluator. Its main purpose is to collect the findings in case of violations to the order.
Collects a finding if the node makes an operation which violates the desired order.
Collects the finding in the AnalysisContext because the DFA finished analyzing the function but the base did not terminate in an accepting state (i.e., some operations are missing).
Codyze-specific implementation of the DFAOrderEvaluator. Its main purpose is to collect the findings in case of violations to the order.
The CPG backend for Coko.
Returns a list of MemberExpressions with the matching something.
Returns a list of ValueDeclarations with the matching name.
Returns a list of ValueDeclarations with the matching fqn.
A CPG specific implementation of a Finding.
Returns a Location object from a Node using the given artifacts as well as its sarifRegion.
The CPG backend for Coko.
A CPG specific implementation of a Finding.
Returns a Location object from a Node using the given artifacts as well as its sarifRegion.
Returns a Region object from a Node's startLine, endLine, startColumn, endColumn property. If these properties do not exist, returns an empty Region
.
the Region
A plain CPG backend providing only the TranslationResult in the cpg property.
Holds the CPG configuration to run the CPG backend with
To add a new configuration option do the following:
add a property to CPGConfiguration
add a new CLI option to the CPGOptionGroup
update the BackendCommand.getBackend methods for all implementations of that interface e.g., BaseCpgBackend
Holds the common CLI options for all CPG based Codyze backends. Used in e.g., BaseCpgBackend and CokoCpgBackend.
A plain CPG backend providing only the TranslationResult in the cpg property.
Holds the CPG configuration to run the CPG backend with
Holds the common CLI options for all CPG based Codyze backends. Used in e.g., BaseCpgBackend and CokoCpgBackend.
Main CliktCommand. Provides the common Codyze options. Each executor must provide a CliktCommand that is registered as a subcommand on CodyzeCli.
The configFile is actually parsed in the ConfigFileParser command and then passed to this class as an argument
The Clikt option for the config file. Defined as extension function because it is used in multiple CliktCommands.
The Clikt option for the config file. Defined as extension function because it is used in multiple CliktCommands.
Every Backend must provide BackendCommand to be selectable in the CLI.
The Clikt option for the config file. Defined as extension function because it is used in multiple CliktCommands.
Each Executor must provide a ExecutorCommand to be selectable in the CLI.
A CliktCommand to parse the --config option.
A ValueSource that uses Kotlin serialization to parse JSON config files as context to Clikt commands.
Every Backend must provide BackendCommand to be selectable in the CLI.
Each Executor must provide a ExecutorCommand to be selectable in the CLI.
List all available OutputBuilders. They convert the internally used SARIF format into the final output.
List all available OutputBuilders. They convert the internally used SARIF format into the final output.
This abstract class must be implemented by all Backends that want to be selectable in the codyze-cli. Remember to add the newly created BackendCommand to the dependency injection.
This interface should be implemented as a data class to contain all the configuration options of a Backend.
When using Codyze as a CLI program, the BackendCommand is responsible to instantiate the respective Backend. However, to facilitate the usage of Codyze as a library, a Backend should have a configuration object as its only constructor argument.
The base class for all OptionGroups in Codyze backends.
If your BackendCommand does not need any OptionGroups, there is no need to implement this interface.
This abstract class must be implemented by all Backends that want to be selectable in the codyze-cli. Remember to add the newly created BackendCommand to the dependency injection.
This interface should be implemented as a data class to contain all the configuration options of a Backend.
The base class for all OptionGroups in Codyze backends.
Holds the main configuration to run Codyze with
To add a new CPG configuration option do the following:
add a property to Configuration
add a new CLI option to the CodyzeOptionGroup
update the CodyzeOptionGroup.asConfiguration method
Optionally: Add the newly added option as an argument to ExecutorCommand.getExecutor to pass it to Executors.
Holds the main configuration to run Codyze with
This abstract class must be implemented by all Executors that want to be selectable in the codyze-cli. Remember to add the newly created ExecutorCommand to the dependency injection.
This should be called in each ExecutorCommand to register possible backends. The registered BackendOptions are filtered such that only BackendOptions providing a backend of type T are registered.
This should be called in each ExecutorCommand to register possible backends. The registered BackendOptions are filtered such that only BackendOptions providing a backend of type T are registered.
This interface should be implemented as a data class to contain all the configuration options of an Executor. An ExecutorConfiguration should also contain the shared codyze options passed to ExecutorCommand.getExecutor.
When using Codyze as a CLI program, the ExecutorCommand is responsible to instantiate the respective Executor. However, to facilitate the usage of Codyze as a library, an Executor should have a configuration object and a Backend as its two constructor arguments.
The base class for all OptionGroups in Codyze backends.
If your ExecutorCommand does not need any OptionGroups, there is no need to implement this interface.
An executor performs the evaluation of a specification language against source code and provides evaluation results in the form of a SARIF Run.
To facilitate the usage of Codyze as a library, an Executor should have a ExecutorConfiguration object and a Backend as its only two constructor arguments
This abstract class must be implemented by all Executors that want to be selectable in the codyze-cli. Remember to add the newly created ExecutorCommand to the dependency injection.
This interface should be implemented as a data class to contain all the configuration options of an Executor. An ExecutorConfiguration should also contain the shared codyze options passed to ExecutorCommand.getExecutor.
The base class for all OptionGroups in Codyze backends.
The interface to all OutputBuilders. They convert the internally used SARIF Run into the chosen output format.
Convert the SARIF Run to the format of this OutputBuilder and write it as file to the given path.
Convert the SARIF Run to the format of this OutputBuilder and write it as file to the given path.
An OutputBuilder for the SARIF format.
Convert the SARIF Run to the format of this OutputBuilder and write it as file to the given path.
Convert the SARIF Run to the format of this OutputBuilder and write it as file to the given path.
The interface to all OutputBuilders. They convert the internally used SARIF Run into the chosen output format.
An OutputBuilder for the SARIF format.
Get the version of a Codyze module.
The name of the module
Provides the version for Codyze modules. The versions are read from a properties file.
Represents the constructor of a class.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Create a Signature which can be added to the ConstructorOp. The Parameters are passed through the vararg.
Create a Signature which can be added to the ConstructorOp. The Parameters are defined in the block.
Convert this OrderFragment to a binary syntax tree
Two FunctionOps will be considered equal if they have the same definitions. This means that structure of the FunctionOps have to be equal as well as the Definition.fqns but not the actual Parameters that are stored in the Signatures.
Represents a group of functions that serve the same purpose in the API.
Two FunctionOps will be considered equal if they have the same definitions. This means that structure of the FunctionOps have to be equal as well as the Definition.fqns but not the actual Parameters that are stored in the Signatures.
Create a Definition which can be added to the FunctionOp.
Two FunctionOps will be considered equal if they have the same definitions. This means that structure of the FunctionOps have to be equal as well as the Definition.fqns but not the actual Parameters that are stored in the Signatures.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Convert this OrderFragment to a binary syntax tree
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Convert this OrderFragment to a binary syntax tree
Convert this OrderFragment to a binary syntax tree
OrderBuilder subclass to hide some implementation details of OrderBuilder to coko users.
Add an Op to the userDefinedOps.
Add an OrderFragment to the orderNodes. All instances of the fragment object are removed from the list before the OrderNode from fragment is added.
Add an OrderToken to the orderNodes
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Remove all instance of fragment from the orderNodes
Represent this OrderFragment as a binary syntax tree.
Add an Op to the userDefinedOps
Add an OrderFragment to the orderNodes
Add an OrderToken to the orderNodes
Returns a representation of an immutable list of all enum entries, in the order they're declared.
This method may be used to iterate over the enum entries.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
if this enum type has no constant with the specified name
Marks a function that should be evaluated as a rule by Codyze
Returns a representation of an immutable list of all enum entries, in the order they're declared.
This method may be used to iterate over the enum entries.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
if this enum type has no constant with the specified name
Create a ConstructorOp.
Create a Definition which can be added to the FunctionOp.
A minimal example
function {
definition("my.fully.qualified.name") {}
}
the fully qualified name of the function this Definition is representing
defines the Signatures of this Definition
Create a ParameterGroup which can be added to the Signature.
Add a group containing any valid OrderDsl provided as a lambda
order {
group {
- arg1::func1
many(arg1::func2)
option {
- arg1::func2
- arg1::func3
}
}
}
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
order {
group(arg1::func1, arg1::func2, arg1::func3)
}
Represents the constructor of a class.
Represents a group of functions that serve the same purpose in the API.
Import other coko script(s)
OrderBuilder subclass to hide some implementation details of OrderBuilder to coko users.
Marks a function that should be evaluated as a rule by Codyze
Use this to create a set with the OrderSetGetOperator.get operator.
Create a ConstructorOp.
Create a Definition which can be added to the FunctionOp.
Add a group containing any valid OrderDsl provided as a lambda
Create a ParameterGroup which can be added to the Signature.
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
Create a FunctionOp.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Adds an alternation token (|
) between the current OrderToken and other. All OrderToken are converted into OrderFragments.
Create a Signature which can be added to the ConstructorOp. The Parameters are passed through the vararg.
Create a Signature which can be added to the ConstructorOp. The Parameters are defined in the block.
Create a Signature which can be added to the Definition. The Parameters are passed through the vararg.
Create a Signature which can be added to the Definition. The Parameters are defined in the block.
Create a FunctionOp.
A full example:
op {
definition("my.fully.qualified.name") {
signature {
- arg1
- arg2
- arg3
}
signature(arg1, arg2)
signature {
- arg2
- arg3
}
}
"my.other.function" { // the call to 'definition' can be omitted
signature(arg2, arg1)
}
}
This would model the functions:
my.fully.qualified.name(arg1,arg2, arg3)
my.fully.qualified.name(arg1,arg2)
my.fully.qualified.name(arg2, arg3)
my.other.function(arg2, arg1)
defines the Definitions of this FunctionOp
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Acts like a boolean OR. Matches the expression before or after the |.
It can operate within a group, or on a whole expression. The patterns will be tested in order.
Adds an alternation token (|
) between the current OrderToken and other. All OrderToken are converted into OrderFragments.
Acts like a boolean OR. Matches the expression before or after the |.
It can operate within a group, or on a whole expression. The patterns will be tested in order.
Add a set to the Order containing any valid OrderDsl provided by a lambda (see group).
Match any OrderToken in the set.
Use this to create a set with the OrderSetGetOperator.get operator.
Like the minimalist group constructor, this also only works with OrderTokens
order {
set[arg1::func1, arg1::func2, arg1::func4]
}
Create a Signature which can be added to the Definition. The Parameters are defined in the block.
are all Parameters for which the order is irrelevant and that only need to
Create a Signature which can be added to the Definition. The Parameters are passed through the vararg.
Create a Signature which can be added to the ConstructorOp. The Parameters are defined in the block.
Create a Signature which can be added to the ConstructorOp. The Parameters are passed through the vararg.
Represents the definitions of a function with the fully qualified name fqn.
stores all possible Signatures for this function
Create a Signature which can be added to the Definition. The Parameters are passed through the vararg.
Create a Signature which can be added to the Definition. The Parameters are defined in the block.
Represents a group of parameters that all belong to the same index
Two Signatures are considered equal if they have the same amount of parameters and unorderedParameters. The equals function will not check the content of parameters and unorderedParameters.
Represents a signature of a function.
Two Signatures are considered equal if they have the same amount of parameters and unorderedParameters. The equals function will not check the content of parameters and unorderedParameters.
stores Parameters of this signature in the correct order
Two Signatures are considered equal if they have the same amount of parameters and unorderedParameters. The equals function will not check the content of parameters and unorderedParameters.
Create a ParameterGroup which can be added to the Signature.
Represents the definitions of a function with the fully qualified name fqn.
Represents a group of parameters that all belong to the same index
Represents a regex OR ('|')
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Add an OrderToken to the orderNodes
Add an OrderFragment to the orderNodes. All instances of the fragment object are removed from the list before the OrderNode from fragment is added.
The reason why all instances of fragment are removed is to ensure consistent behavior of de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.or. de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.or might receive OrderFragments as arguments. OrderFragments can only be built with Order DSL functions which will add their resulting OrderFragment directly to the orderNodes list. This means that de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.or must remove the OrderFragments from the orderNodes list to prevent them from appearing multiple times. An example would be:
order {
maybe(TestClass::a)
maybe(TestClass::a) or some(TestClass::b)
}
The regex would be (a* (a* | b+)). If the OrderFragments from maybe(TestClass::a)
and some(TestClass::b)
were not removed from the orderNodes, the regex would be (a* a* b+ (a* | b+)) which is incorrect.
However, problems arise if we consider a second example:
order {
val maybeA = maybe(TestClass::a)
maybeA or some(TestClass::b)
}
The desired regex would still be (a* (a* | b+)). However, this is a problem for de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.or. It cannot differentiate if a OrderFragment was stored in a variable or not. Therefore, the OrderFragment is always removed. This means that the resulting regex is actually (a* | b+).
To resolve this inconsistency, we decided to disallow the same OrderFragment object (object reference equality, not functional equality) appearing multiple times in the orderNodes list. Instead, the last appearance is used as position for the OrderFragment object. This means, that for the example:
order {
val maybeA = maybe(TestClass::a)
add(maybeA)
some(TestClass::b)
add(maybeA)
}
the regex is (b+ a*).
If the desired regex is (a* a* b+ a*)
, please declare the a*
with separate function calls like:
order {
maybe(TestClass::a)
maybe(TestClass::a)
some(TestClass::b)
maybe(TestClass::a)
}
Add an Op to the userDefinedOps.
Base class for Order, OrderGroup and OrderSet. Creates a binary tree of the given regex with its toNode method.
Add an Op to the userDefinedOps.
Add an OrderFragment to the orderNodes. All instances of the fragment object are removed from the list before the OrderNode from fragment is added.
Add an OrderToken to the orderNodes
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Remove all instance of fragment from the orderNodes
Represent this OrderFragment as a binary syntax tree.
Add an Op to the userDefinedOps
Add an OrderFragment to the orderNodes
Add an OrderToken to the orderNodes
Remove all instance of fragment from the orderNodes
Represent this OrderFragment as a binary syntax tree.
Add an Op to the userDefinedOps
Add an OrderToken to the orderNodes
Add an OrderFragment to the orderNodes
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Convert this OrderFragment to a binary syntax tree
Convert this OrderFragment to a binary syntax tree
Represents a regex group
Add an Op to the userDefinedOps.
Add an OrderFragment to the orderNodes. All instances of the fragment object are removed from the list before the OrderNode from fragment is added.
Add an OrderToken to the orderNodes
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Remove all instance of fragment from the orderNodes
Represent this OrderFragment as a binary syntax tree.
Add an Op to the userDefinedOps
Add an OrderFragment to the orderNodes
Add an OrderToken to the orderNodes
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Returns a representation of an immutable list of all enum entries, in the order they're declared.
This method may be used to iterate over the enum entries.
All the available quantifiers for this simple regex like DSL.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
Returns an array containing the constants of this enum type, in the order they're declared.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
if this enum type has no constant with the specified name
Returns an array containing the constants of this enum type, in the order they're declared.
This method may be used to iterate over the constants.
Represents a regex set. Its toNode method converts the set into a group with OR expressions to simplify the resulting binary tree
Add an Op to the userDefinedOps.
Add an OrderFragment to the orderNodes. All instances of the fragment object are removed from the list before the OrderNode from fragment is added.
Add an OrderToken to the orderNodes
Minimalist way to create a group with a function call. However, this minimalist group constructor only works with OrderTokens
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Remove all instance of fragment from the orderNodes
Represent this OrderSet (OrderFragment) as a binary syntax tree.
Add an Op to the userDefinedOps
Add an OrderFragment to the orderNodes
Add an OrderToken to the orderNodes
Represent this OrderSet (OrderFragment) as a binary syntax tree.
Represents a regex quantifier like: '*', '?', etc.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Represents an OrderToken.
Adds an alternation token (|
) between the current OrderFragment and other. All OrderToken are converted into OrderFragments.
Represents a regex OR ('|')
Base class for Order, OrderGroup and OrderSet. Creates a binary tree of the given regex with its toNode method.
Represents a regex group
All the available quantifiers for this simple regex like DSL.
Represents a regex set. Its toNode method converts the set into a group with OR expressions to simplify the resulting binary tree
Allows the syntactic sugar to create a set with the 'get' operator.
Represents a regex quantifier like: '*', '?', etc.
Represents an OrderToken.
Returns a representation of an immutable list of all enum entries, in the order they're declared.
This method may be used to iterate over the enum entries.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
Returns an array containing the constants of this enum type, in the order they're declared.
Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
if this enum type has no constant with the specified name
Returns an array containing the constants of this enum type, in the order they're declared.
This method may be used to iterate over the constants.
The context used during rule evaluation.
Contains all the options specific to the CokoExecutor.
Compiles the given specification files and analyzes the script contents by adding all the extracted information into a SpecEvaluator.
A SpecEvaluator object containing the extracted information from all specFiles
Evaluates the given project script sourceCode against the given backend.
Compiles the given specification files and analyzes the script contents by adding all the extracted information into a SpecEvaluator.
Evaluates the given project script sourceCode against the given backend.
The Executor to evaluate Coko (codyze.kts) specification files.
Evaluates the rules. It first collects all scripts and divides it in the models and implementations. Then, it generates inputs for the rules and calls the rules with the found implementations.
The Executor to evaluate Coko (codyze.kts) specification files.
Evaluates the rules. It first collects all scripts and divides it in the models and implementations. Then, it generates inputs for the rules and calls the rules with the found implementations.
We'd love to accept your patches and contributions to this project. There are just a few small guidelines you need to follow.
Contributions to this project must be accompanied by a Contributor License Agreement. You (or your employer) retain the copyright to your contribution; this simply gives us permission to use and redistribute your contributions as part of the project. Head over to here to see your current agreements on file or to sign a new one.
You generally only need to submit a CLA once, so if you've already submitted one (even if it was for a different project), you probably don't need to do it again.
All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult GitHub Help for more information on using pull requests.
This project follows Google's Open Source Community Guidelines .