Overview¶
This guide should give you a clear understanding of what Sensei is and how to configure it. The overview will explain some key concepts and guide you to create your first recipe.
How does Sensei work?¶
Sensei is an IDE plugin that performs on the fly code analysis. This behavior is configured in what we call 'recipes'. A recipe consists of four sections.
- Metadata
This section contains the metadata of the recipe, e.g. name, description, category, etc. Most of the information in this section is used to describe a recipe rather than to configure its behavior.
- Search
This section describes the behavior of the recipe, i.e. what code to look for.
- Fix
This section contains all the possible quick fixes (suggestions) for a single recipe. This behavior is invoked when a user places their cursor at a piece of marked code, and clicks on the light bulb or presses the quick fix menu shortcut.
- Documentation
To make sure your recipe informs the developers that use it, you can add a detailed description in this final section. A good description contains an example of what code the search can find, how the quick fix is applied and some references to elaborate further on the topic of the recipe.
How are recipes stored?¶
Recipes are stored in what we call 'cookbooks'. Technically, a cookbook is simply a directory that contains a configuration file and recipes, with optionally subdirectories to group recipes and to store descriptions. Cookbooks can be either in the form of a directory or that of a ZIP file depending on where these are loaded from.
This leads directly to our second topic: recipe distribution. Cookbooks can be stored in numerous places.
Local Path
HTTP(S) server
Git repository
Inside the project
Note
In the tutorials, recipes will always be stored inside the project.
Configuring which cookbooks Sensei should load, can be done locally or remotely (if you have company administrator rights at https://portal.securecodewarrior.com). During IntelliJ startup both of these configurations are read. Afterwards, Sensei itself will load the recipes from these locations. This implies that you can remotely configure to load local recipes.
Note
Free authenticated Sensei users will have the "Basic Protection Cookbook"
configured as a default remote cookbook named basic-protection-set
.
Non-authenticated users will have the "Basic Protection Cookbook"
configured as a default remote cookbook named basic-protection-set
.
- Local settings
Open your IDE and navigate to Tools | Sensei | Cookbook Manager.
- Remote settings
As mentioned before, this requires company administration access to find and tweak these settings. If you have administrator rights, these settings can be found by logging in at the Secure Code Warrior portal and navigating to Administration | Preferences | Rule Settings.
See also
For more information, see How to distribute recipes
What to search for?¶
To understand how the search engine works, we'll start by explaining some key concepts.
search: # start of our recipe
methodcall: # example of a target
name: "equals" # example of an option
The above example is a very simple recipe that you can write in Sensei. The first keyword of every
recipe should be search
. This tells the engine that we will be searching for a specific target. In
this example, we are looking for a methodcall
. Each target can also be configured to match only
specific elements. In this case, only method calls that have the name equals
will match the
configured recipe.
See also
The list of available targets can be found at reference > targets.
Each option has its own way of being configured. Some of these will require you to simply specify a string or a boolean value. Others will expect another target configuration. For example:
search:
methodcall:
name: "equals"
on: # example of an option that expects a target configuration
methodcall: # second configured target
name: "toLowerCase" # option of our second target
See also
All these options are described in the reference section for each of the available targets. To find the list of available options for the target used, visit reference > targets > methodcall.
A quick recap of what we've learned.
Recipes start with the keyword
search
Next, specify what you are looking for by choosing one of the available targets
Finally, targets can be configured using the available options. Some of these options expect primitives values, while others expect other target configurations.
How to make suggestions?¶
Suggestions can be configured in the fix tab. Any recipe has the ability to configure multiple suggestions. Each of these consist of the name that will be shown to the user and a list of actions that will be performed when invoking the quick fix.
availableFixes: # List of all suggestions
- name: "Remove statement" # Name that will be shown to the user
actions:
- remove: # currently only a single action will be performed
See also
The list of available actions can be found at reference > actions.
These actions will by default operate on the element that matches the target specification. In the majority of cases, you'll want to perform multiple actions that modify other parts of the file.
availableFixes:
- name: "Use instance variable" # Name that will be shown to the user
actions:
- rewrite: # First action that will be performed
to: "this.heavyObject"
- addField: # Second action that will be performed
field: "Heavy heavyObject;"
target: "parentClass" # Tells the action to operate on the class
To recap, each recipe can have multiple suggestions. Each suggestion has a name
that is shown to the
user, and a list of actions
. These actions operate by default on the matched element, but this
behavior can be changed by specifying the target
.
Let's get practical¶
Now that the basic concepts have been covered, we can go through a few examples that explain certain details a bit more in-depth. We will address the following topics:
What element should I look for?
How the search influences the quick fix actions
Making recipes more generic by using regular expressions and logical operators.
Narrowing down when a recipe should trigger by scoping
Continue with: Writing a recipe, part 1