diff --git a/.github/img/rules.png b/.github/img/rules.png deleted file mode 100644 index ae0c0a42..00000000 Binary files a/.github/img/rules.png and /dev/null differ diff --git a/README.md b/README.md index 68f2aea2..759fbab7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Sonar Cryptography Plugin +# Sonar Cryptography Plugin (CBOMkit-hyperion) [![License](https://img.shields.io/github/license/IBM/sonar-cryptography.svg?)](https://opensource.org/licenses/Apache-2.0) [![Current Release](https://img.shields.io/github/release/IBM/sonar-cryptography.svg?logo=IBM)](https://github.com/IBM/sonar-cryptography/releases) @@ -6,6 +6,7 @@ This repository contains a SonarQube Plugin that detects cryptographic assets in source code and generates [CBOM](https://cyclonedx.org/capabilities/cbom/). +It is part of **the [CBOMKit](https://github.com/IBM/cbomkit) toolset**. ## Version compatibility @@ -58,7 +59,7 @@ This plugin incorporates rules specifically focused on cryptography. > To generate a Cryptography Bill of Materials (CBOM), it is mandatory to activate at > least one of these cryptography-related rules. -![Activate Rules Crypto Rules](.github/img/rules.png) +![Activate Rules Crypto Rules](docs/images/rules.png) As of the current version, the plugin contains one single rule for creating a cryptographic inventory. Future updates may introduce additional rules to expand functionality. diff --git a/docs/DETECTION_RULE_STRUCTURE.md b/docs/DETECTION_RULE_STRUCTURE.md index b8f3635f..4f297172 100644 --- a/docs/DETECTION_RULE_STRUCTURE.md +++ b/docs/DETECTION_RULE_STRUCTURE.md @@ -99,19 +99,17 @@ A detection context is therefore linked to each detected value, and is designed For example, suppose you have two function calls `Cipher.getInstance("AES")` and `SecretKeyFactory.getInstance("AES")`. When writing detection rules to capture their cryptography information, you will in both cases capture the algorithm value "AES". But using the detection context, you can distinguish these two values. In the first case, using `buildForContext(new CipherContext())`, you can capture "AES" knowing that it is a cipher. In the second case, using `buildForContext(new SecretKeyContext())`, you can capture "AES" knowing that it is a secret key. -Additionally, you can add more precise information in your context if necessary. For example, to specify that your AES cipher is a block cipher, you can use the specific context `buildForContext(new CipherContext(CipherContext.Kind.BLOCK_CIPHER))`. This context first coarsely categorizes your finding as related to ciphers, and specifies more precisely that it is a block cipher. +Additionally, you can add more precise information in your context if necessary, using the constructor `DetectionContext(@Nonnull Map properties)` to add (multiple) properties to any context. +For example, to specify that your AES cipher is a block cipher, you can use the specific context `buildForContext(new CipherContext(Map.of("kind", "BLOCK_CIPHER"))`. This context first coarsely categorizes your finding as related to ciphers, and specifies more precisely that it is a block cipher. After, we have `inBundle(IBundle bundle)` that requires us to link our rule to a bundle identifier ([`IBundle`](../engine/src/main/java/com/ibm/engine/rule/IBundle.java)). -Indeed, we may have several functions or constructors doing the same thing, typically all having the same name, but differing by the various parameters they have. -In this case, we have to write one detection rule per function. -But using the same bundle identifier for all these rules, we can specify that these rules all belong together. +We typically use a short identifier of the cryptography library for the bundle, like "Jca" for JCA and "Bc" for BouncyCastle. +This will then be useful when we translate the detected findings: we use the bundle identifier to distinguish between the cryptography libraries and apply an adequate translation. And finally, we can finish the specification of the detection rules by adding top level dependent detection rules with `withDependingDetectionRules(List> detectionRules)` (or not, using `withoutDependingDetectionRules()` instead). -These are similar to the parameter dependent rules, but instead of applying these rules on a parameter, they are applied to the object itself, i.e. to the object with which the rule matched in the first place. +These are similar to the parameter dependent rules, but instead of applying these rules on a parameter, they are applied to the object itself, i.e. to the object with which the rule matched in the first place[^2]. -> TODO: Currently, findings of top level dependent detection rules are added below *each* (top level and parameter) detections of the rules in the tree of detected values. -> This is not a desired behavior as it duplicates information, and should be changed in the future. -> This issue can be followed [here](https://github.com/IBM/sonar-cryptography/issues/12). +[^2]: Currently, findings of top level dependent detection rules are added below *each* (top level and parameter) detections of the rules in the tree of detected values, *except* for parameter detections using `asChildOfParameterWithId`. More information [here](https://github.com/IBM/sonar-cryptography/pull/142). > [!TIP] > You will find all the classes implementing the action factories, value factories and contexts (that you may use in the functions described above) in the [`model`](../engine/src/main/java/com/ibm/engine/model/) directory of the engine. @@ -144,7 +142,7 @@ new DetectionRuleBuilder() .shouldBeDetectedAs(new BlockSizeFactory<>(Size.UnitType.BIT)) .asChildOfParameterWithId(-1) .buildForContext(new CipherContext(CipherContext.Kind.MODE)) - .inBundle(() -> "BcBlockCipher") + .inBundle(() -> "Bc") .withDependingDetectionRules(BcBlockCipherInit.rules()); ``` @@ -157,6 +155,7 @@ This parameter detection is placed below the mode detection using `asChildOfPara To capture the first parameter, we rely instead on a list of dependent detection rules `BcBlockCipherEngine.rules()`, that should capture all the possible `BlockCipher` classes existing in the library. In our case, a dependent rule targeting `AESEngine.newInstance()` should capture the value "AES", with a context that should specify that it is the base cipher. Finally, a list of top level dependent detection rules `BcBlockCipherInit.rules()` should capture some information contained in the `cfb.init(...)` function call. +This top level dependent detection should be placed only below the `BlockCipher` detection (and not below the `int` detection because it uses `asChildOfParameterWithId`). ### Special cases: no parameter and any parameters @@ -188,14 +187,91 @@ Once you have written your detection rule, and once this rule detects findings w The aim of the translation is to represent these values in a standardized, language-independent tree in the cryptographic domain. For this, you should represent your cryptographic assets and values using the standard classes defined in the [`model`](../mapper/src/main/java/com/ibm/mapper/model/) directory of the *mapper* module (and not of the engine module like before). -You should use the information contained in the detection context and the type of detection value to decide which type of translation you want to apply. +### If your detected asset is generic -With the help of some knowledge about cryptography, you can translate those findings into the correct model classes. -It is straightforward to translate what you detected as an *Algorithm* (from `engine`) into an *Algorithm* (from `mapper`). -But if you know that this algorithm is used for public key encryption in the specific context in which you detect it, you may keep this information by using the context `PublicKeyContext` in your detection rule, and then decide to translate it into a `PublicKeyEncryption` (which is a superclass of mapper's `Algorithm`). +Let's start with the simplest case: suppose you are detecting a generic value, independent of any algorithm, like a key size. +Suppose you detect the value `"256"` as a `KeySize`. +In this case, you don't have to use algorithm-specific classes of our model, you can simply translate it to the appropriate equivalent class of the model, which is in this case `KeyLength`. +This simple translation would look like: +```java +if (value instanceof KeySize keySize) { + KeyLength keyLength = new KeyLength(keySize.getValue(), detectionLocation); + return Optional.of(keyLength); +} +``` + +### If your detected asset is already specified in our model + +Let's suppose you detect the string `"AESEngine"` corresponding to the instantiation of a new AES block cipher. +Because our model already contains the [`AES`](../mapper/src/main/java/com/ibm/mapper/model/algorithms/AES.java) algorithm, you can simply use it. +This concretely means that in the mapper file (implementing [`IMapper`](../mapper/src/main/java/com/ibm/mapper/mapper/IMapper.java)) in which you are implementing this translation, you should return a `new Optional.of(new AES(detectionLocation))` when `parse("AESEngine", detectionLocation)` is called. + +Every time you are using one of these predefined model algorithm, you should have a look at its class: it may contain various constructors for various use cases. +For example, if your `"AESEngine"` call was instead used for authenticated encryption (and you would carry this information through the detection context for example), you should instead translate it using the constructor `new AES(AuthenticatedEncryption.class, detectionLocation)`. + +### If your detected asset is not yet specified in our model: add it! + +Suppose you are detecting the string `"KalynaEngine"`, corresponding to the Kalyna block cipher which is not yet part of our model. +We explain how you can add Kalyna to our general model, which you can then use for your translation. + +First, find resources about Kalyna, like its [Wikipedia page](https://en.wikipedia.org/wiki/Kalyna_(cipher)) or an official [paper](https://eprint.iacr.org/2015/650.pdf). +Kalyna is also sometimes referred as "DSTU 7624:2014", which we will add to the class documentation. + +Using this knowledge, we first need to find the _base class_ of Kalyna: is it an [`Algorithm`](../mapper/src/main/java/com/ibm/mapper/model/Algorithm.java), [`Mode`](../mapper/src/main/java/com/ibm/mapper/model/Mode.java), [`Padding`](../mapper/src/main/java/com/ibm/mapper/model/Padding.java), [`EllipticCurve`](../mapper/src/main/java/com/ibm/mapper/model/EllipticCurve.java) or [`Protocol`](../mapper/src/main/java/com/ibm/mapper/model/Protocol.java)? It is an `Algorithm`. + +Then, we look into the _primitives_ which can apply to Kalyna: these are the classes at the root of [`model`](../mapper/src/main/java/com/ibm/mapper/model/) implementing [`IPrimitive`](../mapper/src/main/java/com/ibm/mapper/model/IPrimitive.java). +Kalyna is mainly used as a [`BlockCipher`](../mapper/src/main/java/com/ibm/mapper/model/BlockCipher.java), but can also be used as a [`Mac`](../mapper/src/main/java/com/ibm/mapper/model/Mac.java) or a [`KeyWrap`](../mapper/src/main/java/com/ibm/mapper/model/KeyWrap.java). + +Therefore, we start writing the class [`Kalyna`](../mapper/src/main/java/com/ibm/mapper/model/algorithms/Kalyna.java), with its basic documentation, as: +```java +/** + * + * + *

