Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scan only PR commits for Gitleaks instead of whole codebase #2504

Merged
merged 30 commits into from
May 13, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
352153f
quick build
DariuszPorowski Mar 31, 2023
03d2b8a
quick build
DariuszPorowski Apr 1, 2023
681e00c
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 1, 2023
d7bb2c9
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 2, 2023
3e8c464
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 2, 2023
344b291
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 2, 2023
55f91ca
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 2, 2023
364d49a
@DariuszPorowski
DariuszPorowski Apr 2, 2023
22703ac
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 2, 2023
a738366
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 3, 2023
49278d0
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 4, 2023
c85988c
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 4, 2023
7b0f75d
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 23, 2023
01731f4
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 23, 2023
1c7290a
remove casefold
DariuszPorowski Apr 23, 2023
fd3308a
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski Apr 30, 2023
d7b2eb7
changelog
DariuszPorowski Apr 30, 2023
2c69985
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 30, 2023
cff15a0
quick build TEST_KEYWORDS=repository_gitleaks
DariuszPorowski Apr 30, 2023
dbe3215
update gitleaks descriptor
DariuszPorowski May 2, 2023
16fe70a
Merge branch 'main' into 2487-gitleaks-pr
DariuszPorowski May 2, 2023
ab59d78
update config.get
DariuszPorowski May 2, 2023
0777480
docs build
DariuszPorowski May 2, 2023
4b4b074
fix utils_reporter conflict
DariuszPorowski May 2, 2023
0026792
typo
DariuszPorowski May 2, 2023
62b2fca
style utils_reporter
DariuszPorowski May 2, 2023
c67a8a3
update utils to new standard
DariuszPorowski May 2, 2023
5829a54
Merge branch 'main' into 2487-gitleaks-pr
nvuillam May 13, 2023
42ca90e
build
nvuillam May 13, 2023
622d0f1
Merge branch 'main' into 2487-gitleaks-pr
nvuillam May 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/linters/.cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,7 @@
"sososhhhyyso",
"sourcefilepath",
"sourceroot",
"sourceversion",
"splitchar",
"sprintf",
"sqlfluff",
Expand Down Expand Up @@ -1261,6 +1262,8 @@
"tableofcontents",
"tabularx",
"tagname",
"targetbranch",
"targetbranchname",
"tcort",
"tekton",
"tektonlintrc",
Expand Down
36 changes: 34 additions & 2 deletions docs/descriptors/repository_gitleaks.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ description: How to use gitleaks (configure, ignore files, ignore errors, help &
<!-- markdownlint-disable MD033 MD041 -->
<!-- @generated by .automation/build.py, please do not update manually -->
# gitleaks

[![GitHub stars](https://img.shields.io/github/stars/zricethezav/gitleaks?cacheSeconds=3600)](https://github.com/zricethezav/gitleaks) ![sarif](https://shields.io/badge/-SARIF-orange) [![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/zricethezav/gitleaks?sort=semver)](https://github.com/zricethezav/gitleaks/releases) [![GitHub last commit](https://img.shields.io/github/last-commit/zricethezav/gitleaks)](https://github.com/zricethezav/gitleaks/commits) [![GitHub commit activity](https://img.shields.io/github/commit-activity/y/zricethezav/gitleaks)](https://github.com/zricethezav/gitleaks/graphs/commit-activity/) [![GitHub contributors](https://img.shields.io/github/contributors/zricethezav/gitleaks)](https://github.com/zricethezav/gitleaks/graphs/contributors/)

## gitleaks documentation
Expand All @@ -31,6 +32,7 @@ description: How to use gitleaks (configure, ignore files, ignore errors, help &
| REPOSITORY_GITLEAKS_RULES_PATH | Path where to find linter configuration file | Workspace folder, then MegaLinter default rules |
| REPOSITORY_GITLEAKS_DISABLE_ERRORS | Run linter but consider errors as warnings | `false` |
| REPOSITORY_GITLEAKS_DISABLE_ERRORS_IF_LESS_THAN | Maximum number of errors allowed | `0` |
| REPOSITORY_GITLEAKS_ONLY_PR_COMMITS | Scan only PR commits on Pull Request | `false` |

## MegaLinter Flavours

Expand Down Expand Up @@ -67,8 +69,38 @@ This linter is available in the following flavours

gitleaks is called once on the whole project directory (`project` CLI lint mode)

- filtering can not be done using MegaLinter configuration variables,it must be done using gitleaks configuration or ignore file (if existing)
- `VALIDATE_ALL_CODEBASE: false` does not make gitleaks analyze only updated files
- filtering can not be done using MegaLinter configuration variables, it must be done using gitleaks configuration itself like: [baseline](https://github.com/gitleaks/gitleaks#creating-a-baseline){target=_blank}, allowlists in [.gitleaks.toml](https://github.com/gitleaks/gitleaks#configuration){target=_blank} or [.gitleaksignore](https://github.com/gitleaks/gitleaks#gitleaksignore){target=_blank}
- `VALIDATE_ALL_CODEBASE: false` does make gitleaks analyze only commits on Pull Request, but only for selected tools: GitHub Actions, Azure Pipelines, GitLab Piplines\* (Merge Requests and External Pull Requestes)
- \* Only GitLab self-managed and GitLab SaaS (Premium and Ultimate) are supported (limitation due to GitLab itself) and [Merge result pipelines](https://docs.gitlab.com/ee/ci/pipelines/merged_results_pipelines.html#enable-merged-results-pipelines){target=_blank} feature has to be enabled.
- If `VALIDATE_ALL_CODEBASE: false` and MegaLinter with the gitleaks runs on PR on the not listed tool above, then the analysis is performed on the whole repository (checked-out commits - depends on fetch-depth configuration).


#### Repository checkout on Pull Requests

To scan only PR commits, a complete repository checkout is required buy setting fetch-depth 0. Below is example configuration for supported scenarios:

##### GitHub Actions

```yml
- uses: actions/checkout@v3
with:
fetch-depth: 0
```

##### Azure Pipelines

```yml
- checkout: self
fetchDepth: 0
```

##### GitLab Pipelines

```yml
variables:
GIT_DEPTH: 0
```


### Example calls

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10270,6 +10270,12 @@
"title": "REPOSITORY_GITLEAKS: Custom config file path",
"type": "string"
},
"REPOSITORY_GITLEAKS_ONLY_PR_COMMITS": {
"$id": "#/properties/REPOSITORY_GITLEAKS_ONLY_PR_COMMITS",
"default": false,
"title": "REPOSITORY_GITLEAKS: Scan only PR commits on Pull Request",
"type": "boolean"
},
"REPOSITORY_GIT_DIFF_ARGUMENTS": {
"$id": "#/properties/REPOSITORY_GIT_DIFF_ARGUMENTS",
"description": "REPOSITORY_GIT_DIFF: User custom arguments to add in linter CLI call",
Expand Down Expand Up @@ -15026,4 +15032,4 @@
"type": "string"
}
}
}
}
95 changes: 94 additions & 1 deletion megalinter/linters/GitleaksLinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,97 @@
"""
Use GitLeaks to check for credentials in repository
"""
import json
import os

from megalinter import Linter
from git import Repo

from megalinter import Linter, config
from megalinter.utils import is_git_repo


class GitleaksLinter(Linter):
def __init__(self, params=None, linter_config=None):
super().__init__(params, linter_config)
self.only_pr_commits = config.get("REPOSITORY_GITLEAKS_ONLY_PR_COMMITS", "false")
if self.only_pr_commits == "true":
self.is_pr, self.pr_source_sha, self.pr_target_sha = self.get_pr_data()


def get_pr_data(self):
DariuszPorowski marked this conversation as resolved.
Show resolved Hide resolved
# https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml
is_azure_devops_pr = config.get("BUILD_REASON") == "PullRequest"
azure_devops_pr_source_sha = config.get("BUILD_SOURCEVERSION")
azure_devops_pr_target_sha = self.get_azure_devops_pr_target_sha(config.get("SYSTEM_PULLREQUEST_TARGETBRANCH"), is_azure_devops_pr)

# https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables
is_github_pr = config.get("GITHUB_EVENT_NAME") == "pull_request"
github_pr_source_sha, github_pr_target_sha = self.get_github_sha(is_github_pr)

# https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
# SHAs are available only on GitLab Premium
is_gitlab_premium = (
True
if config.get("CI_MERGE_REQUEST_EVENT_TYPE") == "merged_result" or config.get("CI_MERGE_REQUEST_EVENT_TYPE") == "merge_train"
else False
)

# GitLab merge request
is_gitlab_mr = config.get("CI_PIPELINE_SOURCE") == "merge_request_event"
gitlab_mr_source_sha = config.get("CI_MERGE_REQUEST_SOURCE_BRANCH_SHA")
gitlab_mr_target_sha = config.get("CI_MERGE_REQUEST_TARGET_BRANCH_SHA")

# GitLab external PR #
is_gitlab_external_pr = config.get("CI_PIPELINE_SOURCE") == "external_pull_request_event"
gitlab_external_pr_source_sha = config.get("CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_SHA")
gitlab_external_pr_target_sha = config.get("CI_EXTERNAL_PULL_REQUEST_TARGET_BRANCH_SHA")

is_pr = (
True
if (
is_azure_devops_pr
or is_github_pr
or (is_gitlab_mr and is_gitlab_premium)
or (is_gitlab_external_pr and is_gitlab_premium)
)
else False
)

pr_source_sha = None
pr_target_sha = None

if is_azure_devops_pr:
pr_source_sha = azure_devops_pr_source_sha
pr_target_sha = azure_devops_pr_target_sha
elif is_github_pr:
pr_source_sha = github_pr_source_sha
pr_target_sha = github_pr_target_sha
elif is_gitlab_mr:
pr_source_sha = gitlab_mr_source_sha
pr_target_sha = gitlab_mr_target_sha
elif is_gitlab_external_pr:
pr_source_sha = gitlab_external_pr_source_sha
pr_target_sha = gitlab_external_pr_target_sha

return is_pr, pr_source_sha, pr_target_sha

def get_azure_devops_pr_target_sha(self, target_branch_name, is_pr=False):
if not is_pr:
return None
repo = Repo(os.path.realpath(self.workspace))
return repo.commit(target_branch_name.replace("refs/heads", "origin"))

def get_github_sha(self, is_pr=False):
if not is_pr:
return None, None
gh_event_file = open(os.environ["GITHUB_EVENT_PATH"])
gh_event = json.load(gh_event_file)
gh_event_file.close()
return (
gh_event["pull_request"]["head"]["sha"],
gh_event["pull_request"]["base"]["sha"],
)

# Manage presence of --no-git in command line
def build_lint_command(self, file=None):
cmd = super().build_lint_command(file)
Expand All @@ -19,4 +104,12 @@ def build_lint_command(self, file=None):
# but as it is a git repo, remove all --no-git from arguments list
elif "--no-git" in cmd and is_git_repo(self.workspace):
cmd = list(filter(lambda a: a != "--no-git", cmd))

if config.get("VALIDATE_ALL_CODEBASE") == "false" and self.only_pr_commits == "true":
if self.is_pr:
if self.pr_target_sha != self.pr_source_sha:
cmd += [
f"--log-opts={self.pr_target_sha}^..{self.pr_source_sha}"
]

return cmd
Loading