Como adicionar uma nova ferramenta usando Horusec-engine?

Nesta seção, você encontra o tutorial para adicionar ferramentas pelo Horusec-engine.

O Horusec permite que você adicione ferramentas à sua stack usando o próprio motor (Horusec-engine).

Como fazer?

Para incluir uma nova ferramenta de análise ao Horusec-CLI, siga os passos abaixo:

Passo 1: Crie as regras do motor

Você precisa criar regras para que o motor do Horusec funcione. Elas são regexes que detectam a vulnerabilidades.

Os regexes possuem tipos, veja abaixo quais:

Tipo Descrição
OrMatch Essas são regras mais compreensivas, o que pode ter mais de um padrão a ser manifesto, por isso o nome. O motor irá realizar a lógica OU a operação para cada um dos RegExps registrados.
Regular É bem similar ao OrMatch, mas contém múltiplos caminhos para detectar o mesmo padrão.
AndMatch Essas regras precisam de um arquivo para manifestar múltiplos padrões para serem considerados como algo a ser reportado. No entanto, o motor realiza a operação lógica em cada RegExps registrado, para garantir que todas as condições foram alcançadas.
NotMatch São regras que precisam que o arquivo manifeste nenhum padrão e com isso ser considerado como algo a ser reportado. Portanto, a engine realiza a operação lógica em cada uma das RegExps cadastradas para garantir que todas as condições não foram encontradas.

Alguns exemplos dessas regras podem ser encontrados no projeto Horusec-CLI, no diretório: internal/services/engines

 -internal/
 ---services/
 -----engines/

Passo 2: Crie o formatter

Você precisa chamar o motor passando as regras e formatar para o padrão Horusec. Para isso, é necessário criar o formatter, veja como no exemplo abaixo:


func NewFormatter(service formatters.IService) formatters.IFormatter {
	return formatters.NewDefaultFormatter(service, csharp.NewRules(), languages.CSharp)
}

O exemplo pode ser encontrado nesses caminhos:

 -internal/
 ---services/
 -----fomatters/
 -------chsarp/
 ---------horuseccsharp/
 -----------fomatter.go

Como o arquivo funciona?

Nesse arquivo foi criado um formatter default, utilizado em todas as engines do Horusec. As regras e a linguagem foram alteradas para ajustar as que o formatter suporta.

Passo 3: Atualize os Enums se for uma nova linguagem

Você também precisa adicionar a linguagem que ainda não é suportada pelo Horusec ao Enum de linguagens.

Veja os passos para a atualização abaixo:

Se for uma linguagem que o Horusec ainda não tem suporte:

  1. Adicione a nova linguagem no projeto Horusec-DevKit no diretório:
 -pkg/
 ---enums/
 -----languages/
 -------language.go
  1. Além de adicionar o enum, você precisa atualizar os métodos no mesmo arquivo com a nova linguagem:
  • func Values() []Language
  • func mapEnableLanguages() map[string]Language
  • func MapLanguagesEnableInCLI() map[Language]string
  1. Depois, adicione a nova linguagem na funcionalidade workdir no projeto Horusec-CLI no diretório:
 -internal/
 ---entities/
 -----workdir/
 -------workdir.go

Como por exemplo:

type WorkDir struct {
  ...
  Csharp []string `json:"csharp"`
  ...
}
  1. E para finalizar, altere os métodos com as linguagens:
  • func NewWorkDir() *WorkDir
  • func (w *WorkDir) LanguagePaths() map[languages.Language][]string
  • func (w *WorkDir) setEmptyOrSliceEmptyInNilContent() *WorkDir

Passo 4: Chamando o Formatter

Se você adicionou uma nova linguagem, atualize a versão do Horusec-DevKit nos pacotes da Horusec-CLI, para que o projeto consiga extrair e utilizar a nova linguagem.

Logo em seguida, você deve chamar a função no analyzer controller.

Veja o seguinte path:

 -internal
 ---controller
 -----analyzer
 -------analyzer.go

Quando o Horusec inicia sua análise, ele identifica as linguagens do projeto e faz um comparativo se tem alguma linguagem que está halitada a realizar uma análise. Caso tenha, ele irá enviar para o analyzer controller quais são as linguagens que devem ser acionadas na análise.

Veja abaixo como chamar a implementação do formatter no analyzer controller.

É uma nova linguagem?

Se sim, será necessário criar uma nova função para detectar as vulnerabilidades daquela linguagem. Veja o exemplo abaixo:

func (a *Analyzer) detectVulnerabilityCsharp(wg *sync.WaitGroup, projectSubPath string) error {
    horuseccsharp.NewFormatter(a.formatterService).StartAnalysis(projectSubPath)
    return nil
}

Você também precisa adicionar uma nova linguagem ao mapa que contém a função detectVulnerabilityFuncs. Veja o exemplo:

func (a *Analyzer) detectVulnerabilityFuncs() map[languages.Language]func(string) {
	return map[languages.Language]func(string){
				...
		languages.Csharp: a.detectVulnerabilityCsharp,
	}
}

É uma linguagem existente?

Se sim, apenas adicione a chamada do novo formatter na função já existente detectVulnerability[LANGUAGE].

Veja como era antes de você adicionar:

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
}

Veja depois que você adicionou:

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
}

Passo 5: Atualize as validações

Agora, para finalizar, é necessário atualizar as validações do Horusec.

Quando a Horusec-CLI envia uma análise para a sua aplicação web, alguns projetos realizam validações para conferir se os dados estão de acordo com o esperado.

Para isso vá até o projeto Horusec-Platform e atualize no serviço API o caso de uso para aceitar a nova ferramenta e a linguagem no diretório:

 -api/
 ---internal/
 -----usecases/
 -------analysis/
 ---------analysis.go
  • Se você adicionou uma linguagem nova, adicione no metodo func (au *UseCases) sliceLanguages() []interface{} como por exemplo:
func (au *UseCases) sliceLanguages() []interface{} {
	return []interface{}{
    ...
		tools.Csharp,
	}
}