Просмотр исходного кода

Merge branch 'master' into fix_default_config

amith-legit 4 лет назад
Родитель
Сommit
be13bba64c
67 измененных файлов с 509 добавлено и 237 удалено
  1. 0 1
      .github/FUNDING.yml
  2. 16 0
      .github/ISSUE_TEMPLATE/maintenance.md
  3. 40 0
      .github/workflows/test.yml
  4. 1 0
      .gitignore
  5. 0 8
      .travis.yml
  6. 5 10
      Dockerfile
  7. 8 11
      Makefile
  8. 68 55
      README.md
  9. 5 1
      config/config.go
  10. 2 8
      config/gitleaks.toml
  11. 60 14
      config/rule.go
  12. 1 1
      examples/leaky-repo.toml
  13. 3 5
      go.mod
  14. 56 40
      go.sum
  15. 18 6
      options/options.go
  16. 2 2
      scan/commit.go
  17. 2 3
      scan/filesatcommit.go
  18. 26 17
      scan/leak.go
  19. 24 22
      scan/nogit.go
  20. 9 12
      scan/repo.go
  21. 15 15
      scan/report.go
  22. 2 0
      scan/sarif.go
  23. 5 1
      scan/scan_test.go
  24. 11 5
      scan/unstaged.go
  25. 1 0
      test_data/test_additional_config.json
  26. 5 0
      test_data/test_allow_list_docx_no_git.json
  27. 1 0
      test_data/test_allow_list_file.json
  28. 2 0
      test_data/test_allow_list_file_no_git.json
  29. 1 0
      test_data/test_append_repo.json
  30. 2 0
      test_data/test_dir1_aws_leak.json
  31. 1 0
      test_data/test_entropy.json
  32. 1 0
      test_data/test_file1_aws_leak.json
  33. 23 0
      test_data/test_local_owner_aws_leak.json
  34. 22 0
      test_data/test_local_owner_aws_leak_allowlist_repo.json
  35. 7 0
      test_data/test_local_owner_aws_leak_depth_2.json
  36. 3 0
      test_data/test_local_repo_eight.json
  37. 1 0
      test_data/test_local_repo_five_at_latest_commit.json
  38. 1 0
      test_data/test_local_repo_five_commit.json
  39. 2 0
      test_data/test_local_repo_five_files_at_commit.json
  40. 2 0
      test_data/test_local_repo_five_files_at_latest_commit.json
  41. 2 0
      test_data/test_local_repo_four_alt_config_entropy.json
  42. 2 0
      test_data/test_local_repo_four_leaks_commit_timerange.json
  43. 1 0
      test_data/test_local_repo_nine_aws_leak.json
  44. 1 0
      test_data/test_local_repo_one_aws_leak.json
  45. 1 0
      test_data/test_local_repo_one_aws_leak_and_file_leak.json
  46. 1 0
      test_data/test_local_repo_one_aws_leak_commit.json
  47. 1 0
      test_data/test_local_repo_one_aws_leak_uncommitted.json
  48. 1 0
      test_data/test_local_repo_seven_aws_leak_uncommitted.json
  49. 3 0
      test_data/test_local_repo_six.json
  50. 2 0
      test_data/test_local_repo_six_filename.json
  51. 1 0
      test_data/test_local_repo_six_filepath.json
  52. 1 0
      test_data/test_local_repo_six_filepath_filename.json
  53. 1 0
      test_data/test_local_repo_six_leaks_since_date.json
  54. 1 0
      test_data/test_local_repo_six_leaks_until_date.json
  55. 1 0
      test_data/test_local_repo_six_path_globally_allowlisted.json
  56. 4 0
      test_data/test_local_repo_three_leaks.json
  57. 3 0
      test_data/test_local_repo_three_leaks_with_report_groups.json
  58. 1 0
      test_data/test_local_repo_two_allowlist_commits.json
  59. 3 0
      test_data/test_local_repo_two_leaks.json
  60. 2 0
      test_data/test_local_repo_two_leaks_commit_from.json
  61. 2 0
      test_data/test_local_repo_two_leaks_commit_range.json
  62. 1 0
      test_data/test_local_repo_two_leaks_commit_to.json
  63. 1 0
      test_data/test_local_repo_two_leaks_commit_to_from.json
  64. 6 0
      test_data/test_local_repo_two_leaks_deletion.json
  65. 2 0
      test_data/test_local_repo_two_leaks_file_commit_range.json
  66. 9 0
      test_data/test_only_files_no_git.json
  67. 1 0
      test_data/test_regex_entropy.json

+ 0 - 1
.github/FUNDING.yml

@@ -1,4 +1,3 @@
 # These are supported funding model platforms
 # These are supported funding model platforms
 
 
 github: [zricethezav]
 github: [zricethezav]
-custom: ["https://www.paypal.me/zricethezav"]

+ 16 - 0
.github/ISSUE_TEMPLATE/maintenance.md

@@ -0,0 +1,16 @@
+---
+name: Maintenance request
+about: Suggest an idea for this project
+title: ''
+labels: enhancement
+assignees: ''
+
+---
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
+
+cc @zricethezav

+ 40 - 0
.github/workflows/test.yml

@@ -0,0 +1,40 @@
+name: Test
+
+on:
+  push:
+    branches:
+      - "*"
+  pull_request:
+    branches:
+      - "*"
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    env:
+      GO111MODULE: on
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Set up Go
+      uses: actions/setup-go@v2
+      with:
+        go-version: 1.17
+
+    - name: Build
+      run: go build -v ./...
+
+  test:
+    runs-on: ubuntu-latest
+    env:
+      GO111MODULE: on
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Set up Go
+      uses: actions/setup-go@v2
+      with:
+        go-version: 1.17
+
+    - name: Test
+      run: make test

+ 1 - 0
.gitignore

@@ -6,6 +6,7 @@
 *.dylib
 *.dylib
 *.DS_STORE
 *.DS_STORE
 *.idea
 *.idea
+*.got
 gitleaks
 gitleaks
 build
 build
 
 

+ 0 - 8
.travis.yml

@@ -1,8 +0,0 @@
-language: go
-go:
-  - 1.16.x
-services:
-  - docker
-script:
-  - make test
-  - make security-scan

+ 5 - 10
Dockerfile

@@ -1,17 +1,12 @@
-FROM golang:1.15.5 AS build
+FROM golang:1.17 AS build
 WORKDIR /go/src/github.com/zricethezav/gitleaks
 WORKDIR /go/src/github.com/zricethezav/gitleaks
 ARG ldflags
 ARG ldflags
 COPY . .
 COPY . .
 RUN GO111MODULE=on CGO_ENABLED=0 go build -o bin/gitleaks -ldflags "-X="${ldflags} *.go 
 RUN GO111MODULE=on CGO_ENABLED=0 go build -o bin/gitleaks -ldflags "-X="${ldflags} *.go 
 
 
