| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package sources
- import (
- "io/fs"
- "os"
- "path/filepath"
- "runtime"
- "github.com/fatih/semgroup"
- "github.com/zricethezav/gitleaks/v8/config"
- "github.com/zricethezav/gitleaks/v8/logging"
- )
- type ScanTarget struct {
- Path string
- Symlink string
- VirtualPath string
- Source string
- // The following items are only used for git archive scans
- // (since we have to treat them like regular dir scans)
- GitInfo GitInfo
- // TODO one day use a single Metadata map
- // instead of git fields
- // Metadata map[string]string
- }
- var isWindows = runtime.GOOS == "windows"
- func DirectoryTargets(source string, s *semgroup.Group, followSymlinks bool, allowlists []*config.Allowlist) (<-chan ScanTarget, error) {
- paths := make(chan ScanTarget)
- s.Go(func() error {
- defer close(paths)
- return filepath.Walk(source,
- func(path string, fInfo os.FileInfo, err error) error {
- logger := logging.With().Str("path", path).Logger()
- if err != nil {
- if os.IsPermission(err) {
- // This seems to only fail on directories at this stage.
- logger.Warn().Msg("Skipping directory: permission denied")
- return filepath.SkipDir
- }
- return err
- }
- // Empty; nothing to do here.
- if fInfo.Size() == 0 {
- return nil
- }
- // Unwrap symlinks, if |followSymlinks| is set.
- scanTarget := ScanTarget{
- Path: path,
- }
- if fInfo.Mode().Type() == fs.ModeSymlink {
- if !followSymlinks {
- logger.Debug().Msg("Skipping symlink")
- return nil
- }
- realPath, err := filepath.EvalSymlinks(path)
- if err != nil {
- return err
- }
- realPathFileInfo, _ := os.Stat(realPath)
- if realPathFileInfo.IsDir() {
- logger.Warn().Str("target", realPath).Msg("Skipping symlinked directory")
- return nil
- }
- scanTarget.Path = realPath
- scanTarget.Symlink = path
- }
- // TODO: Also run this check against the resolved symlink?
- var skip bool
- for _, a := range allowlists {
- skip = a.PathAllowed(path) ||
- // TODO: Remove this in v9.
- // This is an awkward hack to mitigate https://github.com/gitleaks/gitleaks/issues/1641.
- (isWindows && a.PathAllowed(filepath.ToSlash(path)))
- if skip {
- break
- }
- }
- if fInfo.IsDir() {
- // Directory
- if skip {
- logger.Debug().Msg("Skipping directory due to global allowlist")
- return filepath.SkipDir
- }
- if fInfo.Name() == ".git" {
- // Don't scan .git directories.
- // TODO: Add this to the config allowlist, instead of hard-coding it.
- return filepath.SkipDir
- }
- } else {
- // File
- if skip {
- logger.Debug().Msg("Skipping file due to global allowlist")
- return nil
- }
- paths <- scanTarget
- }
- return nil
- })
- })
- return paths, nil
- }
|