Skip to content

Commit 23023fb

Browse files
authored
chore: standardize pre-commit hooks to repo-local pattern (#19)
## Summary - Convert gitleaks, shellcheck, and shellharden hooks from remote repos to local system hooks for consistent behavior across environments - Use shellharden `--check` mode for security hardening validation - Fix vale hook `--no-progress` flag removed in newer vale versions - Update yamllint config to canonical pattern (120 max line length, truthy check-keys false, comments min-spaces 1, consistent indent-sequences) - Fix pre-existing shellharden violations in shell scripts (array expansion, string comparison operators) ## Test plan - [x] `pre-commit run --all-files` passes all hooks (including shellharden, vale, yamllint) - [ ] CI quality checks pass - [ ] CodeRabbit review addressed - [ ] Copilot review addressed
1 parent 92266f9 commit 23023fb

File tree

4 files changed

+49
-41
lines changed

4 files changed

+49
-41
lines changed

.pre-commit-config.yaml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,30 @@ repos:
2525
- id: detect-secrets
2626
args: ["--baseline", ".secrets.baseline"]
2727

28-
- repo: https://github.com/gitleaks/gitleaks
29-
rev: v8.24.0
28+
- repo: local
3029
hooks:
3130
- id: gitleaks
31+
name: gitleaks
32+
entry: gitleaks git --pre-commit --redact --no-banner
33+
language: system
34+
pass_filenames: false
3235

3336
# Shell
34-
- repo: https://github.com/koalaman/shellcheck-precommit
35-
rev: v0.10.0
37+
- repo: local
3638
hooks:
3739
- id: shellcheck
38-
args: ["--severity=warning"]
40+
name: shellcheck
41+
entry: shellcheck --severity=warning
42+
language: system
43+
types: [shell]
3944

40-
- repo: https://github.com/anordal/shellharden
41-
rev: v4.3.1
45+
- repo: local
4246
hooks:
4347
- id: shellharden
48+
name: shellharden
49+
entry: shellharden --check
50+
language: system
51+
types: [shell]
4452

4553
# Markdown
4654
- repo: https://github.com/igorshubovych/markdownlint-cli
@@ -54,7 +62,7 @@ repos:
5462
hooks:
5563
- id: vale
5664
name: vale
57-
entry: bash -c 'vale sync --no-progress 2>/dev/null; vale "$@"' --
65+
entry: bash -c 'vale sync 2>/dev/null; vale "$@"' --
5866
language: system
5967
types: [markdown]
6068

.yamllint.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ extends: default
33

44
rules:
55
line-length:
6-
max: 200
6+
max: 120
77
level: warning
88
document-start: disable
99
truthy:
10-
allowed-values:
11-
- "true"
12-
- "false"
13-
- "on"
10+
check-keys: false
11+
comments:
12+
min-spaces-from-content: 1
1413
indentation:
1514
spaces: 2
15+
indent-sequences: consistent
1616

1717
ignore:
1818
- node_modules/

scripts/generate-report.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ echo "compliant=$compliant"
2222
echo "drift=$drift"
2323

2424
# Output for GitHub Actions
25-
if [ -n "${GITHUB_OUTPUT:-}" ]; then
25+
if [ "${GITHUB_OUTPUT:-}" != "" ]; then
2626
{
2727
echo "total_repos=$total_repos"
2828
echo "compliant=$compliant"

scripts/sync-repo-settings.sh

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ get_effective_settings() {
3434
local repo="$1"
3535
local override
3636
override=$(jq -r --arg r "$repo" '.repos[$r] // empty' "$OVERRIDES" 2>/dev/null || echo "")
37-
if [ -n "$override" ]; then
37+
if [ "$override" != "" ]; then
3838
jq -s '.[0] * .[1]' "$BASELINE" <(echo "$override")
3939
else
4040
cat "$BASELINE"
@@ -57,9 +57,9 @@ sync_repo_settings() {
5757
# Build patch payload from baseline repo_settings
5858
local patch="{}"
5959
local settings_keys
60-
settings_keys=$(echo "$effective" | jq -r '.repo_settings | keys[]')
60+
mapfile -t settings_keys < <(echo "$effective" | jq -r '.repo_settings | keys[]')
6161

62-
for key in $settings_keys; do
62+
for key in "${settings_keys[@]}"; do
6363
local desired current_val
6464
desired=$(echo "$effective" | jq -r ".repo_settings.$key")
6565
current_val=$(echo "$current" | jq -r ".$key")
@@ -70,7 +70,7 @@ sync_repo_settings() {
7070
fi
7171
done
7272

73-
if [ -n "$changes" ]; then
73+
if [ "$changes" != "" ]; then
7474
if [ "$MODE" = "--apply" ]; then
7575
gh api -X PATCH "repos/$OWNER/$repo" --input <(echo "$patch") > /dev/null 2>&1
7676
log "APPLIED repo settings for $repo"
@@ -101,7 +101,7 @@ sync_security() {
101101

102102
local current_scanning="disabled"
103103
local current_push="disabled"
104-
if [ -n "$current_security" ]; then
104+
if [ "$current_security" != "" ]; then
105105
current_scanning=$(echo "$current_security" | jq -r '.secret_scanning.status // "disabled"')
106106
current_push=$(echo "$current_security" | jq -r '.secret_scanning_push_protection.status // "disabled"')
107107
fi
@@ -277,13 +277,13 @@ apply_branch_protection() {
277277
local contexts="[]"
278278
local override_contexts
279279
override_contexts=$(jq -r --arg r "$repo" '.repos[$r].branch_protection.required_status_checks.contexts // empty' "$OVERRIDES" 2>/dev/null || echo "")
280-
if [ -n "$override_contexts" ]; then
280+
if [ "$override_contexts" != "" ]; then
281281
contexts=$(jq -r --arg r "$repo" '.repos[$r].branch_protection.required_status_checks.contexts' "$OVERRIDES")
282282
else
283283
# No override — read current contexts from the repo so we don't wipe them
284284
local current_contexts
285285
current_contexts=$(gh api "repos/$OWNER/$repo/branches/$branch/protection/required_status_checks" --jq '.contexts // []' 2>/dev/null || echo "[]")
286-
if [ -n "$current_contexts" ] && [ "$current_contexts" != "[]" ]; then
286+
if [ "$current_contexts" != "" ] && [ "$current_contexts" != "[]" ]; then
287287
contexts="$current_contexts"
288288
log "INFO: Preserving existing status check contexts for $repo"
289289
fi
@@ -349,7 +349,7 @@ sync_labels() {
349349
current_labels=$(gh api "repos/$OWNER/$repo/labels" --jq '.[].name' 2>/dev/null || echo "")
350350

351351
while read -r label_json; do
352-
[ -z "$label_json" ] && continue
352+
[ "$label_json" = "" ] && continue
353353
local name color description
354354
name=$(echo "$label_json" | jq -r '.name')
355355
color=$(echo "$label_json" | jq -r '.color')
@@ -365,7 +365,7 @@ sync_labels() {
365365
fi
366366
done < <(echo "$effective" | jq -c '.labels[]' 2>/dev/null)
367367

368-
if [ -n "$changes" ]; then
368+
if [ "$changes" != "" ]; then
369369
log "DRIFT detected in labels for $repo"
370370
else
371371
log "OK: labels for $repo"
@@ -382,7 +382,7 @@ sync_rulesets() {
382382

383383
local ruleset_name
384384
ruleset_name=$(echo "$effective" | jq -r '.rulesets.copilot_code_review.name // empty')
385-
if [ -z "$ruleset_name" ]; then
385+
if [ "$ruleset_name" = "" ]; then
386386
echo ""
387387
return
388388
fi
@@ -399,7 +399,7 @@ sync_rulesets() {
399399
local desired_ruleset
400400
desired_ruleset=$(echo "$effective" | jq '.rulesets.copilot_code_review')
401401

402-
if [ -n "$existing" ]; then
402+
if [ "$existing" != "" ]; then
403403
# Compare full ruleset config, not just enforcement
404404
local current_ruleset desired_normalized current_normalized
405405
current_ruleset=$(gh api "repos/$OWNER/$repo/rulesets/$existing" 2>/dev/null || echo "")
@@ -450,7 +450,7 @@ check_default_branch() {
450450
local default_branch
451451
default_branch=$(gh api "repos/$OWNER/$repo" --jq '.default_branch' 2>/dev/null || echo "")
452452

453-
if [ "$default_branch" != "$expected_branch" ] && [ -n "$default_branch" ]; then
453+
if [ "$default_branch" != "$expected_branch" ] && [ "$default_branch" != "" ]; then
454454
changes="- Default branch: \`$default_branch\` (expected \`$expected_branch\`)\n"
455455
if [ "$MODE" = "--apply" ]; then
456456
gh api -X PATCH "repos/$OWNER/$repo" -f default_branch="$expected_branch" > /dev/null 2>&1 \
@@ -475,7 +475,7 @@ check_repo_metadata() {
475475

476476
local description
477477
description=$(echo "$current" | jq -r '.description // ""')
478-
if [ -z "$description" ] || [ "$description" = "null" ]; then
478+
if [ "$description" = "" ] || [ "$description" = "null" ]; then
479479
changes="${changes}- **Missing repository description**\n"
480480
fi
481481

@@ -485,7 +485,7 @@ check_repo_metadata() {
485485
changes="${changes}- **No repository topics configured**\n"
486486
fi
487487

488-
if [ -n "$changes" ]; then
488+
if [ "$changes" != "" ]; then
489489
log "WARN: metadata gaps for $repo"
490490
else
491491
log "OK: metadata for $repo"
@@ -500,9 +500,9 @@ check_required_files() {
500500
effective=$(get_effective_settings "$repo")
501501
local missing=""
502502
local files
503-
files=$(echo "$effective" | jq -r '.required_files[]')
503+
mapfile -t files < <(echo "$effective" | jq -r '.required_files[]')
504504

505-
for file in $files; do
505+
for file in "${files[@]}"; do
506506
if ! gh api "repos/$OWNER/$repo/contents/$file" > /dev/null 2>&1; then
507507
missing="${missing}- Missing: \`$file\`\n"
508508
fi
@@ -535,7 +535,7 @@ REPORT_HEADER
535535
local total_ok=0
536536

537537
while read -r repo; do
538-
[ -z "$repo" ] && continue
538+
[ "$repo" = "" ] && continue
539539
log "Processing: $repo"
540540

541541
echo "## $repo" >> "$REPORT_FILE"
@@ -546,67 +546,67 @@ REPORT_HEADER
546546
# Default branch
547547
local branch_changes
548548
branch_changes=$(check_default_branch "$repo")
549-
if [ -n "$branch_changes" ]; then
549+
if [ "$branch_changes" != "" ]; then
550550
repo_drift="${repo_drift}### Default Branch\n\n${branch_changes}\n"
551551
fi
552552

553553
# Repo settings
554554
local repo_changes
555555
repo_changes=$(sync_repo_settings "$repo")
556-
if [ -n "$repo_changes" ]; then
556+
if [ "$repo_changes" != "" ]; then
557557
repo_drift="${repo_drift}### Repository Settings\n\n${repo_changes}\n"
558558
fi
559559

560560
# Security
561561
local security_changes
562562
security_changes=$(sync_security "$repo")
563-
if [ -n "$security_changes" ]; then
563+
if [ "$security_changes" != "" ]; then
564564
repo_drift="${repo_drift}### Security\n\n${security_changes}\n"
565565
fi
566566

567567
# Vulnerability alerts
568568
local vuln_changes
569569
vuln_changes=$(sync_vulnerability_alerts "$repo")
570-
if [ -n "$vuln_changes" ]; then
570+
if [ "$vuln_changes" != "" ]; then
571571
repo_drift="${repo_drift}### Vulnerability Alerts\n\n${vuln_changes}\n"
572572
fi
573573

574574
# Branch protection
575575
local protection_changes
576576
protection_changes=$(sync_branch_protection "$repo")
577-
if [ -n "$protection_changes" ]; then
577+
if [ "$protection_changes" != "" ]; then
578578
repo_drift="${repo_drift}### Branch Protection\n\n${protection_changes}\n"
579579
fi
580580

581581
# Rulesets (Copilot code review)
582582
local ruleset_changes
583583
ruleset_changes=$(sync_rulesets "$repo")
584-
if [ -n "$ruleset_changes" ]; then
584+
if [ "$ruleset_changes" != "" ]; then
585585
repo_drift="${repo_drift}### Rulesets\n\n${ruleset_changes}\n"
586586
fi
587587

588588
# Labels
589589
local label_changes
590590
label_changes=$(sync_labels "$repo")
591-
if [ -n "$label_changes" ]; then
591+
if [ "$label_changes" != "" ]; then
592592
repo_drift="${repo_drift}### Labels\n\n${label_changes}\n"
593593
fi
594594

595595
# Metadata (advisory only — not auto-fixed)
596596
local metadata_changes
597597
metadata_changes=$(check_repo_metadata "$repo")
598-
if [ -n "$metadata_changes" ]; then
598+
if [ "$metadata_changes" != "" ]; then
599599
repo_drift="${repo_drift}### Metadata (Manual Action Needed)\n\n${metadata_changes}\n"
600600
fi
601601

602602
# Required files
603603
local missing_files
604604
missing_files=$(check_required_files "$repo")
605-
if [ -n "$missing_files" ]; then
605+
if [ "$missing_files" != "" ]; then
606606
repo_drift="${repo_drift}### Missing Files\n\n${missing_files}\n"
607607
fi
608608

609-
if [ -n "$repo_drift" ]; then
609+
if [ "$repo_drift" != "" ]; then
610610
echo -e "$repo_drift" >> "$REPORT_FILE"
611611
total_drift=$((total_drift + 1))
612612
else

0 commit comments

Comments
 (0)