Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGES/+add_support_for_gitleaks.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Taught plugin-template how to interact with .gitleaks.toml files.
6 changes: 6 additions & 0 deletions plugin-template
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,12 @@ def write_template_section(
destination,
template_vars,
)
elif destination.startswith(".gitleaks.toml."):
utils.merge_gitleaks(
template,
plugin_root_dir,
destination,
)
else:
utils.template_to_file(
template,
Expand Down
1 change: 1 addition & 0 deletions templates/bootstrap/pyproject.toml.j2
Copy link
Copy Markdown
Member

@pedro-psb pedro-psb Mar 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be convenient to add/merge a ".gitleaks.toml" to the plugin's check-manifest ignore section (not only to the bootstrap). Otherwise the CI will fail (if it didn't had the gitleaks already) and it will require us to add that manually.

Original file line number Diff line number Diff line change
Expand Up @@ -118,5 +118,6 @@ ignore = [
".dependabot/config.yml",
".ci/**",
".github/**",
".gitleaks.toml",
]
{% endif %}
10 changes: 10 additions & 0 deletions templates/github/.gitleaks.toml.allowlist.j2
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[allowlist]
description = "Allow specific test-keys."
paths = [
]
regexes = [
'''AKIAIT2Z5TDYPX3ARJBA''',
'''qR\+vjWPU50fCqQuUWbj9Fain/j2pV\+ZtBCiDiieS''',
'''fqRvjWaPU5o0fCqQuUWbj9Fainj2pVZtBCiDiieS''',
'''Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw''',
]
52 changes: 52 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,58 @@ def template_to_file(template, plugin_root_path, relative_path, template_vars):
destination_path.chmod(mode)


def merge_gitleaks(template, plugin_root_path, relative_path, template_vars={}):
"""
Take values from .gitleaks.allowlist.j2 and insert them into the allowlist of
an existing .gitleaks.toml file, or create said file otherwise.
"""
basename, merge_key = relative_path.split(".toml.", maxsplit=1)
# "allowlist" is all we recognize for gitleaks
assert "allowlist" == merge_key
# We aren't using template-vars *currently* - but may want to at some point.
data = tomlkit.loads(template.render(**template_vars))
path = Path(plugin_root_path / f"{basename}.toml")
if path.exists():
old_toml = tomlkit.load(path.open())
if merge_key not in old_toml:
old_toml["allowlist"] = data["allowlist"]
else:
old_toml["allowlist"]["description"] = data["allowlist"]["description"]
merge_sets("paths", data, old_toml)
merge_sets("regexes", data, old_toml)

else:
old_toml = data
# Update MANIFEST.in to ignore the file we're about to create
# (if we are only updating .gitleaks, we 'assume' it's already being ignored)
manifest = Path(plugin_root_path / "MANIFEST.in")
if manifest.exists():
# MANIFEST.in is small enough to look at the whole thing at once
manifest_contents = manifest.read_text()
if ".gitleaks.toml" not in manifest_contents:
manifest.write_text(manifest_contents + "\nexclude .gitleaks.toml")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

output = tomlkit.dumps(old_toml)
if output[-1] != "\n":
output = output + "\n"
path.write_text(output)


def merge_sets(key, data, old_toml):
"""
For a given key, merge any existing values and incoming new ones.
Use set() to get rid of duplicates, use sorted() to enforce ordering.
If incoming values are already a subset of the existing ones - nothing to do here.
"""
if key in old_toml["allowlist"]:
old_values = set(old_toml["allowlist"][key])
new_values = set(data["allowlist"][key])
if new_values.issubset(old_values): # Everything we want to add is already there
return
old_toml["allowlist"][key] = sorted(old_values.union(new_values))
else:
old_toml["allowlist"][key] = sorted(set(data["allowlist"][key]))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



def merge_toml(template, plugin_root_path, relative_path, template_vars):
"""
Template a file of the form 'basename.toml.merge_key' and combine its content beneath
Expand Down