How to add a new tool using Horusec-Engine?

In this section, you will find how to add existing images to 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:
  1. Add a new language in Horusec-DevKit project in the directory:
 -pkg/
 ---enums/
 -----languages/
 -------language.go
  1. 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
  1. 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"`
  ...
}
  1. 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
}

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,
	}
}