Add pre-commit config for repo hygiene and secret detection - #30
Add pre-commit config for repo hygiene and secret detection#30Harshaada wants to merge 1 commit into
Conversation
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe pull request expands pre-commit configuration with private-key detection and Gitleaks scanning. It excludes ChangesSecret Scanning Setup
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.pre-commit-config.yaml:
- Around line 4-5: Update the pre-commit usage comments to accurately describe
the coverage of `pre-commit run --all-files`, noting that
`scripts/check-secrets.sh` scans only staged added, copied, or modified files
because filename passing is disabled. Either document this as staged-only
coverage or add and document a separate full-tree scan mode.
- Around line 28-30: Update scripts/check-secrets.sh, specifically the output
for matches triggered by the check-secrets hook, so it never prints full
matching lines containing secrets. Report only the detection rule, file path,
and line number, or replace the matched secret with a redacted value while
preserving the existing five-match limit and detection behavior.
- Around line 11-23: Configure Gitleaks explicitly for the vendor/ path by
adding a global vendor/ allowlist in .gitleaks.toml, or remove vendor/ from the
pre-commit exclude if it is not trusted generated content; update the gitleaks
hook configuration without changing the detect-private-key hook.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a878ef22-e975-44e2-a8fb-64c63b51cf9d
📒 Files selected for processing (2)
.pre-commit-config.yamlREADME.md
| # Install: pip install pre-commit && pre-commit install | ||
| # Run manually: pre-commit run --all-files |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Do not describe --all-files as a full secret scan.
Line 32 disables filename passing, and scripts/check-secrets.sh builds its file list from git diff --cached --diff-filter=ACM. Therefore the command at Lines 4-5 checks only staged added, copied, or modified files for this hook. Add a full-tree scan mode, or document staged-only coverage.
Also applies to: 32-32
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.pre-commit-config.yaml around lines 4 - 5, Update the pre-commit usage
comments to accurately describe the coverage of `pre-commit run --all-files`,
noting that `scripts/check-secrets.sh` scans only staged added, copied, or
modified files because filename passing is disabled. Either document this as
staged-only coverage or add and document a separate full-tree scan mode.
| exclude: "^vendor/" | ||
|
|
||
| repos: | ||
| - repo: https://github.com/pre-commit/pre-commit-hooks | ||
| rev: v6.0.0 | ||
| hooks: | ||
| - id: detect-private-key | ||
|
|
||
| # Secret detection (same approach as usernaut / template-ui) | ||
| - repo: https://github.com/gitleaks/gitleaks | ||
| rev: v8.28.0 | ||
| hooks: | ||
| - id: gitleaks |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
url='https://raw.githubusercontent.com/gitleaks/gitleaks/v8.28.0/.pre-commit-hooks.yaml'
curl -fsSL "$url" |
grep -nE -A8 'id: gitleaks|entry:|pass_filenames:|args:'Repository: redhat-data-and-ai/fivetran-operator
Length of output: 851
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- .pre-commit-config.yaml ---'
sed -n '1,120p' .pre-commit-config.yaml
printf '%s\n' '--- scripts/check-secrets.sh ---'
if [ -f scripts/check-secrets.sh ]; then
sed -n '1,200p' scripts/check-secrets.sh
else
printf '%s\n' 'missing'
fi
printf '%s\n' '--- tracked vendor paths ---'
git ls-files vendor | sed -n '1,80p'
printf 'tracked_vendor_count='
git ls-files vendor | wc -l
printf '%s\n' '--- vendor references and generation markers ---'
rg -n -i 'vendor|generated|go mod vendor|check-secrets|gitleaks' \
--glob '!vendor/**' \
--glob '!.git/**' \
. | sed -n '1,240p'Repository: redhat-data-and-ai/fivetran-operator
Length of output: 13807
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- vendor configuration ---'
rg -n -i 'vendor|go mod vendor|GOFLAGS|mod=' \
go.mod go.work go.sum Makefile .gitignore .gitattributes README.md \
--no-messages | sed -n '1,200p'
printf '%s\n' '--- hook documentation context ---'
sed -n '1,45p' README.md
sed -n '1,70p' .gitignore
printf '%s\n' '--- tracked vendor file classes ---'
git ls-files vendor | awk '
BEGIN { files=0; go=0; docs=0; configs=0; }
{
files++;
if ($0 ~ /\.go$/) go++;
if ($0 ~ /\.(md|txt|rst|adoc)$/ || $0 ~ /(^|\/)(LICENSE|NOTICE|COPYING)(\..*)?$/) docs++;
if ($0 ~ /\.(ya?ml|json|toml|ini|cfg|conf|bazel|bzl)$/ || $0 ~ /(^|\/)(BUILD|MODULE|WORKSPACE)(\..*)?$/) configs++;
}
END {
printf "files=%d go=%d docs_or_licenses=%d configs=%d\n", files, go, docs, configs;
}'Repository: redhat-data-and-ai/fivetran-operator
Length of output: 440
🌐 Web query:
pre-commit documentation exclude pass_filenames false hook files filtering behavior
💡 Result:
In pre-commit, the pass_filenames: false hook configuration serves a specific, narrow purpose: it prevents the framework from appending matched filenames as positional arguments to your command [1][2]. It does not disable the file filtering logic itself [3]. Key behaviors include: Filtering remains active: The files, types, and exclude options continue to function as normal [3]. The framework still identifies which files match your criteria to determine whether the hook should run [3]. If no files match the criteria (and always_run is not set to true), the hook will be skipped [4]. No filenames passed: When the hook is triggered, pre-commit executes the command without passing any of the matched file paths as arguments [1][2]. This is useful for tools that manage their own file discovery (e.g., linters that read from a configuration file or execute on a whole directory) [5][6]. No impact on triggering: The setting only affects the command-line arguments. It does not stop the hook from being triggered by file changes; it simply changes the mechanism of invocation [3]. Because pass_filenames: false changes how the hook interacts with your command, ensure your entry and args are configured correctly to perform the desired action (e.g., linting a directory) without expecting individual file paths from the shell [7][6]. If you need to trigger a hook even when no files are matched, you must use the always_run: true setting [8][5][4].
Citations:
- 1: https://pre-commit.com/
- 2: https://stackoverflow.com/questions/57199833/run-pre-commit-com-hook-once-not-for-every-file-if-a-matched-file-is-detected
- 3: Filtering which files to pass VS filtering for which files to trigger the hook pre-commit/pre-commit#1214
- 4: https://github.com/pre-commit/pre-commit/blob/main/pre_commit/commands/run.py
- 5: Add hook option to not pass matching files as arguments to the program pre-commit/pre-commit#527
- 6: "Pass directories" option pre-commit/pre-commit#1784
- 7: https://stackoverflow.com/questions/77350979/running-pre-commits-excluding-a-directory-for-multiples-hooks
- 8: Hook with
pass_filenames: falsedoesn't trigger when affected files are deleted pre-commit/pre-commit#3502
🌐 Web query:
Gitleaks v8.28.0 pre-commit hook --staged exclude vendor path configuration
💡 Result:
To exclude a path (such as a vendor directory) from Gitleaks v8.28.0 when running as a pre-commit hook, you must use the global allowlist configuration in your Gitleaks configuration file (e.g.,.gitleaks.toml) [1][2]. 1. Create or update your.gitleaks.toml file in the root of your repository [3][4]. 2. Add the [allowlist] section and include the path to be excluded using the paths key. Use regex patterns to define the directory or files you wish to ignore [1][5][2]. Example configuration to exclude a vendor directory: [allowlist] description = "Global allowlist to exclude vendor directory" paths = [ '''(^|/)vendor/.*''' ] [extend] useDefault = true Important considerations: - Global Allowlist: Ensure you use the global [allowlist] table rather than a rule-specific [[rules.allowlist]] table to ensure the exclusion applies across all rules [1][2]. - Use Default Rules: If you define your own configuration file, you must include [extend] useDefault = true if you still want to utilize the built-in Gitleaks secret detection rules [1][5]. - Pre-commit Setup: Ensure your.pre-commit-config.yaml is correctly pointing to your custom configuration file if necessary, though Gitleaks typically detects.gitleaks.toml automatically in the project root [3][4]. Gitleaks v8.28.0 also introduced composite rules, but this feature pertains to secret detection logic (proximity matching) and does not alter the fundamental method for excluding paths via the allowlist [6].
Citations:
- 1: GitLeaks not ignoring folder (pre-commit) gitleaks/gitleaks#1023
- 2: https://github.com/gitleaks/gitleaks/tree/7098f6d958ddf7a96448737edea8ae1dc9e6a660
- 3: https://github.com/gitleaks/gitleaks
- 4: https://github.com/gitleaks/gitleaks/blob/master/README.md
- 5: Simple example needed on how to ignore or whitelist a directory gitleaks/gitleaks#1328
- 6: https://github.com/gitleaks/gitleaks/releases/tag/v8.28.0
🏁 Script executed:
#!/usr/bin/env bash
set -u
printf '%s\n' '--- existing module and vendor metadata ---'
for file in go.mod go.work go.sum Makefile .gitignore .gitattributes vendor/modules.txt; do
if [ -f "$file" ]; then
printf '\n--- %s ---\n' "$file"
case "$file" in
Makefile) rg -n -C 3 -i 'vendor|go mod vendor' "$file" || true ;;
go.mod|go.work|go.sum) sed -n '1,35p' "$file" ;;
*) sed -n '1,45p' "$file" ;;
esac
fi
done
printf '%s\n' '--- Gitleaks configuration files ---'
git ls-files '*gitleaks*' '.gitleaks.toml' '.gitleaks/*' | sed -n '1,80p'Repository: redhat-data-and-ai/fivetran-operator
Length of output: 7538
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
import subprocess
config = Path(".pre-commit-config.yaml").read_text()
gitignore = Path(".gitignore").read_text()
tracked_vendor = subprocess.check_output(
["git", "ls-files", "vendor"], text=True
).splitlines()
hook = re.search(
r"- repo: https://github\.com/gitleaks/gitleaks.*?"
r"(?=\n - repo:|\Z)",
config,
re.S,
)
if not hook:
raise SystemExit("gitleaks hook not found")
hook_text = hook.group(0)
entry = re.search(r"entry:\s*(.+)", hook_text)
pass_filenames = re.search(r"pass_filenames:\s*(\w+)", hook_text)
print(f"top_level_exclude={re.search(r'exclude:\s*\"\^vendor/\"', config) is not None}")
print(f"gitleaks_entry={entry.group(1) if entry else '<not found>'}")
print(f"gitleaks_pass_filenames={pass_filenames.group(1) if pass_filenames else '<default true>'}")
print(f"gitleaks_runs_staged_scan={'--staged' in hook_text}")
print(f"tracked_vendor_files={len(tracked_vendor)}")
print(f"vendor_metadata_tracked={Path('vendor/modules.txt').as_posix() in tracked_vendor}")
print(f"gitignore_describes_vendored_files={'except for vendored files' in gitignore}")
print(f"gitleaks_config_present= {Path('.gitleaks.toml').exists() or Path('.gitleaks').exists()}")
PYRepository: redhat-data-and-ai/fivetran-operator
Length of output: 451
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
import subprocess
config = Path(".pre-commit-config.yaml").read_text()
gitignore = Path(".gitignore").read_text()
tracked_vendor = subprocess.check_output(
["git", "ls-files", "vendor"], text=True
).splitlines()
hook = re.search(
r"- repo: https://github\.com/gitleaks/gitleaks.*?"
r"(?=\n - repo:|\Z)",
config,
re.S,
)
if not hook:
raise SystemExit("gitleaks hook not found")
hook_text = hook.group(0)
entry_match = re.search(r"entry:\s*(.+)", hook_text)
pass_match = re.search(r"pass_filenames:\s*(\w+)", hook_text)
top_level_exclude = bool(re.search(r'exclude:\s*"\\\^vendor/"', config))
print("top_level_exclude=", top_level_exclude)
print("gitleaks_entry=", entry_match.group(1) if entry_match else "<not found>")
print("gitleaks_pass_filenames=", pass_match.group(1) if pass_match else "<default true>")
print("gitleaks_runs_staged_scan=", "--staged" in hook_text)
print("tracked_vendor_files=", len(tracked_vendor))
print("vendor_metadata_tracked=", "vendor/modules.txt" in tracked_vendor)
print("gitignore_describes_vendored_files=", "except for vendored files" in gitignore)
print(
"gitleaks_config_present=",
Path(".gitleaks.toml").exists() or Path(".gitleaks").exists(),
)
PYRepository: redhat-data-and-ai/fivetran-operator
Length of output: 430
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
import subprocess
import urllib.request
config = Path(".pre-commit-config.yaml").read_text()
tracked_vendor = subprocess.check_output(
["git", "ls-files", "vendor"], text=True
).splitlines()
hook_yaml = urllib.request.urlopen(
"https://raw.githubusercontent.com/gitleaks/gitleaks/v8.28.0/.pre-commit-hooks.yaml"
).read().decode()
local_exclude = re.search(r'^exclude:\s*"([^"]+)"\s*$', config, re.M)
gitleaks_block = re.search(
r"(?m)^- id: gitleaks$\n(?:(?!^-\s+id:).)*",
hook_yaml,
re.S,
)
if not gitleaks_block:
raise SystemExit("gitleaks hook definition not found")
block = gitleaks_block.group(0)
entry = re.search(r"(?m)^ entry:\s*(.+)$", block)
pass_filenames = re.search(r"(?m)^ pass_filenames:\s*(\w+)$", block)
print("local_exclude=", local_exclude.group(1) if local_exclude else "<not found>")
print("remote_gitleaks_entry=", entry.group(1) if entry else "<not found>")
print(
"remote_gitleaks_pass_filenames=",
pass_filenames.group(1) if pass_filenames else "<default true>",
)
print("remote_gitleaks_uses_staged=", "--staged" in block)
print("tracked_vendor_files=", len(tracked_vendor))
print("vendor_modules_tracked=", "vendor/modules.txt" in tracked_vendor)
print(
"gitleaks_config_present=",
Path(".gitleaks.toml").exists() or Path(".gitleaks").exists(),
)
# Model the relevant boundary: pre-commit filters hook applicability,
# while the staged Gitleaks command selects its own scan scope.
staged = ["vendor/example.go", "controllers/controller.go"]
pre_commit_candidates = [
path for path in staged if not path.startswith("vendor/")
]
gitleaks_scope = staged if "--staged" in block else pre_commit_candidates
print("pre_commit_candidates=", pre_commit_candidates)
print("gitleaks_staged_scope=", gitleaks_scope)
PYRepository: redhat-data-and-ai/fivetran-operator
Length of output: 2461
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
curl -fsSL \
'https://raw.githubusercontent.com/gitleaks/gitleaks/v8.28.0/.pre-commit-hooks.yaml' |
python3 -c '
from pathlib import Path
import re
import subprocess
import sys
config = Path(".pre-commit-config.yaml").read_text()
hook_yaml = sys.stdin.read()
tracked_vendor = subprocess.check_output(
["git", "ls-files", "vendor"], text=True
).splitlines()
local_exclude = re.search(r"^exclude:\s*\"([^\"]+)\"\s*$", config, re.M)
gitleaks_block = re.search(
r"(?m)^- id: gitleaks$\n(?:(?!^-\s+id:).)*",
hook_yaml,
re.S,
)
if not gitleaks_block:
raise SystemExit("gitleaks hook definition not found")
block = gitleaks_block.group(0)
entry = re.search(r"(?m)^ entry:\s*(.+)$", block)
pass_filenames = re.search(r"(?m)^ pass_filenames:\s*(\w+)$", block)
print("local_exclude=", local_exclude.group(1) if local_exclude else "<not found>")
print("remote_gitleaks_entry=", entry.group(1) if entry else "<not found>")
print(
"remote_gitleaks_pass_filenames=",
pass_filenames.group(1) if pass_filenames else "<default true>",
)
print("remote_gitleaks_uses_staged=", "--staged" in block)
print("tracked_vendor_files=", len(tracked_vendor))
print("vendor_modules_tracked=", "vendor/modules.txt" in tracked_vendor)
print(
"gitleaks_config_present=",
Path(".gitleaks.toml").exists() or Path(".gitleaks").exists(),
)
'Repository: redhat-data-and-ai/fivetran-operator
Length of output: 435
Configure Gitleaks to exclude vendor/ explicitly.
The hook scans staged content independently of pre-commit’s exclude filter. Add a global vendor/ path allowlist to .gitleaks.toml, or remove vendor/ from the exclusion if it is not trusted generated content.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.pre-commit-config.yaml around lines 11 - 23, Configure Gitleaks explicitly
for the vendor/ path by adding a global vendor/ allowlist in .gitleaks.toml, or
remove vendor/ from the pre-commit exclude if it is not trusted generated
content; update the gitleaks hook configuration without changing the
detect-private-key hook.
| - id: check-secrets | ||
| name: Security Check | ||
| entry: bash scripts/check-secrets.sh |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Redact secret matches before printing them.
scripts/check-secrets.sh prints up to five matching lines after detection. A detected API key, password, or private key can therefore enter terminal or CI logs. Report only the rule, path, and line number, or redact the matched value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.pre-commit-config.yaml around lines 28 - 30, Update
scripts/check-secrets.sh, specifically the output for matches triggered by the
check-secrets hook, so it never prints full matching lines containing secrets.
Report only the detection rule, file path, and line number, or replace the
matched secret with a redacted value while preserving the existing five-match
limit and detection behavior.
Updated .pre-commit-config.yaml with gitleaks for secret detection.
Updated CONTRIBUTING.md with steps to install and enable pre-commit locally.