Skip to content

Commit

Permalink
gitleaks:bugfix - updating formatter to gitleaks v8
Browse files Browse the repository at this point in the history
When the v8 version of gitaleks was released, the way to do an analysis
and the output of that analysis changed. This pr updates the formatter
to the new format and updates gitleaks to v8.3.0. It also contains some
improvements in the formatter code.

Signed-off-by: Nathan Martins <nathan.martins@zup.com.br>
  • Loading branch information
nathanmartinszup committed Mar 4, 2022
1 parent 345c748 commit a7462c0
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 75 deletions.
1 change: 1 addition & 0 deletions e2e/analysis/test_case.go
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,7 @@ func NewTestCase() []*TestCase {
fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.GitLeaks, languages.Leaks),
fmt.Sprintf("{HORUSEC_CLI} Running %s - %s", tools.HorusecEngine, languages.Leaks),
fmt.Sprintf("{HORUSEC_CLI} %s - %s is finished in analysisID:", tools.HorusecEngine, languages.Leaks),
fmt.Sprintf("{HORUSEC_CLI} The current path it's not a valid git repository"),
},
OutputsNotContains: []string{
fmt.Sprintf("{HORUSEC_CLI} Something error went wrong in %s tool", tools.GitLeaks),
Expand Down
3 changes: 2 additions & 1 deletion internal/controllers/analyzer/analyzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,5 +452,6 @@ func (a *Analyzer) isWarning(err string) bool {
return strings.Contains(err, messages.MsgErrorPacketJSONNotFound) ||
strings.Contains(err, messages.MsgErrorYarnLockNotFound) ||
strings.Contains(err, messages.MsgErrorGemLockNotFound) ||
strings.Contains(err, messages.MsgErrorNotFoundRequirementsTxt)
strings.Contains(err, messages.MsgErrorNotFoundRequirementsTxt) ||
strings.Contains(err, messages.MsgWarnPathIsInvalidGitRepository)
}
2 changes: 1 addition & 1 deletion internal/enums/images/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const (
Go = "horuszup/horusec-go:v1.2.1"
HCL = "horuszup/horusec-hcl:v1.1.0"
Javascript = "horuszup/horusec-js:v1.2.0"
Leaks = "horuszup/horusec-leaks:v1.1.0"
Leaks = "horuszup/horusec-leaks:v1.2.0"
PHP = "horuszup/horusec-php:v1.0.1"
Python = "horuszup/horusec-python:v1.0.0"
Ruby = "horuszup/horusec-ruby:v1.1.1"
Expand Down
1 change: 1 addition & 0 deletions internal/helpers/messages/warn.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,5 @@ const (
// TODO: Remove MsgWarnAnalysisContainsOutdatedHash before release v2.10.0
MsgWarnAnalysisContainsOutdatedHash = "{HORUSEC_CLI} YOUR CONFIGURATION FILE CONTAINS SOME HASHES THAT WILL NO " +
"LONGER BE VALID AS OF v2.10.0 IS RELEASED. PLEASE UPDATE YOUR CONFIGURATION FILE WITH THE FOLLOWING HASHES:"
MsgWarnPathIsInvalidGitRepository = "{HORUSEC_CLI} The current path it's not a valid git repository"
)
2 changes: 1 addition & 1 deletion internal/services/formatters/leaks/deployments/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

FROM zricethezav/gitleaks:v8.2.7
FROM zricethezav/gitleaks:v8.3.0

COPY ./internal/services/formatters/leaks/deployments/rules.toml /rules/rules.toml

Expand Down
16 changes: 9 additions & 7 deletions internal/services/formatters/leaks/gitleaks/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//nolint
package gitleaks

// CMD contains the necessary code to execute Gitleaks inside the container. The 'git config diff.renames 0' command
// it's necessary to avoid the 'inexact rename detection was skipped due to too many files' error in big projects.
const CMD = `
{{WORK_DIR}}
if ! gitleaks --config-path /rules/rules.toml --path . --leaks-exit-code 0 --format json --report /tmp/leaks-result.json &> /tmp/leaks-runner-output.txt; then
echo /tmp/leaks-runner-output.txt
else
cat /tmp/leaks-result.json
fi
{{WORK_DIR}}
git config diff.renames 0
if ! gitleaks detect -c /rules/rules.toml -f json -r /tmp/leaks.json --exit-code 0 &> /tmp/leaks-output.txt; then
cat /tmp/leaks-output.txt
else
cat /tmp/leaks.json
fi
`
101 changes: 48 additions & 53 deletions internal/services/formatters/leaks/gitleaks/formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package gitleaks
import (
"encoding/json"
"errors"
"strconv"
"strings"

"github.com/ZupIT/horusec-devkit/pkg/entities/vulnerability"
Expand All @@ -29,7 +30,6 @@ import (
"github.com/ZupIT/horusec/internal/enums/images"
"github.com/ZupIT/horusec/internal/helpers/messages"
"github.com/ZupIT/horusec/internal/services/formatters"
"github.com/ZupIT/horusec/internal/services/formatters/leaks/gitleaks/entities"
vulnhash "github.com/ZupIT/horusec/internal/utils/vuln_hash"
)

Expand Down Expand Up @@ -62,78 +62,73 @@ func (f *Formatter) startGitLeaks(projectSubPath string) (string, error) {
return output, err
}

return output, f.formatOutputGitLeaks(output)
if err := f.checkOutputErrors(output); err != nil {
return output, err
}

return output, f.parseOutput(output)
}

func (f *Formatter) formatOutputGitLeaks(output string) error {
if output == "" || (len(output) >= 4 && output[:4] == "null") {
func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData {
analysisData := &dockerEntities.AnalysisData{
CMD: f.AddWorkDirInCmd(CMD, projectSubPath, tools.GitLeaks),
Language: languages.Leaks,
}

return analysisData.SetImage(f.GetCustomImageByLanguage(languages.Leaks), images.Leaks)
}

func (f *Formatter) parseOutput(output string) error {
issues := make([]*Issue, 0)

if err := json.Unmarshal([]byte(output), &issues); err != nil {
return err
}

if len(issues) == 0 {
logger.LogDebugWithLevel(messages.MsgDebugOutputEmpty,
map[string]interface{}{"tool": tools.GitLeaks.ToString()})
f.setGitLeaksOutPutInHorusecAnalysis([]entities.Issue{})
return nil
}

issues, err := f.parseOutputToIssues(output)
if err != nil {
return err
}
f.forEachIssueCreateNewVuln(issues)

f.setGitLeaksOutPutInHorusecAnalysis(issues)
return nil
}

func (f *Formatter) parseOutputToIssues(output string) ([]entities.Issue, error) {
var issues []entities.Issue
err := json.Unmarshal([]byte(output), &issues)
if err != nil && strings.Contains(err.Error(), "invalid character") {
err = errors.New(output)
}
return issues, err
}

func (f *Formatter) setGitLeaksOutPutInHorusecAnalysis(issues []entities.Issue) {
for key := range issues {
vuln := f.setupVulnerabilitiesSeveritiesGitLeaks(&issues[key])
f.AddNewVulnerabilityIntoAnalysis(vuln)
func (f *Formatter) forEachIssueCreateNewVuln(issues []*Issue) {
for _, issue := range issues {
f.AddNewVulnerabilityIntoAnalysis(f.newVulnerability(issue))
}
}

func (f *Formatter) setupVulnerabilitiesSeveritiesGitLeaks(issue *entities.Issue) (
vulnerabilitySeverity *vulnerability.Vulnerability,
) {
vulnerabilitySeverity = f.getDefaultSeverity()
vulnerabilitySeverity.Severity = severities.Critical
vulnerabilitySeverity.RuleID = vulnhash.HashRuleID(issue.Rule)
vulnerabilitySeverity.Details = issue.Rule
vulnerabilitySeverity.Code = f.GetCodeWithMaxCharacters(issue.Line, 0)
vulnerabilitySeverity.File = issue.File
vulnerabilitySeverity = vulnhash.Bind(vulnerabilitySeverity)
return f.setCommitAuthor(vulnerabilitySeverity, issue)
}

func (f *Formatter) setCommitAuthor(vuln *vulnerability.Vulnerability,
issue *entities.Issue,
) *vulnerability.Vulnerability {
//nolint:funlen // necessary to be long
func (f *Formatter) newVulnerability(issue *Issue) *vulnerability.Vulnerability {
vuln := &vulnerability.Vulnerability{}

vuln.Language = languages.Leaks
vuln.SecurityTool = tools.GitLeaks
vuln.Severity = severities.Critical
vuln.RuleID = vulnhash.HashRuleID(issue.Description)
vuln.Details = issue.Description
vuln.Code = f.GetCodeWithMaxCharacters(issue.Secret, 0)
vuln.File = issue.File
vuln.Line = strconv.Itoa(issue.StartLine)
vuln.Column = strconv.Itoa(issue.StartColumn)
vuln.CommitAuthor = issue.Author
vuln.CommitMessage = strings.ReplaceAll(issue.CommitMessage, "\n", "")
vuln.CommitMessage = f.GetCodeWithMaxCharacters(issue.Message, 0)
vuln.CommitEmail = issue.Email
vuln.CommitDate = issue.Date
vuln.CommitHash = issue.Commit
return vuln

return vulnhash.Bind(vuln)
}

func (f *Formatter) getDockerConfig(projectSubPath string) *dockerEntities.AnalysisData {
analysisData := &dockerEntities.AnalysisData{
CMD: f.AddWorkDirInCmd(CMD, projectSubPath, tools.GitLeaks),
Language: languages.Leaks,
func (f *Formatter) checkOutputErrors(output string) error {
if strings.Contains(output, "fatal: not a git repository") ||
strings.Contains(output, "fatal: cannot chdir to") {
return errors.New(messages.MsgWarnPathIsInvalidGitRepository)
}

return analysisData.SetImage(f.GetCustomImageByLanguage(languages.Leaks), images.Leaks)
}

func (f *Formatter) getDefaultSeverity() *vulnerability.Vulnerability {
vulnerabilitySeverity := &vulnerability.Vulnerability{}
vulnerabilitySeverity.Language = languages.Leaks
vulnerabilitySeverity.SecurityTool = tools.GitLeaks
return vulnerabilitySeverity
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package entities
package gitleaks

type Issue struct {
Line string `json:"line"`
Offender string `json:"offender"`
Commit string `json:"commit"`
Repo string `json:"repo"`
Rule string `json:"rule"`
CommitMessage string `json:"commitMessage"`
Author string `json:"author"`
Email string `json:"email"`
File string `json:"file"`
Date string `json:"date"`
Tags string `json:"tags"`
Description string
StartLine int
EndLine int
StartColumn int
EndColumn int
Match string
Secret string
File string
Commit string
Entropy int
Author string
Email string
Date string
Message string
}

0 comments on commit a7462c0

Please # to comment.