{@value #NAME}

+ * + *

+ * + *

Specification

+ * + *
    + *
  • https://en.wikipedia.org/wiki/Kalyna_(cipher) + *
  • https://eprint.iacr.org/2015/650.pdf + *
+ * + *

Other Names and Related Standards

+ * + *
    + *
  • DSTU 7624:2014 + *
+ */ +public final class Kalyna extends Algorithm implements BlockCipher, Mac, KeyWrap { + + private static final String NAME = "Kalyna"; +``` + +You then should define multiple constructors which could be useful in the context of Kalyna. +Because it is primarily a `BlockCipher`, let's add a basic constructor, and a second one adding the size of the block: +```java +public Kalyna(@Nonnull DetectionLocation detectionLocation) { + super(NAME, BlockCipher.class, detectionLocation); +} + +public Kalyna(int blockSize, @Nonnull DetectionLocation detectionLocation) { + this(detectionLocation); + this.put(new BlockSize(blockSize, detectionLocation)); +} +``` + +Here, we have added the `BlockSize` as a parameter, but there are a lot of other building blocks in this cryptography model. You can explore all the possibilities at the root of [`model`](../mapper/src/main/java/com/ibm/mapper/model/) and in its [`functionality`](../mapper/src/main/java/com/ibm/mapper/model/functionality/) subdirectory. + +However, it is important to note that Kalyna is not _always_ a `BlockCipher` (as it also implements `Mac` and `KeyWrap`), and an easy way to let the user instantiate a Kalyna with the kind of its choice is to have this kind of constructor: +```java +public Kalyna(@Nonnull final Class asKind, @Nonnull Kalyna kalyna) { + super(kalyna, asKind); +} +``` -As a rule a thumb, there is almost always a straightforward translation of the assets you detect. -But if you keep sufficiently enough information using the context and if you use some cryptography knowledge, you may translate your finding into a more specific class which will then bring more information into the CBOM. +### The output of the translation The translation of the tree of detected findings is done node-by-node. A tree of translated values is built while you are translating your detected values. @@ -204,7 +280,7 @@ This means that the translation of a child node of a detected value will be appe | ![example of the node-by-node translation process](./images/translation.png) | |:--:| -| *This diagram represents the node-by-node translation process. In blue, we have the tree of detected values. The dotted lines show that each detected value gets independently translated into some translated value(s), in green. At the end of the node-by-node translation process, we have a tree of translated values (right part of the diagram) which is composed of each translated value, linked with the same ordering as the tree of detected values. This current result is not satisfying, and we will explain next how we can reorganize this tree of translated values.* | +| *This diagram represents the node-by-node translation process. In blue, we have the tree of detected values. The dotted lines show that each detected value gets independently translated into some translated value(s), in green. Note that we translate `CCMBlockCipher` into an `UNKNOWN` authenticated encryption node with a `CCM` mode node, to avoid having the mode as the parent of the algorithm (`AES`), which will make the next step (reorganization) a bit simpler. At the end of the node-by-node translation process, we have a tree of translated values (right part of the diagram) which is composed of each translated value, linked with the same ordering as the tree of detected values. This current result is not satisfying, and we will explain next how we can reorganize this tree of translated values.* | ## Reorganizing the translation tree diff --git a/docs/LANGUAGE_SUPPORT.md b/docs/LANGUAGE_SUPPORT.md index cc77c6d0..649da27b 100644 --- a/docs/LANGUAGE_SUPPORT.md +++ b/docs/LANGUAGE_SUPPORT.md @@ -76,7 +76,9 @@ The tree does not contain any semantic information about how the cryptographic v Ultimately, we want a meaningful representation of all cryptography-relevant values: a tree structure in which the relationships between the nodes have a meaning. Back to our example, we want a tree where the mode is a child node of the algorithm node, to indicate that it's the mode of this algorithm. -This process of building a meaningful tree representation of the captured cryptography values is called the translation. This process is also part of the language module (like the `java` or `python` module). In certain cases where translation requires to parse a string, the parsing and translation process is outsourced to the `mapper` module for better modularity. +This process of building a meaningful tree representation of the captured cryptography values is called the translation. This process is also part of the language module (like the `java` or `python` module). +The translation process requires at some point to map those captured cryptography strings to a standard representation of the cryptography asset. +For better modularity, this mapping is done as part of the `mapper` module. The last step of the translation process is called the enrichment, and is done by the `enricher` module. This step aims at adding content to the translated tree, based on external knowledge. @@ -131,6 +133,17 @@ And add the dependency (using this version reference) under ` +java,jsp,py,ipynb +``` + ### Identifying the four classes to use in generics Recall that our methodology aims to bridge the gap between the language-specific parser APIs and a higher level language-agnostic API. @@ -434,10 +447,9 @@ public static List> rules() { Once this is done, try to run your unit test and look at the logs. If it works, you should see logs[^4] of your detected values, in a tree structure looking like this (but with the values of your test file that you specified to detect in *MyRule*): ``` -DEBUG [id: 1c259, bundle: -2060…, level: 0, hash: -8884…] (CipherContext, ValueAction) CBC -DEBUG [id: f5b9a, bundle: 21061…, level: 1, hash: 13077…] └─ (CipherContext, OperationMode) 0 -DEBUG [id: 7b818, bundle: 92146…, level: 1, hash: -4294…] └─ (CipherContext, ValueAction) AES -DEBUG [id: 8d2d8, bundle: 21061…, level: 2, hash: 13077…] └─ (CipherContext, OperationMode) 0 +[id: afeca, bundle: Bc, level: 0, hash: -1948…] (CipherContext<{kind=BLOCK_CIPHER}>, ValueAction) CBCBlockCipher +[id: cca99, bundle: Bc, level: 1, hash: 10584…] └─ (CipherContext<{kind=ENCRYPTION_STATUS}>, OperationMode) 0 +[id: bb6ad, bundle: Bc, level: 1, hash: -6352…] └─ (CipherContext<{kind=BLOCK_CIPHER_ENGINE}>, ValueAction) AESEngine ``` [^4]: If you wrote your own `TestBase`, make sure that you call the `DetectionStoreLogger.print(DetectionStore ds)` method at the right place to display your findings in the logs. @@ -487,9 +499,8 @@ java ├── translator │ └── contexts └── reorganizer - └── rules ``` -

edit this tree

+

edit this tree

#### The translator @@ -498,19 +509,30 @@ In Java, this is the [`JavaTranslator`](../java/src/main/java/com/ibm/plugin/tra For better structure, we advise to split the translation in multiple files based on the detection context of the detected values. We therefore advise creating one translator file per detection context, and to store them in `translation/translator/contexts/`. +Each of these files should implement the interface [`IContextTranslation`](../mapper/src/main/java/com/ibm/mapper/IContextTranslation.java). In your main translator file, you can switch over the detection context of the values of your detection store, and delegate the actual translation work to the context translator files. Look at how it is done in Java for more details. -Additionally, if translating your assets implies parsing complicated strings (typically like `"AES/ECB/PKCS5Padding"` in Java's JCA), we recommend handling the parsing with dedicated classes of the `mapper` module. -These classes should be in the `mapper/.../mapper/mapper/mycrypto/` directory and should implement the [`IMapper`](../mapper/src/main/java/com/ibm/mapper/mapper/IMapper.java) interface. +In each context translation file, you may want to have a different translation process depending on the cryptography library. +If so, have a look to how it is done in Java, where an abstract class [`JavaAbstractLibraryTranslator`](../java/src/main/java/com/ibm/plugin/translation/translator/contexts/JavaAbstractLibraryTranslator.java) implementing `IContextTranslation` is defined, and performs a switch on the bundle identifier to distinguish between the various cryptography libraries. +Then, the various classes in the `context` folder extend this abstract class, and implement library-specific translation functions. + +Then for each context, you want to map each detected value (often a string) to a "standard" representation of this asset. +Such representations form what we call the cryptography _model_, and you can find a wide variety of classes describing algorithms, modes, paddings and others in the subfolders of the mapper's [`model`](../mapper/src/main/java/com/ibm/mapper/model/) folder. +The mapping should therefore link detected values to model classes, and should be done in the `mapper` module, with classes in the `mapper/.../mapper/mapper/mycrypto/` directory which should implement the [`IMapper`](../mapper/src/main/java/com/ibm/mapper/mapper/IMapper.java) interface. +Typically, a mapper file provides a switch statement over a variety of possible detected values, and maps each value to a class of the `model`. +When translating your detected values implies parsing complicated strings (typically like `"AES/ECB/PKCS5Padding"` in Java's JCA), the parsing should also be handled in those mapper classes. + +Ultimately, those mapper classes can be called from your context-specific translation functions. You can now add content to these files to translate the findings from your first detection rule, following the section [*Translating findings of a detection rule*](./DETECTION_RULE_STRUCTURE.md#translating-findings-of-a-detection-rule). #### The reorganization -In the directory `translation/reorganizer/`, start by creating your file listing all reorganization rules for your language. In Java, this is the [`JavaReorganizerRules`](../java/src/main/java/com/ibm/plugin/translation/reorganizer/JavaReorganizerRules.java) class. +Reorganization rules can be added in the [`reorganizer/rules/`](../mapper/src/main/java/com/ibm/mapper/reorganizer/rules/) directory of the mapper, independently of the programming language and cryptography library (a same rule could be reused in multiple cases). +You can use the helpers defined in [`UsualPerformActions.java`](../mapper/src/main/java/com/ibm/mapper/reorganizer/UsualPerformActions.java) to easily write common reorganization rules. -All these reorganization rules should then be stored in `translation/reorganizer/rules/`, with the structure of your choice. +Then, in the directory `translation/reorganizer/`, create a file listing all reorganization rules for your language. In Java, this is the [`JavaReorganizerRules`](../java/src/main/java/com/ibm/plugin/translation/reorganizer/JavaReorganizerRules.java) class. If necessary, you can now reorganize the translation of the findings of your first detection rule, following the section [*Reorganizing the translation tree*](./DETECTION_RULE_STRUCTURE.md#reorganizing-the-translation-tree). @@ -521,6 +543,7 @@ In `translation/`, start by creating a file controlling the translation process In Java, this is [`JavaTranslationProcess`](../java/src/main/java/com/ibm/plugin/translation/JavaTranslationProcess.java). This is where you will apply the translation and reorganization steps, as well as the enrichment process, which is a step adding external information to the translation tree, as mentioned [earlier](#the-translation). +Make sure to log the translated, reorganized and enriched trees of findings by calling `Utils.printNodeTree(List nodes)` at the right places (with `Utils` from `com.ibm.mapper.utils`). These steps must be called in the `initiate` function, which looks like this in Java: ```java @Override @@ -529,26 +552,29 @@ public List initiate( @Nonnull DetectionStore rootDetectionStore) { // 1. Translate - JavaTranslator javaTranslator = new JavaTranslator(rule); - List translatedValues = javaTranslator.translate(rootDetectionStore); + final JavaTranslator javaTranslator = new JavaTranslator(); + final List translatedValues = javaTranslator.translate(rootDetectionStore); + Utils.printNodeTree("translated ", translatedValues); // 2. Reorganize - Reorganizer javaReorganizer = new Reorganizer(reorganizerRules); - List reorganizedValues = javaReorganizer.reorganize(translatedValues); + final Reorganizer javaReorganizer = new Reorganizer(reorganizerRules); + final List reorganizedValues = javaReorganizer.reorganize(translatedValues); + Utils.printNodeTree("reorganised", reorganizedValues); // 3. Enrich - Enricher.enrich(reorganizedValues); + final List enrichedValues = Enricher.enrich(reorganizedValues).stream().toList(); + Utils.printNodeTree("enriched ", enrichedValues); - return reorganizedValues; + return Collections.unmodifiableCollection(enrichedValues).stream().toList(); } ``` Finally, this translation process file should be registered in two places: - In your class implementing the language-specific sonar visitor class ([`JavaBaseDetectionRule`](../java/src/main/java/com/ibm/plugin/rules/detection/JavaBaseDetectionRule.java) in Java), mentioned in [here](#the-check-registrar-extension-point). -- In your `TestBase` class ([`TestBase`](../java/src/test/java/com/ibm/plugin/TestBase.java) in Java), mentioned in [here](#organizing-your-files). Also makes sure to log the translated tree of findings by calling `Utils.printNodeTree(List nodes)` at the right place (with `Utils` from `com.ibm.mapper.utils`). +- In your `TestBase` class ([`TestBase`](../java/src/test/java/com/ibm/plugin/TestBase.java) in Java), mentioned in [here](#organizing-your-files). You can now run again your unit test to check whether your detected values are correctly translated. -If your implementation works, you should observe logs displaying the translated (and potentially reorganized) trees, after the initial logs of the detected values. +If your implementation works, you should observe logs displaying the translated (and potentially reorganized/enriched) trees, after the initial logs of the detected values. ### Writing assert statements @@ -560,7 +586,7 @@ For this, we advise writing exhaustive assert statements for each unit test, che You can look into existing unit tests to know how these assert statements are written. If you have to write a lot of assert statements for a lot of detection rules, you may want to automate this process. -While we do not provide a generic methodology to do so, we have done it for Java, with [`GenerateAssertsHelper`](../java/src/test/java/com/ibm/plugin/utils/GenerateAssertsHelper.java) (documented in its file), which can easily be reused for another language, requiring only minor modifications. +While we do not provide a generic methodology to do so, we have done it for Java (and Python), with [`GenerateAssertsHelper`](../java/src/test/java/com/ibm/plugin/utils/GenerateAssertsHelper.java) (documented in its file), which can easily be reused for another language, requiring only minor modifications. ### Going further: using graph visualization to better understand dependent detection rules diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index 2858b139..1431b52e 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -4,7 +4,7 @@ If you are new to SonarQube, or if you did not manage to obtain results with our ## Installing SonarQube with the plugin > [!IMPORTANT] -> Make sure you use a version of SonarQube supported by our plugin. Currently, SonarQube versions `10.5` and above (including the latest) version are not supported, and we advise installing SonarQube `10.4`. +> Make sure you use a version of SonarQube supported by our plugin. See [here](../README.md#version-compatibility). ### If you already have a SonarQube instance Follow the [Installation](../README.md#installation) paragraph of the main [`README.md`](../README.md) to add the latest released plugin to your SonarQube instance. @@ -16,7 +16,7 @@ In this case, we advise you to use our [`docker-compose.yaml`](../docker-compose To do so, start by opening this repo and `git checkout` to the latest release branch (for example, at the time of writing this document, it is `release/1.2.0`). -Open the [`docker-compose.yaml`](../docker-compose.yaml) file and check the `image` argument to make sure that it uses a version of SonarQube supported by our plugin. In our case, yes, it is `sonarqube:10.4-community`. +Open the [`docker-compose.yaml`](../docker-compose.yaml) file and check the `image` argument to make sure that it uses a version of SonarQube supported by our plugin. You then need to have a `.jar` plugin in the `.SonarQube/plugins/` directory. There are two options for this: - Easiest way: download the `.jar` file from the [latest releases](https://github.com/IBM/sonar-cryptography/releases) GitHub page and move it to this directory. In our case, it is named `sonar-cryptography-plugin-1.2.0.jar`. @@ -35,7 +35,6 @@ You should then be able to access the SonarQube UI at `http://localhost:9000`. #### Managing your own Docker installation Alternatively, you can follow these [SonarQube instructions](https://docs.sonarsource.com/sonarqube/latest/setup-and-upgrade/install-the-server/installing-sonarqube-from-docker/) to manage your own Docker installation. -Make sure to use the right version of the Docker image (we advise using `sonarqube:10.4-community`). --- diff --git a/docs/images/reorganization.png b/docs/images/reorganization.png index e89db43f..f88cc627 100644 Binary files a/docs/images/reorganization.png and b/docs/images/reorganization.png differ diff --git a/docs/images/rules.png b/docs/images/rules.png new file mode 100644 index 00000000..7db38b73 Binary files /dev/null and b/docs/images/rules.png differ diff --git a/docs/images/translation.png b/docs/images/translation.png index fd5e331a..70eab1ae 100644 Binary files a/docs/images/translation.png and b/docs/images/translation.png differ diff --git a/java/src/main/java/com/ibm/plugin/translation/JavaTranslationProcess.java b/java/src/main/java/com/ibm/plugin/translation/JavaTranslationProcess.java index 54e6aadb..dc2a64f8 100644 --- a/java/src/main/java/com/ibm/plugin/translation/JavaTranslationProcess.java +++ b/java/src/main/java/com/ibm/plugin/translation/JavaTranslationProcess.java @@ -27,7 +27,6 @@ import com.ibm.mapper.reorganizer.Reorganizer; import com.ibm.mapper.utils.Utils; import com.ibm.plugin.translation.translator.JavaTranslator; -import java.util.Collection; import java.util.Collections; import java.util.List; import javax.annotation.Nonnull; @@ -61,8 +60,8 @@ public JavaTranslationProcess(@Nonnull List reorganizerRules) Utils.printNodeTree("reorganised", reorganizedValues); // 3. Enrich - final Collection enrichedValues = Enricher.enrich(reorganizedValues); - Utils.printNodeTree("enriched ", reorganizedValues); + final List enrichedValues = Enricher.enrich(reorganizedValues).stream().toList(); + Utils.printNodeTree("enriched ", enrichedValues); return Collections.unmodifiableCollection(enrichedValues).stream().toList(); } diff --git a/python/src/main/java/com/ibm/plugin/translation/PythonTranslationProcess.java b/python/src/main/java/com/ibm/plugin/translation/PythonTranslationProcess.java index 3ada60c7..cb165365 100644 --- a/python/src/main/java/com/ibm/plugin/translation/PythonTranslationProcess.java +++ b/python/src/main/java/com/ibm/plugin/translation/PythonTranslationProcess.java @@ -27,7 +27,6 @@ import com.ibm.mapper.reorganizer.Reorganizer; import com.ibm.mapper.utils.Utils; import com.ibm.plugin.translation.translator.PythonTranslator; -import java.util.Collection; import java.util.Collections; import java.util.List; import org.jetbrains.annotations.NotNull; @@ -59,8 +58,8 @@ public PythonTranslationProcess(@NotNull List reorganizerRules Utils.printNodeTree("reorganised ", reorganizedValues); // 3. Enrich - final Collection enrichedValues = Enricher.enrich(reorganizedValues); - Utils.printNodeTree(" enriched ", reorganizedValues); + final List enrichedValues = Enricher.enrich(reorganizedValues).stream().toList(); + Utils.printNodeTree(" enriched ", enrichedValues); return Collections.unmodifiableCollection(enrichedValues).stream().toList(); }