-FROM alpine:3.11
-RUN apk add --no-cache bash git openssh
+FROM alpine:3.14.1
+RUN adduser -D gitleaks && \
+    apk add --no-cache bash git openssh-client
 COPY --from=build /go/src/github.com/zricethezav/gitleaks/bin/* /usr/bin/
 COPY --from=build /go/src/github.com/zricethezav/gitleaks/bin/* /usr/bin/
+USER gitleaks
 ENTRYPOINT ["gitleaks"]
 ENTRYPOINT ["gitleaks"]
-
-# How to use me :
-
-# docker build -t gitleaks .
-# docker run --rm --name=gitleaks gitleaks --repo-url=https://github.com/zricethezav/gitleaks
-
-# This will check for secrets in https://github.com/zricethezav/gitleaks

+ 8 - 11
Makefile

@@ -10,24 +10,21 @@ test-cover:
 	go test ./... --race $(COVER) $(PKG) -v
 	go test ./... --race $(COVER) $(PKG) -v
 	go tool cover -html=cover.out
 	go tool cover -html=cover.out
 
 
-test:
-	go get golang.org/x/lint/golint
+format:
 	go fmt ./...
 	go fmt ./...
+
+test: format
+	go get golang.org/x/lint/golint
 	go vet ./...
 	go vet ./...
 	golint ./...
 	golint ./...
 	go test ./... --race $(PKG) -v
 	go test ./... --race $(PKG) -v
 
 
-build:
-	go fmt ./...
+build: format
 	golint ./...
 	golint ./...
 	go vet ./...
 	go vet ./...
 	go mod tidy
 	go mod tidy
 	go build $(LDFLAGS)
 	go build $(LDFLAGS)
 
 
-security-scan:
-	go get github.com/securego/gosec/cmd/gosec
-	gosec -no-fail ./...
-
 release-builds:
 release-builds:
 	rm -rf build
 	rm -rf build
 	mkdir build
 	mkdir build
@@ -41,9 +38,9 @@ release-builds:
 
 
 deploy:
 deploy:
 	@echo "$(DOCKER_PASSWORD)" | docker login -u "$(DOCKER_USERNAME)" --password-stdin
 	@echo "$(DOCKER_PASSWORD)" | docker login -u "$(DOCKER_USERNAME)" --password-stdin
-	docker build --build-arg ldflags=$(_LDFLAGS) -f Dockerfile -t zricethezav/gitleaks:latest -t zricethezav/gitleaks:$(VERSION) . 
+	docker build --build-arg ldflags=$(_LDFLAGS) -f Dockerfile -t zricethezav/gitleaks:latest -t zricethezav/gitleaks:$(VERSION) .
 	echo "Pushing zricethezav/gitleaks:$(VERSION) and zricethezav/gitleaks:latest"
 	echo "Pushing zricethezav/gitleaks:$(VERSION) and zricethezav/gitleaks:latest"
 	docker push zricethezav/gitleaks
 	docker push zricethezav/gitleaks
 
 
-dockerbuild: 
-	docker build --build-arg ldflags=$(_LDFLAGS) -f Dockerfile -t zricethezav/gitleaks:latest -t zricethezav/gitleaks:$(VERSION) . 
+dockerbuild:
+	docker build --build-arg ldflags=$(_LDFLAGS) -f Dockerfile -t zricethezav/gitleaks:latest -t zricethezav/gitleaks:$(VERSION) .

+ 68 - 55
README.md

@@ -1,17 +1,32 @@
-<p align="center">
-  <img alt="gitleaks" src="https://raw.githubusercontent.com/zricethezav/gifs/master/gitleakslogo.png" height="70" />
-  <p align="center">
-      <a href="https://travis-ci.org/zricethezav/gitleaks"><img alt="Travis" src="https://img.shields.io/travis/zricethezav/gitleaks/master.svg?style=flat-square"></a>
-  </p>
-</p>
 
 
-Gitleaks is a SAST tool for detecting hardcoded secrets like passwords, api keys, and tokens in git repos. Gitleaks is an **easy-to-use, all-in-one solution** for finding secrets, past or present, in your code. 
+```
+○
+│╲
+│ ○
+○ ░
+░    gitleaks 
+```
+
 
 
-### Introduction Video
 <p align="left">
 <p align="left">
-      <a href="https://www.youtube.com/watch?v=VUq2eII20S4"><img alt="intro" src="https://img.youtube.com/vi/VUq2eII20S4/maxresdefault.jpg" height="200"></a>
+  <p align="left">
+	  <a href="https://github.com/zricethezav/gitleaks/actions/workflows/test.yml">
+		  <img alt="Github Test" src="https://github.com/zricethezav/gitleaks/actions/workflows/test.yml/badge.svg">
+	  </a>
+	  <a href="https://hub.docker.com/r/zricethezav/gitleaks">
+		  <img src="https://img.shields.io/docker/pulls/zricethezav/gitleaks.svg" />
+	  </a>
+	  <a href="https://twitter.com/intent/follow?screen_name=zricethezav">
+		  <img src="https://img.shields.io/twitter/follow/zricethezav?label=Follow%20zricethezav&style=social&color=blue" alt="Follow @zricethezav" />
+	  </a>
+  </p>
 </p>
 </p>
 
 
+Gitleaks is a SAST tool for detecting hardcoded secrets like passwords, api keys, and tokens in git repos. Gitleaks is an **easy-to-use, all-in-one solution** for finding secrets, past or present, in your code.
+
+### [Introduction Video](https://www.youtube.com/watch?v=VUq2eII20S4)
+
+
 ### Features:
 ### Features:
 - Scan for [commited](https://github.com/zricethezav/gitleaks#Scanning) secrets
 - Scan for [commited](https://github.com/zricethezav/gitleaks#Scanning) secrets
 - Scan for [unstaged](https://github.com/zricethezav/gitleaks#scan-unstaged-changes) secrets to shift security left
 - Scan for [unstaged](https://github.com/zricethezav/gitleaks#scan-unstaged-changes) secrets to shift security left
@@ -19,7 +34,7 @@ Gitleaks is a SAST tool for detecting hardcoded secrets like passwords, api keys
 - Run [Gitleaks Action](https://github.com/marketplace/actions/gitleaks) in your CI/CD pipeline
 - Run [Gitleaks Action](https://github.com/marketplace/actions/gitleaks) in your CI/CD pipeline
 - [Custom rules](https://github.com/zricethezav/gitleaks#configuration) via toml configuration
 - [Custom rules](https://github.com/zricethezav/gitleaks#configuration) via toml configuration
 - Increased performance using [go-git](https://github.com/go-git/go-git)
 - Increased performance using [go-git](https://github.com/go-git/go-git)
-- JSON, SARIF, and CSV reporting
+- json, sarif, and csv reporting
 - Private repo scans using key or password based authentication
 - Private repo scans using key or password based authentication
 
 
 
 
@@ -28,14 +43,18 @@ Gitleaks can be installed using Homebrew, Docker, or Go. Gitleaks is also availa
 
 
 ##### MacOS
 ##### MacOS
 
 
-```
+```bash
 brew install gitleaks
 brew install gitleaks
 ```
 ```
 
 
 ##### Docker
 ##### Docker
 
 
 ```bash
 ```bash
-docker pull zricethezav/gitleaks
+# To just pull the image
+docker pull zricethezav/gitleaks:latest
+# To run it from your cloned repo
+cd to/your/repo/
+docker run -v ${PWD}:/my-repo zricethezav/gitleaks:latest --path="/my-repo" [OPTIONS]
 ```
 ```
 
 
 ##### Go
 ##### Go
@@ -49,8 +68,11 @@ See [pre-commit](https://github.com/pre-commit/pre-commit) for instructions.
 Sample `.pre-commit-config.yaml`
 Sample `.pre-commit-config.yaml`
 
 
 ```yaml
 ```yaml
+# The revision doesn't get updated manually
+# check this https://github.com/zricethezav/gitleaks/releases
+# to see if there are newer versions
 -   repo: https://github.com/zricethezav/gitleaks
 -   repo: https://github.com/zricethezav/gitleaks
-    rev: v7.4.0
+    rev: v7.6.0
     hooks:
     hooks:
     -   id: gitleaks
     -   id: gitleaks
 ```
 ```
@@ -83,13 +105,11 @@ Application Options:
       --append-repo-config  Append the provided or default config with the repo config.
       --append-repo-config  Append the provided or default config with the repo config.
       --additional-config=  Path to an additional gitleaks config to append with an existing config. Can be used with --append-repo-config to append up to three configurations
       --additional-config=  Path to an additional gitleaks config to append with an existing config. Can be used with --append-repo-config to append up to three configurations
   -o, --report=             Report output path
   -o, --report=             Report output path
-  -f, --format=             JSON, CSV, SARIF (default: json)
+  -f, --format=             json, csv, sarif (default: json)
       --files-at-commit=    Sha of commit to scan all files at commit
       --files-at-commit=    Sha of commit to scan all files at commit
       --commit=             Sha of commit to scan or "latest" to scan the last commit of the repository
       --commit=             Sha of commit to scan or "latest" to scan the last commit of the repository
       --commits=            Comma separated list of a commits to scan
       --commits=            Comma separated list of a commits to scan
       --commits-file=       Path to file of line separated list of commits to scan
       --commits-file=       Path to file of line separated list of commits to scan
-      --commit-from=        Commit to start scan from
-      --commit-to=          Commit to stop scan
       --commit-since=       Scan commits more recent than a specific date. Ex: '2006-01-02' or '2006-01-02T15:04:05-0700' format.
       --commit-since=       Scan commits more recent than a specific date. Ex: '2006-01-02' or '2006-01-02T15:04:05-0700' format.
       --commit-until=       Scan commits older than a specific date. Ex: '2006-01-02' or '2006-01-02T15:04:05-0700' format.
       --commit-until=       Scan commits older than a specific date. Ex: '2006-01-02' or '2006-01-02T15:04:05-0700' format.
       --depth=              Number of commits to scan
       --depth=              Number of commits to scan
@@ -103,49 +123,49 @@ Help Options:
 
 
 #### Basic repo-url scan:
 #### Basic repo-url scan:
 This scans the entire history of tests/secrets and logs leaks as they are encountered `-v`/`--verbose` being set.
 This scans the entire history of tests/secrets and logs leaks as they are encountered `-v`/`--verbose` being set.
-```
+```bash
 gitleaks --repo-url=https://github.com/my-insecure/repo -v
 gitleaks --repo-url=https://github.com/my-insecure/repo -v
 ```
 ```
 
 
 
 
 #### Basic repo-url scan output to a report:
 #### Basic repo-url scan output to a report:
 If you want the report in sarif or csv you can set the `-f/--format` option
 If you want the report in sarif or csv you can set the `-f/--format` option
-```
+```bash
 gitleaks --repo-url=https://github.com/my-insecure/repo -v --report=my-report.json
 gitleaks --repo-url=https://github.com/my-insecure/repo -v --report=my-report.json
 ```
 ```
 
 
 #### Scan specific commit:
 #### Scan specific commit:
-```
+```bash
 gitleaks --repo-url=https://github.com/my-insecure/repo --commit=commit-sha -v
 gitleaks --repo-url=https://github.com/my-insecure/repo --commit=commit-sha -v
 ```
 ```
 
 
 #### Scan local repo:
 #### Scan local repo:
-```
+```bash
 gitleaks --path=path/to/local/repo -v
 gitleaks --path=path/to/local/repo -v
 ```
 ```
 
 
 #### Scan repos contained in a parent directory:
 #### Scan repos contained in a parent directory:
 If you have `repo1`, `repo2`, `repo3` all under `path/to/local`, gitleaks will discover and scan those repos.
 If you have `repo1`, `repo2`, `repo3` all under `path/to/local`, gitleaks will discover and scan those repos.
-```
+```bash
 gitleaks --path=path/to/local/ -v
 gitleaks --path=path/to/local/ -v
 ```
 ```
 
 
 #### Scan local directory:
 #### Scan local directory:
 If you want to scan the current contents of a repo, ignoring git alltogether. You can use the `--no-git` option to do this.
 If you want to scan the current contents of a repo, ignoring git alltogether. You can use the `--no-git` option to do this.
-```
+```bash
 gitleaks --path=path/to/local/repo -v --no-git
 gitleaks --path=path/to/local/repo -v --no-git
 ```
 ```
 
 
 #### Scan a file:
 #### Scan a file:
 Or if you want to scan a single file using gitleaks rules. You can do this by specifying the file in `--path` and including the `--no-git` option.
 Or if you want to scan a single file using gitleaks rules. You can do this by specifying the file in `--path` and including the `--no-git` option.
-```
+```bash
 gitleaks --path=path/to/local/repo/main.go -v --no-git
 gitleaks --path=path/to/local/repo/main.go -v --no-git
 ```
 ```
 
 
 #### Scan unstaged changes:
 #### Scan unstaged changes:
-If you have unstaged changes are are currently at the root of the repo, you can run `gitleaks` with no `--path` or `--repo-url` specified which will run a scan on your uncommitted changes. Or if you want to specify a 
+If you have unstaged changes are are currently at the root of the repo, you can run `gitleaks` with no `--path` or `--repo-url` specified which will run a scan on your uncommitted changes. Or if you want to specify a
 path, you can run:
 path, you can run:
-```
+```bash
 gitleaks --path=path/to/local/repo -v --unstaged
 gitleaks --path=path/to/local/repo -v --unstaged
 ```
 ```
 
 
@@ -158,12 +178,10 @@ The default configuration Gitleaks uses is located [here](https://github.com/zri
 
 
 The rules are written in [TOML](https://github.com/toml-lang/toml) as defined in [TomlLoader struct](https://github.com/zricethezav/gitleaks/blob/master/config/config.go#L57-L87), and can be summarized as:
 The rules are written in [TOML](https://github.com/toml-lang/toml) as defined in [TomlLoader struct](https://github.com/zricethezav/gitleaks/blob/master/config/config.go#L57-L87), and can be summarized as:
 
 
-```
-
-
+```toml
 [[rules]]
 [[rules]]
   description = "a string describing one of many rule in this config"
   description = "a string describing one of many rule in this config"
-  regex = '''one-go-style-regex-for-this-rule''' 
+  regex = '''one-go-style-regex-for-this-rule'''
   file = '''a-file-name-regex'''
   file = '''a-file-name-regex'''
   path = '''a-file-path-regex'''
   path = '''a-file-path-regex'''
   tags = ["tag","another tag"]
   tags = ["tag","another tag"]
@@ -193,7 +211,7 @@ Regular expressions are _NOT_ the full Perl set, so there are no look-aheads or
 ### Examples
 ### Examples
 #### Example 1
 #### Example 1
 The first and most commonly edited array of tables is `[[rules]]`. This is where you can define your own custom rules for Gitleaks to use while scanning repos. Example keys/values within the `[[rules]]` table:
 The first and most commonly edited array of tables is `[[rules]]`. This is where you can define your own custom rules for Gitleaks to use while scanning repos. Example keys/values within the `[[rules]]` table:
-```
+```toml
 [[rules]]
 [[rules]]
   description = "generic secret regex"
   description = "generic secret regex"
   regex = '''secret(.{0,20})([0-9a-zA-Z-._{}$\/\+=]{20,120})'''
   regex = '''secret(.{0,20})([0-9a-zA-Z-._{}$\/\+=]{20,120})'''
@@ -201,35 +219,34 @@ The first and most commonly edited array of tables is `[[rules]]`. This is where
 ```
 ```
 #### Example 2
 #### Example 2
 We can also **combine** regular expressions AND entropy:
 We can also **combine** regular expressions AND entropy:
-```
+```toml
 [[rules]]
 [[rules]]
   description = "entropy and regex example"
   description = "entropy and regex example"
   regex = '''secret(.{0,20})['|"]([0-9a-zA-Z-._{}$\/\+=]{20,120})['|"]'''
   regex = '''secret(.{0,20})['|"]([0-9a-zA-Z-._{}$\/\+=]{20,120})['|"]'''
   [[rules.Entropies]]
   [[rules.Entropies]]
-	Min = "4.5"
-        Max = "4.7"
+    Min = "4.5"
+    Max = "4.7"
 ```
 ```
 Translating this rule to English, this rule states: "if we encounter a line of code that matches *regex* AND the line falls within the bounds of a [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory)) of 4.5 to 4.7, then the line must be a leak"
 Translating this rule to English, this rule states: "if we encounter a line of code that matches *regex* AND the line falls within the bounds of a [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory)) of 4.5 to 4.7, then the line must be a leak"
 
 
 #### Example 3
 #### Example 3
-Let's compare two lines of code: 
+Let's compare two lines of code:
 ```
 ```
 aws_secret='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'
 aws_secret='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'
 ```
 ```
-and 
+and
 ```
 ```
 aws_secret=os.getenv('AWS_SECRET_ACCESS_KEY')
 aws_secret=os.getenv('AWS_SECRET_ACCESS_KEY')
-
 ```
 ```
 The first line of code is an example of a hardcoded secret being assigned to the variable `aws_secret`. The second line of code is an example of a secret being assigned via env variables to `aws_secret`. Both would be caught by the rule defined in *example 2* but only the first line is actually a leak. Let's define a new rule that will capture only the first line of code. We can do this by combining regular expression **groups** and entropy.
 The first line of code is an example of a hardcoded secret being assigned to the variable `aws_secret`. The second line of code is an example of a secret being assigned via env variables to `aws_secret`. Both would be caught by the rule defined in *example 2* but only the first line is actually a leak. Let's define a new rule that will capture only the first line of code. We can do this by combining regular expression **groups** and entropy.
-```
+```toml
 [[rules]]
 [[rules]]
   description = "entropy and regex example"
   description = "entropy and regex example"
   regex = '''secret(.{0,20})['|"]([0-9a-zA-Z-._{}$\/\+=]{20,120})['|"]'''
   regex = '''secret(.{0,20})['|"]([0-9a-zA-Z-._{}$\/\+=]{20,120})['|"]'''
   [[rules.Entropies]]
   [[rules.Entropies]]
-	Min = "4.5"
-        Max = "4.7"
-        Group = "2"
+    Min = "4.5"
+    Max = "4.7"
+    Group = "2"
 ```
 ```
 Notice how we added `Group = "2"` to this rule. We can translate this rule to English: "if we encounter a line of code that matches regex AND the entropy of the *second regex group* falls within the bounds of a [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory)) of 4.5 to 4.7, then the line must be a leak"
 Notice how we added `Group = "2"` to this rule. We can translate this rule to English: "if we encounter a line of code that matches regex AND the entropy of the *second regex group* falls within the bounds of a [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory)) of 4.5 to 4.7, then the line must be a leak"
 
 
@@ -239,24 +256,22 @@ The proper Perl regex for AWS secret keys is
 `(?<![A-Za-z0-9\\+])[A-Za-z0-9\\+=]{40}(?![A-Za-z0-9\\+=])`
 `(?<![A-Za-z0-9\\+])[A-Za-z0-9\\+=]{40}(?![A-Za-z0-9\\+=])`
 but the Go library doesn't do lookahead/lookbehind, so
 but the Go library doesn't do lookahead/lookbehind, so
 we'll look for 40 base64 characters, then allowlist
 we'll look for 40 base64 characters, then allowlist
-if they're embedded in a string of 41 base64 characters, that is, 
+if they're embedded in a string of 41 base64 characters, that is,
 without any delimiters. This will make a false negative for, say:
 without any delimiters. This will make a false negative for, say:
 ```
 ```
     foo=+awsSecretAccessKeyisBase64=40characters
     foo=+awsSecretAccessKeyisBase64=40characters
 ```
 ```
 So you can use the following to effectively create the proper Perl regex:
 So you can use the following to effectively create the proper Perl regex:
-```
+```toml
 [[rules]]
 [[rules]]
-	description = "AWS secret key regardless of labeling"
-	regex = '''.?[A-Za-z0-9\\+=]{40}.?'''
-	[rules.allowlist]
-                description = "41 base64 characters is not an AWS secret key"
-		regexes = ['''[A-Za-z0-9\\+=]{41}''']
-		
+  description = "AWS secret key regardless of labeling"
+  regex = '''.?[A-Za-z0-9\\+=]{40}.?'''
+  [rules.allowlist]
+    description = "41 base64 characters is not an AWS secret key"
+    regexes = ['''[A-Za-z0-9\\+=]{41}''']
 ```
 ```
 
 
 
 
-
 ### Exit Codes
 ### Exit Codes
 You can always set the exit code when leaves are encountered with the `--leaks-exit-code` flag. Default exit codes below:
 You can always set the exit code when leaves are encountered with the `--leaks-exit-code` flag. Default exit codes below:
 ```
 ```
@@ -266,17 +281,15 @@ You can always set the exit code when leaves are encountered with the `--leaks-e
 
 
 ###  Sponsors ❤️
 ###  Sponsors ❤️
 #### Organization Sponsors
 #### Organization Sponsors
-[![gammanet](https://gammanet.com/assets/images/new-design/gamma-logo.png)](https://gammanet.com/?utm_source=gitleaks&utm_medium=homepage&utm_campaign=gitleaks_promotion)
-
-Gamma proactively detects and remediates data leaks across cloud apps. Scan your public repos for secret leaks with [Gamma](https://gammanet.com/github-demo?utm_source=gitleaks&utm_medium=homepage&utm_campaign=gitleaks_promotion)
+Sir, ehm, this is uhh... this is empty [😭](https://www.youtube.com/watch?v=w1o4O2SfQ5g)
 
 
-#### Individual Sponsors 
+#### Individual Sponsors
 These users are [sponsors](https://github.com/sponsors/zricethezav) of gitleaks:
 These users are [sponsors](https://github.com/sponsors/zricethezav) of gitleaks:
 
 
 - [Adam Shannon](https://github.com/adamdecaf)
 - [Adam Shannon](https://github.com/adamdecaf)
 - [ProjectDiscovery](https://projectdiscovery.io/#/)
 - [ProjectDiscovery](https://projectdiscovery.io/#/)
-
+- [Ben "Ihavespoons"](https://github.com/ihavespoons)
+- [Henry Sachs](https://github.com/henrysachs)
 
 
 #### Logo Attribution
 #### Logo Attribution
 The Gitleaks logo uses the Git Logo created <a href="https://twitter.com/jasonlong">Jason Long</a> is licensed under the <a href="https://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.
 The Gitleaks logo uses the Git Logo created <a href="https://twitter.com/jasonlong">Jason Long</a> is licensed under the <a href="https://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 Unported License</a>.
-

+ 5 - 1
config/config.go

@@ -1,6 +1,7 @@
 package config
 package config
 
 
 import (
 import (
+	_ "embed"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
@@ -16,6 +17,9 @@ import (
 	log "github.com/sirupsen/logrus"
 	log "github.com/sirupsen/logrus"
 )
 )
 
 
+//go:embed gitleaks.toml
+var DefaultConfig string
+
 // Config is a composite struct of Rules and Allowlists
 // Config is a composite struct of Rules and Allowlists
 // Each Rule contains a description, regular expression, tags, and allowlists if available
 // Each Rule contains a description, regular expression, tags, and allowlists if available
 type Config struct {
 type Config struct {
@@ -42,7 +46,7 @@ type TomlAllowList struct {
 }
 }
 
 
 // TomlLoader gets loaded with the values from a gitleaks toml config
 // TomlLoader gets loaded with the values from a gitleaks toml config
-// see the config in config/defaults.go for an example. TomlLoader is used
+// see the config in config/gitleaks.toml for an example. TomlLoader is used
 // to generate Config values (compiling regexes, etc).
 // to generate Config values (compiling regexes, etc).
 type TomlLoader struct {
 type TomlLoader struct {
 	AllowList TomlAllowList
 	AllowList TomlAllowList

+ 2 - 8
config/default.go → config/gitleaks.toml

@@ -1,9 +1,4 @@
-package config
 
 
-// DefaultConfig is the default gitleaks configuration. If --config={path-to-config} is set than the config located
-// at {path-to-config} will be used. Alternatively, if --repo-config is set then gitleaks will attempt to
-// use the config set in a gitleaks.toml or .gitleaks.toml file in the repo that is run with --repo-config set.
-const DefaultConfig = `
 title = "gitleaks config"
 title = "gitleaks config"
 
 
 [[rules]]
 [[rules]]
@@ -33,12 +28,12 @@ title = "gitleaks config"
 
 
 [[rules]]
 [[rules]]
     description = "Twitter Secret Key"
     description = "Twitter Secret Key"
-    regex = '''(?i)twitter(.{0,20})?[0-9a-z]{35,44}'''
+    regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{35,44}['\"]'''
     tags = ["key", "Twitter"]
     tags = ["key", "Twitter"]
 
 
 [[rules]]
 [[rules]]
     description = "Twitter Client ID"
     description = "Twitter Client ID"
-    regex = '''(?i)twitter(.{0,20})?[0-9a-z]{18,25}'''
+    regex = '''(?i)twitter(.{0,20})?['\"][0-9a-z]{18,25}['\"]'''
     tags = ["client", "Twitter"]
     tags = ["client", "Twitter"]
 
 
 [[rules]]
 [[rules]]
@@ -178,4 +173,3 @@ title = "gitleaks config"
     files = ['''^\.?gitleaks.toml$''',
     files = ['''^\.?gitleaks.toml$''',
     '''(.*?)(png|jpg|gif|doc|docx|pdf|bin|xls|pyc|zip)$''',
     '''(.*?)(png|jpg|gif|doc|docx|pdf|bin|xls|pyc|zip)$''',
     '''(go.mod|go.sum)$''']
     '''(go.mod|go.sum)$''']
-`

+ 60 - 14
config/rule.go

@@ -6,6 +6,23 @@ import (
 	"regexp"
 	"regexp"
 )
 )
 
 
+// Offender is a struct that contains the information matched when searching
+// content and information on why it matched (i.e. the EntropyLevel)
+type Offender struct {
+	Match        string
+	EntropyLevel float64
+}
+
+// IsEmpty checks to see if nothing was found in the match
+func (o *Offender) IsEmpty() bool {
+	return o.Match == ""
+}
+
+// ToString the contents of the match
+func (o *Offender) ToString() string {
+	return o.Match
+}
+
 // Rule is a struct that contains information that is loaded from a gitleaks config.
 // Rule is a struct that contains information that is loaded from a gitleaks config.
 // This struct is used in the Config struct as an array of Rules and is iterated
 // This struct is used in the Config struct as an array of Rules and is iterated
 // over during an scan. Each rule will be checked. If a regex match is found AND
 // over during an scan. Each rule will be checked. If a regex match is found AND
@@ -23,28 +40,46 @@ type Rule struct {
 }
 }
 
 
 // Inspect checks the content of a line for a leak
 // Inspect checks the content of a line for a leak
-func (r *Rule) Inspect(line string) string {
-	offender := r.Regex.FindString(line)
-	if offender == "" {
-		return ""
+func (r *Rule) Inspect(line string) *Offender {
+	match := r.Regex.FindString(line)
+
+	// EntropyLevel -1 means not checked
+	if match == "" {
+		return &Offender{
+			Match:        "",
+			EntropyLevel: -1,
+		}
 	}
 	}
 
 
 	// check if offender is allowed
 	// check if offender is allowed
+	// EntropyLevel -1 means not checked
 	if r.RegexAllowed(line) {
 	if r.RegexAllowed(line) {
-		return ""
+		return &Offender{
+			Match:        "",
+			EntropyLevel: -1,
+		}
 	}
 	}
 
 
 	// check entropy
 	// check entropy
-	groups := r.Regex.FindStringSubmatch(offender)
-	if len(r.Entropies) != 0 && !r.ContainsEntropyLeak(groups) {
-		return ""
+	groups := r.Regex.FindStringSubmatch(match)
+	entropyWithinRange, entropyLevel := r.CheckEntropy(groups)
+
+	if len(r.Entropies) != 0 && !entropyWithinRange {
+		return &Offender{
+			Match:        "",
+			EntropyLevel: entropyLevel,
+		}
 	}
 	}
 
 
 	// 0 is a match for the full regex pattern
 	// 0 is a match for the full regex pattern
 	if 0 < r.ReportGroup && r.ReportGroup < len(groups) {
 	if 0 < r.ReportGroup && r.ReportGroup < len(groups) {
-		offender = groups[r.ReportGroup]
+		match = groups[r.ReportGroup]
+	}
+
+	return &Offender{
+		Match:        match,
+		EntropyLevel: entropyLevel,
 	}
 	}
-	return offender
 }
 }
 
 
 // RegexAllowed checks if the content is allowlisted
 // RegexAllowed checks if the content is allowlisted
@@ -57,17 +92,28 @@ func (r *Rule) CommitAllowed(commit string) bool {
 	return r.AllowList.CommitAllowed(commit)
 	return r.AllowList.CommitAllowed(commit)
 }
 }
 
 
-// ContainsEntropyLeak checks if there is an entropy leak
-func (r *Rule) ContainsEntropyLeak(groups []string) bool {
+// CheckEntropy checks if there is an entropy leak
+func (r *Rule) CheckEntropy(groups []string) (bool, float64) {
+	var highestFound float64 = 0
+
 	for _, e := range r.Entropies {
 	for _, e := range r.Entropies {
 		if len(groups) > e.Group {
 		if len(groups) > e.Group {
 			entropy := shannonEntropy(groups[e.Group])
 			entropy := shannonEntropy(groups[e.Group])
 			if entropy >= e.Min && entropy <= e.Max {
 			if entropy >= e.Min && entropy <= e.Max {
-				return true
+				return true, entropy
+			} else if entropy > highestFound {
+				highestFound = entropy
 			}
 			}
 		}
 		}
 	}
 	}
-	return false
+
+	if len(r.Entropies) == 0 {
+		// entropies not checked
+		return false, -1
+	}
+
+	// entropies checked but not within the range
+	return false, highestFound
 }
 }
 
 
 // HasFileOrPathLeakOnly first checks if there are no entropy/regex rules, then checks if
 // HasFileOrPathLeakOnly first checks if there are no entropy/regex rules, then checks if

+ 1 - 1
examples/leaky-repo.toml

@@ -186,7 +186,7 @@ title = "gitleaks config"
 
 
 [[rules]]
 [[rules]]
 	description = "Files with keys and credentials"
 	description = "Files with keys and credentials"
-    file = '''(?i)(id_rsa|passwd|id_rsa.pub|pgpass|pem|key|shadow)'''
+	file = '''(?i)(id_rsa|passwd|id_rsa.pub|pgpass|pem|key|shadow)'''
 
 
 # Global allowlist
 # Global allowlist
 [allowlist]
 [allowlist]

+ 3 - 5
go.mod

@@ -2,16 +2,14 @@ module github.com/zricethezav/gitleaks/v7
 
 
 go 1.16
 go 1.16
 
 
-replace github.com/go-git/go-git/v5 => github.com/zricethezav/go-git/v5 v5.2.2
+replace github.com/go-git/go-git/v5 => github.com/zricethezav/go-git/v5 v5.3.0
 
 
 require (
 require (
 	github.com/BurntSushi/toml v0.3.1
 	github.com/BurntSushi/toml v0.3.1
-	github.com/go-git/go-git/v5 v5.2.0
-	github.com/google/go-cmp v0.4.0 // indirect
+	github.com/go-git/go-git/v5 v5.3.0
 	github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4
 	github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4
-	github.com/jessevdk/go-flags v1.4.0
+	github.com/jessevdk/go-flags v1.5.0
 	github.com/sergi/go-diff v1.1.0
 	github.com/sergi/go-diff v1.1.0
 	github.com/sirupsen/logrus v1.4.2
 	github.com/sirupsen/logrus v1.4.2
 	golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
 	golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9
-	gopkg.in/yaml.v2 v2.2.8 // indirect
 )
 )

+ 56 - 40
go.sum

@@ -1,7 +1,12 @@
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk=
+github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
+github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
+github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
+github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
@@ -12,85 +17,96 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
 github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
 github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
 github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
 github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
 github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
 github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
-github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM=
-github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M=
-github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
+github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
+github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
+github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
+github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4 h1:60gBOooTSmNtrqNaRvrDbi8VAne0REaek2agjnITKSw=
 github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4 h1:60gBOooTSmNtrqNaRvrDbi8VAne0REaek2agjnITKSw=
 github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
 github.com/hako/durafmt v0.0.0-20191009132224-3f39dc1ed9f4/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
-github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
+github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
+github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
+github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
+github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
-github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
-github.com/zricethezav/go-git/v5 v5.2.2 h1:VOVijF5OpIiHvFZXX94AJezdJ0b0kTyRyVNZ4yaqCRU=
-github.com/zricethezav/go-git/v5 v5.2.2/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
+github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+github.com/zricethezav/go-git/v5 v5.3.0 h1:sx02mqKAT6Doe4rLcquIJr1XjrV5QcX8KXk3wSCVic4=
+github.com/zricethezav/go-git/v5 v5.3.0/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
 golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
-golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
-golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b h1:7mWr3k41Qtv8XlltBkDkl8LoP3mpSgBW8BUoxtEdbXg=
+golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897 h1:KrsHThm5nFk34YtATK1LsThyGhGbGe1olrte/HInHvs=
+golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79 h1:RX8C8PRZc2hTIod4ds8ij+/4RQX3AqhYj3uOHmyaz4E=
+golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
-gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 18 - 6
options/options.go

@@ -44,7 +44,7 @@ type Options struct {
 
 
 	// Report Options
 	// Report Options
 	Report       string `short:"o" long:"report" description:"Report output path"`
 	Report       string `short:"o" long:"report" description:"Report output path"`
-	ReportFormat string `short:"f" long:"format" default:"json" description:"JSON, CSV, SARIF"`
+	ReportFormat string `short:"f" long:"format" default:"json" description:"json, csv, sarif"`
 
 
 	// Commit Options
 	// Commit Options
 	FilesAtCommit string `long:"files-at-commit" description:"Sha of commit to scan all files at commit"`
 	FilesAtCommit string `long:"files-at-commit" description:"Sha of commit to scan all files at commit"`
@@ -144,8 +144,8 @@ func (opts Options) CloneOptions() (*git.CloneOptions, error) {
 
 
 	var auth transport.AuthMethod
 	var auth transport.AuthMethod
 
 
-	if strings.HasPrefix(opts.RepoURL, "git") {
-		// using git protocol so needs ssh auth
+	if strings.HasPrefix(opts.RepoURL, "ssh://") || (!strings.Contains(opts.RepoURL, "://") && strings.Contains(opts.RepoURL, ":")) {
+		// using ssh:// url or scp-like syntax
 		auth, err = SSHAuth(opts)
 		auth, err = SSHAuth(opts)
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
@@ -176,17 +176,29 @@ func (opts Options) CloneOptions() (*git.CloneOptions, error) {
 // SSHAuth tried to generate ssh public keys based on what was passed via cli. If no
 // SSHAuth tried to generate ssh public keys based on what was passed via cli. If no
 // path was passed via cli then this will attempt to retrieve keys from the default
 // path was passed via cli then this will attempt to retrieve keys from the default
 // location for ssh keys, $HOME/.ssh/id_rsa. This function is only called if the
 // location for ssh keys, $HOME/.ssh/id_rsa. This function is only called if the
-// repo url using the git:// protocol.
+// repo url using the ssh:// protocol or scp-like syntax.
 func SSHAuth(opts Options) (*ssh.PublicKeys, error) {
 func SSHAuth(opts Options) (*ssh.PublicKeys, error) {
+	params := strings.Split(opts.RepoURL, "@")
+
+	if len(params) != 2 {
+		return nil, fmt.Errorf("user must be specified in the URL")
+	}
+
+	// the part of the RepoURL before the "@" (params[0]) can be something like:
+	// - "ssh://user" if RepoURL is an ssh:// URL
+	// - "user" if RepoURL uses scp-like syntax
+	// we must strip the protocol if it is present so that we only have "user"
+	username := strings.Replace(params[0], "ssh://", "", 1)
+
 	if opts.SSH != "" {
 	if opts.SSH != "" {
-		return ssh.NewPublicKeysFromFile("git", opts.SSH, "")
+		return ssh.NewPublicKeysFromFile(username, opts.SSH, "")
 	}
 	}
 	c, err := user.Current()
 	c, err := user.Current()
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	defaultPath := fmt.Sprintf("%s/.ssh/id_rsa", c.HomeDir)
 	defaultPath := fmt.Sprintf("%s/.ssh/id_rsa", c.HomeDir)
-	return ssh.NewPublicKeysFromFile("git", defaultPath, "")
+	return ssh.NewPublicKeysFromFile(username, defaultPath, "")
 }
 }
 
 
 // OpenLocal checks what options are set, if no remote targets are set
 // OpenLocal checks what options are set, if no remote targets are set

+ 2 - 2
scan/commit.go

@@ -121,7 +121,7 @@ func (cs *CommitScanner) Scan() (Report, error) {
 							continue
 							continue
 						}
 						}
 						offender := rule.Inspect(line)
 						offender := rule.Inspect(line)
-						if offender == "" {
+						if offender.IsEmpty() {
 							continue
 							continue
 						}
 						}
 
 
@@ -136,7 +136,7 @@ func (cs *CommitScanner) Scan() (Report, error) {
 							continue
 							continue
 						}
 						}
 
 
-						leak := NewLeak(line, offender, defaultLineNumber).WithCommit(cs.commit)
+						leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithCommit(cs.commit).WithEntropy(offender.EntropyLevel)
 						leak.File = to.Path()
 						leak.File = to.Path()
 						leak.LineNumber = extractLine(patchContent, leak, lineLookup)
 						leak.LineNumber = extractLine(patchContent, leak, lineLookup)
 						leak.RepoURL = cs.opts.RepoURL
 						leak.RepoURL = cs.opts.RepoURL

+ 2 - 3
scan/filesatcommit.go

@@ -97,8 +97,7 @@ func (fs *FilesAtCommitScanner) Scan() (Report, error) {
 				}
 				}
 
 
 				offender := rule.Inspect(line)
 				offender := rule.Inspect(line)
-
-				if offender == "" {
+				if offender.IsEmpty() {
 					continue
 					continue
 				}
 				}
 
 
@@ -113,7 +112,7 @@ func (fs *FilesAtCommitScanner) Scan() (Report, error) {
 					continue
 					continue
 				}
 				}
 
 
-				leak := NewLeak(line, offender, defaultLineNumber).WithCommit(fs.commit)
+				leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithCommit(fs.commit).WithEntropy(offender.EntropyLevel)
 				leak.File = f.Name
 				leak.File = f.Name
 				leak.LineNumber = i + 1
 				leak.LineNumber = i + 1
 				leak.RepoURL = fs.opts.RepoURL
 				leak.RepoURL = fs.opts.RepoURL

+ 26 - 17
scan/leak.go

@@ -3,6 +3,7 @@ package scan
 import (
 import (
 	"encoding/json"
 	"encoding/json"
 	"fmt"
 	"fmt"
+	"math"
 	"strings"
 	"strings"
 	"time"
 	"time"
 
 
@@ -14,20 +15,21 @@ import (
 // Leak is a struct that contains information about some line of code that contains
 // Leak is a struct that contains information about some line of code that contains
 // sensitive information as determined by the rules set in a gitleaks config
 // sensitive information as determined by the rules set in a gitleaks config
 type Leak struct {
 type Leak struct {
-	Line       string    `json:"line"`
-	LineNumber int       `json:"lineNumber"`
-	Offender   string    `json:"offender"`
-	Commit     string    `json:"commit"`
-	Repo       string    `json:"repo"`
-	RepoURL    string    `json:"repoURL"`
-	LeakURL    string    `json:"leakURL"`
-	Rule       string    `json:"rule"`
-	Message    string    `json:"commitMessage"`
-	Author     string    `json:"author"`
-	Email      string    `json:"email"`
-	File       string    `json:"file"`
-	Date       time.Time `json:"date"`
-	Tags       string    `json:"tags"`
+	Line            string    `json:"line"`
+	LineNumber      int       `json:"lineNumber"`
+	Offender        string    `json:"offender"`
+	OffenderEntropy float64   `json:"offenderEntropy"`
+	Commit          string    `json:"commit"`
+	Repo            string    `json:"repo"`
+	RepoURL         string    `json:"repoURL"`
+	LeakURL         string    `json:"leakURL"`
+	Rule            string    `json:"rule"`
+	Message         string    `json:"commitMessage"`
+	Author          string    `json:"author"`
+	Email           string    `json:"email"`
+	File            string    `json:"file"`
+	Date            time.Time `json:"date"`
+	Tags            string    `json:"tags"`
 }
 }
 
 
 // RedactLeak will replace the offending string with "REDACTED" in both
 // RedactLeak will replace the offending string with "REDACTED" in both
@@ -41,9 +43,10 @@ func RedactLeak(leak Leak) Leak {
 // NewLeak creates a new leak from common data all leaks must have, line, offender, linenumber
 // NewLeak creates a new leak from common data all leaks must have, line, offender, linenumber
 func NewLeak(line string, offender string, lineNumber int) Leak {
 func NewLeak(line string, offender string, lineNumber int) Leak {
 	return Leak{
 	return Leak{
-		Line:       line,
-		Offender:   offender,
-		LineNumber: lineNumber,
+		Line:            line,
+		Offender:        offender,
+		LineNumber:      lineNumber,
+		OffenderEntropy: -1, // -1 means not checked
 	}
 	}
 }
 }
 
 
@@ -57,6 +60,12 @@ func (leak Leak) WithCommit(commit *object.Commit) Leak {
 	return leak
 	return leak
 }
 }
 
 
+// WithEntropy adds OffenderEntropy data to the leak
+func (leak Leak) WithEntropy(entropyLevel float64) Leak {
+	leak.OffenderEntropy = math.Round(entropyLevel*1000) / 1000
+	return leak
+}
+
 // Log logs a leak and redacts if necessary
 // Log logs a leak and redacts if necessary
 func (leak Leak) Log(opts options.Options) {
 func (leak Leak) Log(opts options.Options) {
 	if !opts.Quiet && !opts.Verbose {
 	if !opts.Quiet && !opts.Verbose {

+ 24 - 22
scan/nogit.go

@@ -6,6 +6,7 @@ import (
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
+	"sync"
 
 
 	log "github.com/sirupsen/logrus"
 	log "github.com/sirupsen/logrus"
 
 
@@ -17,15 +18,19 @@ import (
 
 
 // NoGitScanner is a scanner that absolutely despises git
 // NoGitScanner is a scanner that absolutely despises git
 type NoGitScanner struct {
 type NoGitScanner struct {
-	opts options.Options
-	cfg  config.Config
+	opts     options.Options
+	cfg      config.Config
+	throttle *Throttle
+	mtx      *sync.Mutex
 }
 }
 
 
 // NewNoGitScanner creates and returns a nogit scanner. This is used for scanning files and directories
 // NewNoGitScanner creates and returns a nogit scanner. This is used for scanning files and directories
 func NewNoGitScanner(opts options.Options, cfg config.Config) *NoGitScanner {
 func NewNoGitScanner(opts options.Options, cfg config.Config) *NoGitScanner {
 	ngs := &NoGitScanner{
 	ngs := &NoGitScanner{
-		opts: opts,
-		cfg:  cfg,
+		opts:     opts,
+		cfg:      cfg,
+		throttle: NewThrottle(opts),
+		mtx:      &sync.Mutex{},
 	}
 	}
 
 
 	// no-git scans should ignore .git folders by default
 	// no-git scans should ignore .git folders by default
@@ -44,7 +49,8 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 	var scannerReport Report
 	var scannerReport Report
 
 
 	g, _ := errgroup.WithContext(context.Background())
 	g, _ := errgroup.WithContext(context.Background())
-	paths := make(chan string, 100)
+
+	paths := make(chan string)
 
 
 	g.Go(func() error {
 	g.Go(func() error {
 		defer close(paths)
 		defer close(paths)
@@ -60,11 +66,11 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 			})
 			})
 	})
 	})
 
 
-	leaks := make(chan Leak, 100)
-
 	for path := range paths {
 	for path := range paths {
 		p := path
 		p := path
+		ngs.throttle.Limit()
 		g.Go(func() error {
 		g.Go(func() error {
+			defer ngs.throttle.Release()
 			if ngs.cfg.Allowlist.FileAllowed(filepath.Base(p)) ||
 			if ngs.cfg.Allowlist.FileAllowed(filepath.Base(p)) ||
 				ngs.cfg.Allowlist.PathAllowed(p) {
 				ngs.cfg.Allowlist.PathAllowed(p) {
 				return nil
 				return nil
@@ -84,7 +90,9 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 
 
 					leak.Log(ngs.opts)
 					leak.Log(ngs.opts)
 
 
-					leaks <- leak
+					ngs.mtx.Lock()
+					scannerReport.Leaks = append(scannerReport.Leaks, leak)
+					ngs.mtx.Unlock()
 				}
 				}
 			}
 			}
 
 
@@ -105,7 +113,7 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 					}
 					}
 
 
 					offender := rule.Inspect(line)
 					offender := rule.Inspect(line)
-					if offender == "" {
+					if offender.IsEmpty() {
 						continue
 						continue
 					}
 					}
 					if ngs.cfg.Allowlist.RegexAllowed(line) {
 					if ngs.cfg.Allowlist.RegexAllowed(line) {
@@ -119,7 +127,7 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 						continue
 						continue
 					}
 					}
 
 
-					leak := NewLeak(line, offender, defaultLineNumber)
+					leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithEntropy(offender.EntropyLevel)
 					relPath, err := filepath.Rel(ngs.opts.Path, p)
 					relPath, err := filepath.Rel(ngs.opts.Path, p)
 					if err != nil {
 					if err != nil {
 						leak.File = p
 						leak.File = p
@@ -129,26 +137,20 @@ func (ngs *NoGitScanner) Scan() (Report, error) {
 					leak.LineNumber = lineNumber
 					leak.LineNumber = lineNumber
 					leak.Rule = rule.Description
 					leak.Rule = rule.Description
 					leak.Tags = strings.Join(rule.Tags, ", ")
 					leak.Tags = strings.Join(rule.Tags, ", ")
-
 					leak.Log(ngs.opts)
 					leak.Log(ngs.opts)
 
 
-					leaks <- leak
+					ngs.mtx.Lock()
+					scannerReport.Leaks = append(scannerReport.Leaks, leak)
+					ngs.mtx.Unlock()
 				}
 				}
 			}
 			}
 			return f.Close()
 			return f.Close()
 		})
 		})
 	}
 	}
 
 
-	go func() {
-		if err := g.Wait(); err != nil {
-			log.Error(err)
-		}
-		close(leaks)
-	}()
-
-	for leak := range leaks {
-		scannerReport.Leaks = append(scannerReport.Leaks, leak)
+	if err := g.Wait(); err != nil {
+		log.Error(err)
 	}
 	}
 
 
-	return scannerReport, g.Wait()
+	return scannerReport, nil
 }
 }

+ 9 - 12
scan/repo.go

@@ -2,6 +2,7 @@ package scan
 
 
 import (
 import (
 	"context"
 	"context"
+	"sync"
 
 
 	"golang.org/x/sync/errgroup"
 	"golang.org/x/sync/errgroup"
 
 
@@ -21,6 +22,7 @@ type RepoScanner struct {
 	repo     *git.Repository
 	repo     *git.Repository
 	throttle *Throttle
 	throttle *Throttle
 	repoName string
 	repoName string
+	mtx      *sync.Mutex
 }
 }
 
 
 // NewRepoScanner returns a new repo scanner (go figure). This function also
 // NewRepoScanner returns a new repo scanner (go figure). This function also
@@ -32,6 +34,7 @@ func NewRepoScanner(opts options.Options, cfg config.Config, repo *git.Repositor
 		repo:     repo,
 		repo:     repo,
 		throttle: NewThrottle(opts),
 		throttle: NewThrottle(opts),
 		repoName: getRepoName(opts),
 		repoName: getRepoName(opts),
+		mtx:      &sync.Mutex{},
 	}
 	}
 
 
 	return rs
 	return rs
@@ -54,7 +57,6 @@ func (rs *RepoScanner) Scan() (Report, error) {
 
 
 	g, _ := errgroup.WithContext(context.Background())
 	g, _ := errgroup.WithContext(context.Background())
 	commits = make(chan *object.Commit)
 	commits = make(chan *object.Commit)
-	leaks := make(chan Leak)
 
 
 	commitNum := 0
 	commitNum := 0
 	g.Go(func() error {
 	g.Go(func() error {
@@ -91,25 +93,20 @@ func (rs *RepoScanner) Scan() (Report, error) {
 				log.Error(err)
 				log.Error(err)
 			}
 			}
 			for _, leak := range report.Leaks {
 			for _, leak := range report.Leaks {
-				leaks <- leak
+				rs.mtx.Lock()
+				scannerReport.Leaks = append(scannerReport.Leaks, leak)
+				rs.mtx.Unlock()
 			}
 			}
 			return nil
 			return nil
 		})
 		})
 	}
 	}
 
 
-	go func() {
-		if err := g.Wait(); err != nil {
-			log.Error(err)
-		}
-		close(leaks)
-	}()
-
-	for leak := range leaks {
-		scannerReport.Leaks = append(scannerReport.Leaks, leak)
+	if err := g.Wait(); err != nil {
+		log.Error(err)
 	}
 	}
 
 
 	scannerReport.Commits = commitNum
 	scannerReport.Commits = commitNum
-	return scannerReport, g.Wait()
+	return scannerReport, nil
 }
 }
 
 
 // SetRepoName sets the repo name
 // SetRepoName sets the repo name

+ 15 - 15
scan/report.go

@@ -4,6 +4,7 @@ import (
 	"encoding/csv"
 	"encoding/csv"
 	"encoding/json"
 	"encoding/json"
 	"os"
 	"os"
+	"strings"
 	"time"
 	"time"
 
 
 	"github.com/sirupsen/logrus"
 	"github.com/sirupsen/logrus"
@@ -27,28 +28,27 @@ func WriteReport(report Report, opts options.Options, cfg config.Config) error {
 		logrus.Warn("leaks found: ", len(report.Leaks))
 		logrus.Warn("leaks found: ", len(report.Leaks))
 	} else {
 	} else {
 		logrus.Info("No leaks found")
 		logrus.Info("No leaks found")
+		return nil
 	}
 	}
 
 
 	if opts.Report == "" {
 	if opts.Report == "" {
 		return nil
 		return nil
-	}
-
-	if opts.Redact {
-		var redactedLeaks []Leak
-		for _, leak := range report.Leaks {
-			redactedLeaks = append(redactedLeaks, RedactLeak(leak))
+	} else {
+		if opts.Redact {
+			var redactedLeaks []Leak
+			for _, leak := range report.Leaks {
+				redactedLeaks = append(redactedLeaks, RedactLeak(leak))
+			}
+			report.Leaks = redactedLeaks
 		}
 		}
-		report.Leaks = redactedLeaks
-	}
 
 
-	file, err := os.Create(opts.Report)
-	if err != nil {
-		return err
-	}
-	defer rable(file.Close)
+		file, err := os.Create(opts.Report)
+		if err != nil {
+			return err
+		}
+		defer rable(file.Close)
 
 
-	if opts.Report != "" {
-		switch opts.ReportFormat {
+		switch strings.ToLower(opts.ReportFormat) {
 		case "json":
 		case "json":
 			encoder := json.NewEncoder(file)
 			encoder := json.NewEncoder(file)
 			encoder.SetIndent("", " ")
 			encoder.SetIndent("", " ")

+ 2 - 0
scan/sarif.go

@@ -77,6 +77,7 @@ type Locations struct {
 //Results ...
 //Results ...
 type Results struct {
 type Results struct {
 	Message    Message          `json:"message"`
 	Message    Message          `json:"message"`
+	RuleId     string           `json:"ruleId"`
 	Properties ResultProperties `json:"properties"`
 	Properties ResultProperties `json:"properties"`
 	Locations  []Locations      `json:"locations"`
 	Locations  []Locations      `json:"locations"`
 }
 }
@@ -117,6 +118,7 @@ func leaksToResults(leaks []Leak) []Results {
 			Message: Message{
 			Message: Message{
 				Text: fmt.Sprintf("%s secret detected", leak.Rule),
 				Text: fmt.Sprintf("%s secret detected", leak.Rule),
 			},
 			},
+			RuleId: leak.Rule,
 			Properties: ResultProperties{
 			Properties: ResultProperties{
 				Commit:        leak.Commit,
 				Commit:        leak.Commit,
 				Offender:      leak.Offender,
 				Offender:      leak.Offender,

+ 5 - 1
scan/scan_test.go

@@ -760,7 +760,7 @@ func fileCheck(wantPath, gotPath string) error {
 			}
 			}
 		}
 		}
 		if !found {
 		if !found {
-			return fmt.Errorf("unable to find %+v in got leaks", wantLeak)
+			return fmt.Errorf("unable to find %+v in %s", wantLeak, gotPath)
 		}
 		}
 	}
 	}
 
 
@@ -779,6 +779,10 @@ func same(l1, l2 Leak) bool {
 		return false
 		return false
 	}
 	}
 
 
+	if l1.OffenderEntropy != l2.OffenderEntropy {
+		return false
+	}
+
 	if l1.Line != l2.Line {
 	if l1.Line != l2.Line {
 		return false
 		return false
 	}
 	}

+ 11 - 5
scan/unstaged.go

@@ -4,6 +4,7 @@ import (
 	"bytes"
 	"bytes"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
+	"os"
 	"os/exec"
 	"os/exec"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
@@ -79,7 +80,9 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 				}
 				}
 			}
 			}
 
 
-			if _, err := io.Copy(workTreeBuf, workTreeFile); err != nil {
+			if fc, err := os.Readlink(fn); err == nil {
+				workTreeBuf = bytes.NewBufferString(fc)
+			} else if _, err := io.Copy(workTreeBuf, workTreeFile); err != nil {
 				return scannerReport, err
 				return scannerReport, err
 			}
 			}
 			lineNumber := 0
 			lineNumber := 0
@@ -87,7 +90,7 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 				lineNumber++
 				lineNumber++
 				for _, rule := range us.cfg.Rules {
 				for _, rule := range us.cfg.Rules {
 					offender := rule.Inspect(line)
 					offender := rule.Inspect(line)
-					if offender == "" {
+					if offender.IsEmpty() {
 						continue
 						continue
 					}
 					}
 					if us.cfg.Allowlist.RegexAllowed(line) ||
 					if us.cfg.Allowlist.RegexAllowed(line) ||
@@ -101,7 +104,7 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 					if rule.Path.String() != "" && !rule.HasFilePathLeak(filepath.Base(workTreeFile.Name())) {
 					if rule.Path.String() != "" && !rule.HasFilePathLeak(filepath.Base(workTreeFile.Name())) {
 						continue
 						continue
 					}
 					}
-					leak := NewLeak(line, offender, defaultLineNumber).WithCommit(emptyCommit())
+					leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithCommit(emptyCommit()).WithEntropy(offender.EntropyLevel)
 					leak.File = workTreeFile.Name()
 					leak.File = workTreeFile.Name()
 					leak.LineNumber = lineNumber
 					leak.LineNumber = lineNumber
 					leak.Repo = us.repoName
 					leak.Repo = us.repoName
@@ -156,6 +159,9 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 				// file in staging has been deleted, aka it is not on the filesystem
 				// file in staging has been deleted, aka it is not on the filesystem
 				// so the contents of the file are ""
 				// so the contents of the file are ""
 				currFileContents = ""
 				currFileContents = ""
+				//check if file is symlink
+			} else if fc, err := os.Readlink(fn); err == nil {
+				currFileContents = fc
 			} else {
 			} else {
 				workTreeBuf := bytes.NewBuffer(nil)
 				workTreeBuf := bytes.NewBuffer(nil)
 				workTreeFile, err := wt.Filesystem.Open(fn)
 				workTreeFile, err := wt.Filesystem.Open(fn)
@@ -206,7 +212,7 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 			for _, line := range strings.Split(diffContents, "\n") {
 			for _, line := range strings.Split(diffContents, "\n") {
 				for _, rule := range us.cfg.Rules {
 				for _, rule := range us.cfg.Rules {
 					offender := rule.Inspect(line)
 					offender := rule.Inspect(line)
-					if offender == "" {
+					if offender.IsEmpty() {
 						continue
 						continue
 					}
 					}
 					if us.cfg.Allowlist.RegexAllowed(line) ||
 					if us.cfg.Allowlist.RegexAllowed(line) ||
@@ -220,7 +226,7 @@ func (us *UnstagedScanner) Scan() (Report, error) {
 					if rule.Path.String() != "" && !rule.HasFilePathLeak(filepath.Base(filename)) {
 					if rule.Path.String() != "" && !rule.HasFilePathLeak(filepath.Base(filename)) {
 						continue
 						continue
 					}
 					}
-					leak := NewLeak(line, offender, defaultLineNumber).WithCommit(emptyCommit())
+					leak := NewLeak(line, offender.ToString(), defaultLineNumber).WithCommit(emptyCommit()).WithEntropy(offender.EntropyLevel)
 					leak.File = filename
 					leak.File = filename
 					leak.LineNumber = extractLine(prettyDiff, leak, lineLookup) + 1
 					leak.LineNumber = extractLine(prettyDiff, leak, lineLookup) + 1
 					leak.Repo = us.repoName
 					leak.Repo = us.repoName

+ 1 - 0
test_data/test_additional_config.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: tmp/bad.docx",
   "offender": "Filename or path offender: tmp/bad.docx",
+  "offenderEntropy": -1,
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "repo": "test_repo_10",
   "repo": "test_repo_10",
   "repoURL": "",
   "repoURL": "",

+ 5 - 0
test_data/test_allow_list_docx_no_git.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/.gitignore",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/.gitignore",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/bad.zip",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/bad.zip",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/gitfile.txt",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/gitfile.txt",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/creds.git",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/creds.git",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -67,6 +71,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/somedir.git/secret.key",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/somedir.git/secret.key",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_allow_list_file.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: tmp/bad.docx",
   "offender": "Filename or path offender: tmp/bad.docx",
+  "offenderEntropy": -1,
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "repo": "test_repo_10",
   "repo": "test_repo_10",
   "repoURL": "",
   "repoURL": "",

+ 2 - 0
test_data/test_allow_list_file_no_git.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/somedir.git/secret.key",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/somedir.git/secret.key",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/tmp/bad.docx",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/tmp/bad.docx",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_append_repo.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: tmp/bad.docx",
   "offender": "Filename or path offender: tmp/bad.docx",
+  "offenderEntropy": -1,
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "commit": "b0f9b62dfe12e4e10de180359c6b9276472494f8",
   "repo": "test_repo_10",
   "repo": "test_repo_10",
   "repoURL": "",
   "repoURL": "",

+ 2 - 0
test_data/test_dir1_aws_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_entropy.json

@@ -2,6 +2,7 @@
  {
  {
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "offender": "Entropy range [{P1:4.5 P2:4.7} {P1:5.5 P2:6.3}]",
   "offender": "Entropy range [{P1:4.5 P2:4.7} {P1:5.5 P2:6.3}]",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "rule": "entropy",
   "rule": "entropy",

+ 1 - 0
test_data/test_file1_aws_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",

+ 23 - 0
test_data/test_local_owner_aws_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -67,6 +71,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -83,6 +88,7 @@
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -99,6 +105,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -115,6 +122,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -131,6 +139,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -147,6 +156,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -163,6 +173,7 @@
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -179,6 +190,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -195,6 +207,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -211,6 +224,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -227,6 +241,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "1f2a4abc47dabf991e6af6f9770867ce0ac1f360",
   "commit": "1f2a4abc47dabf991e6af6f9770867ce0ac1f360",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "repoURL": "",
   "repoURL": "",
@@ -243,6 +258,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIAIO5FODNN7EXAMPL2",
   "offender": "AKIAIO5FODNN7EXAMPL2",
+  "offenderEntropy": -1,
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "repoURL": "",
   "repoURL": "",
@@ -259,6 +275,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",
@@ -275,6 +292,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "repoURL": "",
   "repoURL": "",
@@ -291,6 +309,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 2,
   "lineNumber": 2,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -307,6 +326,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -323,6 +343,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -339,6 +360,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "repo": "test_repo_9",
   "repo": "test_repo_9",
   "repoURL": "",
   "repoURL": "",
@@ -355,6 +377,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",

+ 22 - 0
test_data/test_local_owner_aws_leak_allowlist_repo.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -67,6 +71,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -83,6 +88,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -99,6 +105,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -115,6 +122,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -131,6 +139,7 @@
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -147,6 +156,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -163,6 +173,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -179,6 +190,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -195,6 +207,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -211,6 +224,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIAIO5FODNN7EXAMPL2",
   "offender": "AKIAIO5FODNN7EXAMPL2",
+  "offenderEntropy": -1,
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "repoURL": "",
   "repoURL": "",
@@ -227,6 +241,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "1f2a4abc47dabf991e6af6f9770867ce0ac1f360",
   "commit": "1f2a4abc47dabf991e6af6f9770867ce0ac1f360",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "repoURL": "",
   "repoURL": "",
@@ -243,6 +258,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "repoURL": "",
   "repoURL": "",
@@ -259,6 +275,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",
@@ -275,6 +292,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -291,6 +309,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 2,
   "lineNumber": 2,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -307,6 +326,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -323,6 +343,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "repo": "test_repo_9",
   "repo": "test_repo_9",
   "repoURL": "",
   "repoURL": "",
@@ -339,6 +360,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",

+ 7 - 0
test_data/test_local_owner_aws_leak_depth_2.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repos",
   "repo": "test_repos",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "line": "const AWSKEY = \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIAIO5FODNN7EXAMPL2",
   "offender": "AKIAIO5FODNN7EXAMPL2",
+  "offenderEntropy": -1,
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "commit": "ca71fcdeda15f25f0cc661d90e8785c255925c27",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "repoURL": "",
   "repoURL": "",
@@ -67,6 +71,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "repoURL": "",
   "repoURL": "",
@@ -83,6 +88,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -99,6 +105,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE', #gitleaks:allow",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "commit": "8d1fb60d2d80f0590f191ed5ace1e45ef780909a",
   "repo": "test_repo_9",
   "repo": "test_repo_9",
   "repoURL": "",
   "repoURL": "",

+ 3 - 0
test_data/test_local_repo_eight.json

@@ -3,6 +3,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "commit": "748f11eaf2c38c3cf0ac6a22e44208777e79fa6f",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 2,
   "lineNumber": 2,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "commit": "ce7e8177bbf8a172c06b6a1e370a374d5c19f660",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "commit": "9267bc86ec1497471cbc6f3308f3527f7ef34b9d",
   "repo": "test_repo_8",
   "repo": "test_repo_8",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_five_at_latest_commit.json

@@ -3,6 +3,7 @@
   "line": "more_secrets = '99432bfewaf823ec3294e231'",
   "line": "more_secrets = '99432bfewaf823ec3294e231'",
   "lineNumber": 7,
   "lineNumber": 7,
   "offender": "secrets = '99432bfewaf823ec3294e231",
   "offender": "secrets = '99432bfewaf823ec3294e231",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "Generic Credential",
   "rule": "Generic Credential",

+ 1 - 0
test_data/test_local_repo_five_commit.json

@@ -3,6 +3,7 @@
   "line": "more_secrets = '99432bfewaf823ec3294e231'",
   "line": "more_secrets = '99432bfewaf823ec3294e231'",
   "lineNumber": 7,
   "lineNumber": 7,
   "offender": "secrets = '99432bfewaf823ec3294e231",
   "offender": "secrets = '99432bfewaf823ec3294e231",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "Generic Credential",
   "rule": "Generic Credential",

+ 2 - 0
test_data/test_local_repo_five_files_at_commit.json

@@ -3,6 +3,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -18,6 +19,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIAIO5FODNN7EXAMPL2",
   "offender": "AKIAIO5FODNN7EXAMPL2",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 2 - 0
test_data/test_local_repo_five_files_at_latest_commit.json

@@ -3,6 +3,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPLE'",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -18,6 +19,7 @@
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "line": "aws_access_key_id='AKIAIO5FODNN7EXAMPL2'",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIAIO5FODNN7EXAMPL2",
   "offender": "AKIAIO5FODNN7EXAMPL2",
+  "offenderEntropy": -1,
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "commit": "a4c9fb737d5552fd96fce5cc7eedb23353ba9ed0",
   "repo": "test_repo_5",
   "repo": "test_repo_5",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 2 - 0
test_data/test_local_repo_four_alt_config_entropy.json

@@ -3,6 +3,7 @@
   "line": "const AWSSECRET = \"99432bfewaf823ec3294e231\"",
   "line": "const AWSSECRET = \"99432bfewaf823ec3294e231\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "\"99432bfewaf823ec3294e231\"",
   "offender": "\"99432bfewaf823ec3294e231\"",
+  "offenderEntropy": 3.355,
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "commit": "84ac4e80d4dbf2c968b64e9d4005f5079795bb81",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "    const AWSSECRET = \"99432bfewaf823ec3294e231\"",
   "line": "    const AWSSECRET = \"99432bfewaf823ec3294e231\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "\"99432bfewaf823ec3294e231\"",
   "offender": "\"99432bfewaf823ec3294e231\"",
+  "offenderEntropy": 3.355,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",

+ 2 - 0
test_data/test_local_repo_four_leaks_commit_timerange.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_4",
   "repo": "test_repo_4",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_nine_aws_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_9",
   "repo": "test_repo_9",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_one_aws_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_one_aws_leak_and_file_leak.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_one_aws_leak_commit.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_one_aws_leak_uncommitted.json

@@ -3,6 +3,7 @@
   "line": " aws_access_key_id='AKIAIO5FODNN7DXAMPLE'",
   "line": " aws_access_key_id='AKIAIO5FODNN7DXAMPLE'",
   "lineNumber": 10,
   "lineNumber": 10,
   "offender": "AKIAIO5FODNN7DXAMPLE",
   "offender": "AKIAIO5FODNN7DXAMPLE",
+  "offenderEntropy": -1,
   "commit": "0000000000000000000000000000000000000000",
   "commit": "0000000000000000000000000000000000000000",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_seven_aws_leak_uncommitted.json

@@ -3,6 +3,7 @@
   "line": "AKIAIO5FODNN7EXAMPLE",
   "line": "AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "0000000000000000000000000000000000000000",
   "commit": "0000000000000000000000000000000000000000",
   "repo": "test_repo_7",
   "repo": "test_repo_7",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 3 - 0
test_data/test_local_repo_six.json

@@ -3,6 +3,7 @@
   "line": "api_token: exampleSecretPassword",
   "line": "api_token: exampleSecretPassword",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "token: exampleSecretPassword",
   "offender": "token: exampleSecretPassword",
+  "offenderEntropy": -1,
   "commit": "e7bf376f855ae9bc6e3bb27b5f9d65c57eba799d",
   "commit": "e7bf376f855ae9bc6e3bb27b5f9d65c57eba799d",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "Generic password",
   "rule": "Generic password",
@@ -17,6 +18,7 @@
   "line": "db_password_token: exampleSecretPassword",
   "line": "db_password_token: exampleSecretPassword",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "password_token: exampleSecretPassword",
   "offender": "password_token: exampleSecretPassword",
+  "offenderEntropy": -1,
   "commit": "e7bf376f855ae9bc6e3bb27b5f9d65c57eba799d",
   "commit": "e7bf376f855ae9bc6e3bb27b5f9d65c57eba799d",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "Generic password",
   "rule": "Generic password",
@@ -31,6 +33,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "95cf0237f8cdfc0686a29df08260d8635f46c9b0",
   "commit": "95cf0237f8cdfc0686a29df08260d8635f46c9b0",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 2 - 0
test_data/test_local_repo_six_filename.json

@@ -3,6 +3,7 @@
   "line": "api_token: exampleSecretPassword",
   "line": "api_token: exampleSecretPassword",
   "lineNumber": 2,
   "lineNumber": 2,
   "offender": "token: exampleSecretPassword",
   "offender": "token: exampleSecretPassword",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "Generic password",
   "rule": "Generic password",
@@ -18,6 +19,7 @@
   "line": "db_password: verySecretProductionPassword",
   "line": "db_password: verySecretProductionPassword",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "password: verySecretProductionPassword",
   "offender": "password: verySecretProductionPassword",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "Generic password",
   "rule": "Generic password",

+ 1 - 0
test_data/test_local_repo_six_filepath.json

@@ -3,6 +3,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_six_filepath_filename.json

@@ -3,6 +3,7 @@
   "line": "apiToken=d41d8cd98f00b204e9800998ecf8427e",
   "line": "apiToken=d41d8cd98f00b204e9800998ecf8427e",
   "lineNumber": 2,
   "lineNumber": 2,
   "offender": "Token=d41d8cd98f00b204e9800998ecf8427e",
   "offender": "Token=d41d8cd98f00b204e9800998ecf8427e",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "Generic password",
   "rule": "Generic password",

+ 1 - 0
test_data/test_local_repo_six_leaks_since_date.json

@@ -3,6 +3,7 @@
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "line": "aws_access_key_id=AKIAIO5FODNN7EXAMPLE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "commit": "98b6c7cb3fb29a5993c4c95c56a2dc53050b9247",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_six_leaks_until_date.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 1 - 0
test_data/test_local_repo_six_path_globally_allowlisted.json

@@ -3,6 +3,7 @@
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "line": "    aws_access_key_id='AKIAIO5FODNN7EXAMPLE',",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIAIO5FODNN7EXAMPLE",
   "offender": "AKIAIO5FODNN7EXAMPLE",
+  "offenderEntropy": -1,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_6",
   "repo": "test_repo_6",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 4 - 0
test_data/test_local_repo_three_leaks.json

@@ -3,6 +3,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",

+ 3 - 0
test_data/test_local_repo_three_leaks_with_report_groups.json

@@ -3,6 +3,7 @@
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "commit": "deea550dd6c7acaf0e59432600593533984a2125",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_3",
   "repo": "test_repo_3",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_two_allowlist_commits.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 3 - 0
test_data/test_local_repo_two_leaks.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 2 - 0
test_data/test_local_repo_two_leaks_commit_from.json

@@ -3,6 +3,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 2 - 0
test_data/test_local_repo_two_leaks_commit_range.json

@@ -3,6 +3,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_two_leaks_commit_to.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 4,
   "lineNumber": 4,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_local_repo_two_leaks_commit_to_from.json

@@ -3,6 +3,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 6 - 0
test_data/test_local_repo_two_leaks_deletion.json

@@ -3,6 +3,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": -1,
   "lineNumber": -1,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "f61cd8587b7ac1d75a89a0c9af870a2f24c60263",
   "commit": "f61cd8587b7ac1d75a89a0c9af870a2f24c60263",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -18,6 +19,7 @@
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "line": "    const AWSKEY = \"AKIALALEMEL33243OLIBE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIB",
   "offender": "AKIALALEMEL33243OLIB",
+  "offenderEntropy": -1,
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "commit": "b2eb34a61c988afd9b4aaa9dd58c8dd7d5f14dba",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -33,6 +35,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": -1,
   "lineNumber": -1,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "996865bb912f3bc45898a370a13aadb315014b55",
   "commit": "996865bb912f3bc45898a370a13aadb315014b55",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -48,6 +51,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": -1,
   "lineNumber": -1,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -63,6 +67,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 5,
   "lineNumber": 5,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",
@@ -78,6 +83,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "rule": "AWS Access Key",
   "rule": "AWS Access Key",

+ 2 - 0
test_data/test_local_repo_two_leaks_file_commit_range.json

@@ -3,6 +3,7 @@
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "line": "Here's an AWS secret: \"AKIALALEMEL33243OLIAE\"",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "commit": "17471a5fda722a9e423f1a0d3f0d267ea009d41c",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "line": "Here's an AWS secret: AKIALALEMEL33243OLIAE",
   "lineNumber": 3,
   "lineNumber": 3,
   "offender": "AKIALALEMEL33243OLIA",
   "offender": "AKIALALEMEL33243OLIA",
+  "offenderEntropy": -1,
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "commit": "b10b3e2cb320a8c211fda94c4567299d37de7776",
   "repo": "test_repo_2",
   "repo": "test_repo_2",
   "repoURL": "",
   "repoURL": "",

+ 9 - 0
test_data/test_only_files_no_git.json

@@ -3,6 +3,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/README.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_10/README.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -19,6 +20,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_2/secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_2/secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -35,6 +37,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_2/no_secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_2/no_secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -51,6 +54,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_3/no_secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_3/no_secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -67,6 +71,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_3/secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_3/secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -83,6 +88,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_4/secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_4/secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -99,6 +105,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_4/no_secrets.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_4/no_secrets.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -115,6 +122,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_5/notes.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_5/notes.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",
@@ -131,6 +139,7 @@
   "line": "",
   "line": "",
   "lineNumber": 1,
   "lineNumber": 1,
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_8/README.md",
   "offender": "Filename or path offender: ../test_data/test_repos/test_repo_8/README.md",
+  "offenderEntropy": -1,
   "commit": "",
   "commit": "",
   "repo": "",
   "repo": "",
   "repoURL": "",
   "repoURL": "",

+ 1 - 0
test_data/test_regex_entropy.json

@@ -3,6 +3,7 @@
   "line": "    aws_secret_access_key='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'",
   "line": "    aws_secret_access_key='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'",
   "lineNumber": 6,
   "lineNumber": 6,
   "offender": "'ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'",
   "offender": "'ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE'",
+  "offenderEntropy": 4.631,
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "commit": "6557c92612d3b35979bd426d429255b3bf9fab74",
   "repo": "test_repo_1",
   "repo": "test_repo_1",
   "rule": "entropy and regex",
   "rule": "entropy and regex",