// Copyright 2023 Harness, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package api import ( "fmt" "github.com/zricethezav/gitleaks/v8/detect" "github.com/zricethezav/gitleaks/v8/report" "github.com/zricethezav/gitleaks/v8/sources" ) // Finding contains gitleaks report.finding information. type Finding struct { Description string `json:"description"` StartLine int64 `json:"start_line"` EndLine int64 `json:"end_line"` StartColumn int64 `json:"start_column"` EndColumn int64 `json:"end_column"` Match string `json:"match"` Secret string `json:"secret"` File string `json:"file"` SymlinkFile string `json:"symlink_file"` Commit string `json:"commit"` Entropy float64 `json:"entropy"` Author string `json:"author"` Email string `json:"email"` Date string `json:"date"` Message string `json:"message"` Tags []string `json:"tags"` RuleID string `json:"rule_id"` // unique identifier Fingerprint string `json:"fingerprint"` } // ScanSecrets detects secret leakage using gitleaks on the provided revision, // or on the diff with baseRev if provided (baseRev is optional). func (g *Git) ScanSecrets( repoPath string, baseRev string, rev string, ) ([]Finding, error) { if repoPath == "" { return nil, ErrRepositoryPathEmpty } detector, err := detect.NewDetectorDefaultConfig() if err != nil { return nil, fmt.Errorf("failed to create a new gitleaks detector with default config: %w", err) } var logOpts string logOpts = fmt.Sprintf("--no-merges --first-parent %s", rev) if baseRev != "" { logOpts = fmt.Sprintf("--no-merges --first-parent %s..%s", baseRev, rev) } gitCmd, err := sources.NewGitLogCmd(repoPath, logOpts) if err != nil { return nil, fmt.Errorf("failed to create a new git log cmd with diff: %w", err) } res, err := detector.DetectGit(gitCmd) if err != nil { return nil, fmt.Errorf("failed to detect git leaks on diff: %w", err) } return mapFindings(res), nil } func mapFindings(reports []report.Finding) []Finding { var findings []Finding for _, f := range reports { findings = append(findings, Finding{ Description: f.Description, StartLine: int64(f.StartLine), EndLine: int64(f.EndLine), StartColumn: int64(f.StartColumn), EndColumn: int64(f.EndColumn), Match: f.Match, Secret: f.Secret, File: f.File, SymlinkFile: f.SymlinkFile, Commit: f.Commit, Entropy: float64(f.Entropy), Author: f.Author, Email: f.Email, Date: f.Date, Message: f.Message, Tags: f.Tags, RuleID: f.RuleID, Fingerprint: f.Fingerprint, }) } return findings }