How to add a new tool using Horusec-Engine?
Horusec allows you to add tools its own engine. (Horusec-engine).
How can you do it?
To include a new analysis tool to Horusec-CLI, follow the steps below:
Step 1: Create the engine rules
You need to create rules so the Horusec engine works. These rules are regexes that detects vulnerabilites.
The regexes have types, see on the table below what they are:
Type | Description |
---|---|
OrMatch | These are more comprehensive rules, that can have more than one pattern to be manifested, that’s why this name. The engine will make the logic OR an operation to each of the registred RegExps. |
Regular | It is similar to OrMatch, but has multiple paths to detect the same pattern. |
AndMatch | These rules need a file to manifest multiple patterns to be considered as something to be reported. However, the engine makes a logical operation in each registered RegExps to ensure that all conditions have been reached. |
NotMatch | These rules need a file to manifest any pattern and with that it can be considered as something to be reported. However, the engine performes logical operation in each registered RegExps to make sure all the conditions were not found. |
Some examples of these rules can be found in the project Horusec-CLI, in the directory:
internal/services/engines
-internal/
---services/
-----engines/
Step 2: Create a formatter
You need to call an engine passing the rules and format the Horusec pattern. To do so, it is necessary to create a formatter, see the example below:
func NewFormatter(service formatters.IService) formatters.IFormatter {
return formatters.NewDefaultFormatter(service, csharp.NewRules(), languages.CSharp)
}
The example can be found in these paths:
-internal/
---services/
-----fomatters/
-------leaks/
---------horusecleaks/
-----------fomatter.go
How does the file work?
In this file a default formatter was created, it will be used in all Horusec engines. The rules and language were changed to adjust what the formatter supports.
Step 3: Update the Enums if it is a new language
You can also add the languages not supported by Horusec to the Enum of languages.
See the steps to update below:
If it is a language Horusec does not support yet
- Follow the steps:
- Add a new language in Horusec-DevKit project in the directory:
-pkg/
---enums/
-----languages/
-------language.go
- After adding the enum , you need to update the methods in the same file with the new language:
func Values() []Language
func mapEnableLanguages() map[string]Language
func MapLanguagesEnableInCLI() map[Language]string
- After that, add the new language in the workdir functionality in Horusec-CLI project in the directory:
-internal/
---entities/
-----workdir/
-------workdir.go
See the example:
type WorkDir struct {
...
Csharp []string `json:"csharp"`
...
}
- To finish, change the methods with the languages:
func NewWorkDir() *WorkDir
func (w *WorkDir) LanguagePaths() map[languages.Language][]string
func (w *WorkDir) setEmptyOrSliceEmptyInNilContent() *WorkDir
Step 4: Call the formatter
If you’ve added a new language, update the Horusec-DevKit version in the Horusec-CLI packages, so the project is able to extract and use the new language.
After that, you have to call the function in the analyzer controller.
See the following path:
-internal
---controller
-----analyser
-------analyser.go
When Horusec starts the analysis, it identifies the project’s languages and compares if there is one able to perform an analysis. It there is one, it will send to the analyzer controller which languages must be enabled in the analysis.
See below how to call the formatter implementation in the analyzer controller.
Is it a new language?
If yes, it will be necessary to create a new function to detect the vulnerabilities in the language. See the example below:
func (a *Analyzer) detectVulnerabilityCsharp(wg *sync.WaitGroup, projectSubPath string) error {
horuseccsharp.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
return nil
}
You can also add a new language to the map containing the detectVulnerabilityFuncs
function. See the example:
func (a *Analyser) detectVulnerabilityFuncs() map[languages.Language]func(string) {
return map[languages.Language]func(string){
...
languages.Csharp: a.detectVulnerabilityCsharp,
}
}
Is it an existing language?
If it is, just add a call for a new formatter on the detectVulnerability[LANGUAGE]
existing function.
See how it was before you add it:
func (a *Analyzer) detectVulnerabilityCsharp(wg *sync.WaitGroup, projectSubPath string) {
if err := a.dockerSDK.PullImage(a.getCustomOrDefaultImage(languages.CSharp)); err != nil {
return err
}
scs.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
return nil
}
Now, check out after you’ve added:
func (a *Analyzer) detectVulnerabilityCsharp(wg *sync.WaitGroup, projectSubPath string) error {
spawn(wg, horuseccsharp.NewFormatter(a.formatterService), projectSubPath)
if err := a.dockerSDK.PullImage(a.getCustomOrDefaultImage(languages.CSharp)); err != nil {
return err
}
scs.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
return nil
}
All analyzes are executed in parallel.If the function performing the analysis runs only one tool is not necessary to use GO Routine or call the spawn
function because it will already be running in parallel, but if necessary to run multiple analyzes within a it is recommended that you use the spawn
function for each complementary analysis.
In this scenario, Horusec engine does not have any dependency with docker. It is not necessary to wait to download the image, it can be executed before the download starts. When the download ends, the other tools that have this dependency with docker will be executed.
Step 5: Update the validations
Now, to finish, it is necessary update Horusec’s validations. When Horusec-CLI sends an analysis to the web application, some projects perform validations to check if the data is what you expected.
For that, go to Horusec-Platform project and update in the API service the use case, in order to accept the new tool and language in the directory:
-api/
---internal/
-----usecases/
-------analysis/
---------analysis.go
- If you added a new language add the method
func (au *UseCases) sliceLanguages() []interface{}
as the example below:
func (au *UseCases) sliceLanguages() []interface{} {
return []interface{}{
...
tools.Csharp,
}
}
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.