-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.pre-commit-config.yaml
More file actions
260 lines (234 loc) · 9.2 KB
/
.pre-commit-config.yaml
File metadata and controls
260 lines (234 loc) · 9.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# Pre-commit hooks for Splunk app development
# Install: pip install pre-commit
# Setup: pre-commit install
# Run manually: pre-commit run --all-files
repos:
# General file cleanup
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
name: Trim trailing whitespace
exclude: '\.csv$'
- id: end-of-file-fixer
name: Fix end of files
- id: check-yaml
name: Check YAML syntax
exclude: '(local/.*-environment\.yaml|local/.*\.yaml)$' # Exclude K8s multi-document YAML files
- id: check-json
name: Check JSON syntax
files: '\.(json|manifest)$'
- id: check-xml
name: Check XML syntax
files: '\.xml$'
- id: check-added-large-files
name: Check for large files
args: ['--maxkb=1000']
- id: check-case-conflict
name: Check for case conflicts
- id: check-merge-conflict
name: Check for merge conflicts
- id: mixed-line-ending
name: Check line endings
args: ['--fix=lf']
- id: detect-private-key
name: Detect private keys
# Python validation (if Python scripts are added)
- repo: https://github.com/psf/black
rev: 24.1.1
hooks:
- id: black
name: Format Python code with black
language_version: python3
files: '\.py$'
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
name: Lint Python with flake8
args: ['--max-line-length=100', '--ignore=E203,W503']
files: '\.py$'
# Security scanning
- repo: https://github.com/PyCQA/bandit
rev: 1.7.6
hooks:
- id: bandit
name: Security scan with bandit
args: ['-c', '.bandit.yml']
files: '\.py$'
# Custom Splunk-specific hooks
- repo: local
hooks:
- id: validate-splunk-conf
name: Validate Splunk .conf files
entry: python
language: system
files: '\.conf$'
args:
- -c
- |
import sys
files_ok = True
for filepath in sys.argv[1:]:
try:
with open(filepath, 'r', encoding='utf-8') as f:
in_multiline = False
for i, line in enumerate(f, 1):
stripped = line.strip()
# Skip empty lines and comments
if not stripped or stripped.startswith('#'):
continue
# Check for line continuation (ends with backslash)
if stripped.endswith('\\'):
in_multiline = True
continue
# If we're in a multi-line value, continue
if in_multiline:
in_multiline = False
continue
# Check for stanza or key=value
is_stanza = stripped.startswith('[') and stripped.endswith(']')
has_equals = '=' in stripped
if not (is_stanza or has_equals):
print(f'{filepath}:{i} - Invalid line (not stanza or key=value)')
files_ok = False
except Exception as e:
print(f'{filepath} - Error: {e}')
files_ok = False
sys.exit(0 if files_ok else 1)
- id: check-version-consistency
name: Check version consistency
entry: python
language: system
pass_filenames: false
always_run: false
files: '(app\.manifest|app\.conf)$'
args:
- -c
- |
import json, re, sys
try:
with open('app.manifest', encoding='utf-8') as f:
manifest = json.load(f)
manifest_version = manifest['info']['id']['version']
with open('default/app.conf', encoding='utf-8') as f:
app_conf = f.read()
app_version = re.search(r'^version\s*=\s*(.+)$', app_conf, re.M)
if not app_version:
print('[ERROR] No version found in app.conf')
sys.exit(1)
if manifest_version != app_version.group(1).strip():
print(f'[ERROR] Version mismatch: app.manifest={manifest_version}, app.conf={app_version.group(1).strip()}')
sys.exit(1)
print(f'[OK] Version consistent: {manifest_version}')
except Exception as e:
print(f'[ERROR] Error checking versions: {e}')
sys.exit(1)
- id: check-app-id-consistency
name: Check app ID consistency
entry: python
language: system
pass_filenames: false
always_run: false
files: '(app\.manifest|app\.conf)$'
args:
- -c
- |
import json, re, sys
try:
with open('app.manifest', encoding='utf-8') as f:
manifest = json.load(f)
manifest_id = manifest['info']['id']['name']
with open('default/app.conf', encoding='utf-8') as f:
app_conf = f.read()
app_id = re.search(r'^\[package\].*?^id\s*=\s*([^\s]+)', app_conf, re.M | re.S)
if not app_id:
print('[ERROR] No package id found in app.conf')
sys.exit(1)
if manifest_id != app_id.group(1).strip():
print(f'[ERROR] App ID mismatch: app.manifest={manifest_id}, app.conf={app_id.group(1).strip()}')
sys.exit(1)
print(f'[OK] App ID consistent: {manifest_id}')
except Exception as e:
print(f'[ERROR] Error checking app IDs: {e}')
sys.exit(1)
- id: check-sensitive-data
name: Scan for sensitive data patterns
entry: python
language: system
files: '\.(conf|py|xml)$'
args:
- -c
- |
import re, sys
patterns = [
(r'password\s*=\s*[^\s]+', 'hardcoded password'),
(r'token\s*=\s*[^\s]+', 'hardcoded token'),
(r'api[_-]?key\s*=\s*[^\s]+', 'hardcoded API key'),
(r'secret\s*=\s*[^\s]+', 'hardcoded secret'),
]
issues = []
for filepath in sys.argv[1:]:
with open(filepath, encoding='utf-8', errors='ignore') as f:
for i, line in enumerate(f, 1):
if line.strip().startswith('#'):
continue
for pattern, msg in patterns:
if re.search(pattern, line, re.I):
issues.append(f'{filepath}:{i} - Potential {msg}')
if issues:
print('[WARNING] Potential sensitive data:')
for issue in issues:
print(f' {issue}')
# Warning only, don't fail
sys.exit(0)
- id: validate-lookup-tables
name: Validate lookup table definitions
entry: python
language: system
pass_filenames: false
files: '(transforms\.conf|lookups/.*\.csv)$'
args:
- -c
- |
import re, sys
from pathlib import Path
transforms = Path('default/transforms.conf')
if not transforms.exists():
sys.exit(0)
lookups_defined = set()
with open(transforms, encoding='utf-8') as f:
for line in f:
match = re.match(r'^\[([^\]]+)\]', line.strip())
if match:
lookups_defined.add(match.group(1))
# Check CSV files exist
lookups_dir = Path('lookups')
if not lookups_dir.exists():
print('[WARNING] No lookups/ directory found')
sys.exit(0)
csv_files = {f.stem for f in lookups_dir.glob('*.csv')}
for lookup_def in lookups_defined:
# Basic check - lookup name should roughly match CSV filename
if lookup_def not in csv_files and lookup_def.replace('_lookup', '') not in csv_files:
print(f'[WARNING] Lookup "{lookup_def}" may not have corresponding CSV')
print(f'[OK] Checked {len(lookups_defined)} lookup definitions')
- id: no-local-directory
name: Check for local/ directory
entry: python
language: system
pass_filenames: false
always_run: true
args:
- -c
- |
import sys
from pathlib import Path
local_dir = Path('local')
if local_dir.exists() and any(local_dir.iterdir()):
print('[WARNING] local/ directory exists and is not empty')
print(' This should not be committed to version control')
# Warning only
sys.exit(0)
# Configure bandit security scanner
# Create .bandit.yml in repo root if it doesn't exist