dargslan-git-audit 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dargslan_git_audit-1.0.0/LICENSE +21 -0
- dargslan_git_audit-1.0.0/PKG-INFO +68 -0
- dargslan_git_audit-1.0.0/README.md +44 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit/__init__.py +230 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit/cli.py +36 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit.egg-info/PKG-INFO +68 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit.egg-info/SOURCES.txt +10 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit.egg-info/dependency_links.txt +1 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit.egg-info/entry_points.txt +2 -0
- dargslan_git_audit-1.0.0/dargslan_git_audit.egg-info/top_level.txt +1 -0
- dargslan_git_audit-1.0.0/pyproject.toml +32 -0
- dargslan_git_audit-1.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dargslan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dargslan-git-audit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Git repository security auditor — scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks
|
|
5
|
+
Author-email: Dargslan <info@dargslan.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://dargslan.com
|
|
8
|
+
Project-URL: Documentation, https://dargslan.com/blog
|
|
9
|
+
Project-URL: Repository, https://github.com/Dargslan
|
|
10
|
+
Project-URL: Free Cheat Sheets, https://dargslan.com/cheat-sheets
|
|
11
|
+
Project-URL: Linux & DevOps Books, https://dargslan.com/books
|
|
12
|
+
Keywords: git,security,audit,secrets,gitignore,devops,linux,sysadmin
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
20
|
+
Requires-Python: >=3.7
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# dargslan-git-audit
|
|
26
|
+
|
|
27
|
+
**Git Repository Security Auditor** — Scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks. Zero external dependencies.
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/dargslan-git-audit/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install dargslan-git-audit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## CLI Usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dargslan-git report # Full security report
|
|
42
|
+
dargslan-git secrets # Scan for secrets
|
|
43
|
+
dargslan-git sensitive # Check sensitive files
|
|
44
|
+
dargslan-git gitignore # Check .gitignore gaps
|
|
45
|
+
dargslan-git large # Find large files
|
|
46
|
+
dargslan-git stats # Repository statistics
|
|
47
|
+
dargslan-git json # JSON output
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Python API
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from dargslan_git_audit import GitAudit
|
|
54
|
+
ga = GitAudit()
|
|
55
|
+
secrets = ga.scan_working_secrets()
|
|
56
|
+
issues = ga.audit()
|
|
57
|
+
ga.print_report()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## More from Dargslan
|
|
61
|
+
|
|
62
|
+
- [Dargslan.com](https://dargslan.com) — Linux & DevOps eBook Store
|
|
63
|
+
- [Free Cheat Sheets](https://dargslan.com/cheat-sheets)
|
|
64
|
+
- [Blog & Tutorials](https://dargslan.com/blog)
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# dargslan-git-audit
|
|
2
|
+
|
|
3
|
+
**Git Repository Security Auditor** — Scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks. Zero external dependencies.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/dargslan-git-audit/)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install dargslan-git-audit
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## CLI Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
dargslan-git report # Full security report
|
|
18
|
+
dargslan-git secrets # Scan for secrets
|
|
19
|
+
dargslan-git sensitive # Check sensitive files
|
|
20
|
+
dargslan-git gitignore # Check .gitignore gaps
|
|
21
|
+
dargslan-git large # Find large files
|
|
22
|
+
dargslan-git stats # Repository statistics
|
|
23
|
+
dargslan-git json # JSON output
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Python API
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from dargslan_git_audit import GitAudit
|
|
30
|
+
ga = GitAudit()
|
|
31
|
+
secrets = ga.scan_working_secrets()
|
|
32
|
+
issues = ga.audit()
|
|
33
|
+
ga.print_report()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## More from Dargslan
|
|
37
|
+
|
|
38
|
+
- [Dargslan.com](https://dargslan.com) — Linux & DevOps eBook Store
|
|
39
|
+
- [Free Cheat Sheets](https://dargslan.com/cheat-sheets)
|
|
40
|
+
- [Blog & Tutorials](https://dargslan.com/blog)
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
MIT — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"""
|
|
2
|
+
dargslan-git-audit — Git Repository Security Auditor
|
|
3
|
+
|
|
4
|
+
Scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks.
|
|
5
|
+
Zero external dependencies — uses only Python standard library.
|
|
6
|
+
|
|
7
|
+
Homepage: https://dargslan.com
|
|
8
|
+
Books: https://dargslan.com/books
|
|
9
|
+
Blog: https://dargslan.com/blog
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__version__ = "1.0.0"
|
|
13
|
+
__author__ = "Dargslan"
|
|
14
|
+
__url__ = "https://dargslan.com"
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
import subprocess
|
|
19
|
+
import json
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class GitAudit:
|
|
23
|
+
"""Audit Git repositories for security issues."""
|
|
24
|
+
|
|
25
|
+
SECRET_PATTERNS = [
|
|
26
|
+
(r'(?:password|passwd|pwd)\s*[:=]\s*["\']?[A-Za-z0-9!@#$%^&*]{8,}', 'password'),
|
|
27
|
+
(r'(?:api[_-]?key|apikey)\s*[:=]\s*["\']?[A-Za-z0-9]{16,}', 'api_key'),
|
|
28
|
+
(r'(?:secret[_-]?key|secretkey)\s*[:=]\s*["\']?[A-Za-z0-9]{16,}', 'secret_key'),
|
|
29
|
+
(r'(?:access[_-]?token|auth[_-]?token)\s*[:=]\s*["\']?[A-Za-z0-9_\-]{20,}', 'token'),
|
|
30
|
+
(r'AKIA[0-9A-Z]{16}', 'aws_access_key'),
|
|
31
|
+
(r'(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}', 'github_token'),
|
|
32
|
+
(r'sk-[A-Za-z0-9]{48,}', 'openai_key'),
|
|
33
|
+
(r'-----BEGIN (?:RSA |DSA |EC )?PRIVATE KEY-----', 'private_key'),
|
|
34
|
+
(r'(?:mysql|postgres|mongodb)://[^:]+:[^@]+@', 'database_url'),
|
|
35
|
+
(r'Bearer\s+[A-Za-z0-9\-._~+/]+=*', 'bearer_token'),
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
SENSITIVE_FILES = [
|
|
39
|
+
'.env', '.env.local', '.env.production', 'id_rsa', 'id_dsa', 'id_ecdsa', 'id_ed25519',
|
|
40
|
+
'*.pem', '*.key', '*.p12', '*.pfx', '*.jks', 'credentials.json', 'service-account.json',
|
|
41
|
+
'wp-config.php', 'config.php', 'secrets.yml', 'secrets.yaml', '.htpasswd',
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
def __init__(self, repo_path=None):
|
|
45
|
+
self.repo_path = repo_path or os.getcwd()
|
|
46
|
+
|
|
47
|
+
def _run_git(self, args):
|
|
48
|
+
try:
|
|
49
|
+
result = subprocess.run(['git'] + args, capture_output=True, text=True,
|
|
50
|
+
timeout=30, cwd=self.repo_path)
|
|
51
|
+
return result.stdout.strip() if result.returncode == 0 else ''
|
|
52
|
+
except (FileNotFoundError, subprocess.TimeoutExpired):
|
|
53
|
+
return ''
|
|
54
|
+
|
|
55
|
+
def is_git_repo(self):
|
|
56
|
+
"""Check if current directory is a Git repo."""
|
|
57
|
+
return os.path.isdir(os.path.join(self.repo_path, '.git'))
|
|
58
|
+
|
|
59
|
+
def scan_staged_secrets(self):
|
|
60
|
+
"""Scan staged files for secrets."""
|
|
61
|
+
diff = self._run_git(['diff', '--cached', '--diff-filter=ACMR'])
|
|
62
|
+
return self._scan_content(diff, 'staged')
|
|
63
|
+
|
|
64
|
+
def scan_working_secrets(self):
|
|
65
|
+
"""Scan working directory for secrets."""
|
|
66
|
+
issues = []
|
|
67
|
+
tracked = self._run_git(['ls-files'])
|
|
68
|
+
for filepath in tracked.split('\n'):
|
|
69
|
+
if not filepath.strip(): continue
|
|
70
|
+
full_path = os.path.join(self.repo_path, filepath)
|
|
71
|
+
try:
|
|
72
|
+
if os.path.getsize(full_path) > 1048576: continue
|
|
73
|
+
with open(full_path, 'r', errors='replace') as f:
|
|
74
|
+
content = f.read()
|
|
75
|
+
for pattern, secret_type in self.SECRET_PATTERNS:
|
|
76
|
+
matches = re.findall(pattern, content, re.IGNORECASE)
|
|
77
|
+
for match in matches[:3]:
|
|
78
|
+
issues.append({
|
|
79
|
+
'file': filepath,
|
|
80
|
+
'type': secret_type,
|
|
81
|
+
'severity': 'critical',
|
|
82
|
+
'preview': match[:30] + '...' if len(match) > 30 else match,
|
|
83
|
+
})
|
|
84
|
+
except (FileNotFoundError, PermissionError, UnicodeDecodeError):
|
|
85
|
+
continue
|
|
86
|
+
return issues
|
|
87
|
+
|
|
88
|
+
def _scan_content(self, content, source):
|
|
89
|
+
issues = []
|
|
90
|
+
for pattern, secret_type in self.SECRET_PATTERNS:
|
|
91
|
+
matches = re.findall(pattern, content, re.IGNORECASE)
|
|
92
|
+
for match in matches[:5]:
|
|
93
|
+
issues.append({
|
|
94
|
+
'source': source,
|
|
95
|
+
'type': secret_type,
|
|
96
|
+
'severity': 'critical',
|
|
97
|
+
'preview': match[:30] + '...',
|
|
98
|
+
})
|
|
99
|
+
return issues
|
|
100
|
+
|
|
101
|
+
def check_gitignore(self):
|
|
102
|
+
"""Check for missing .gitignore entries."""
|
|
103
|
+
gitignore_path = os.path.join(self.repo_path, '.gitignore')
|
|
104
|
+
missing = []
|
|
105
|
+
gitignore_content = ''
|
|
106
|
+
if os.path.exists(gitignore_path):
|
|
107
|
+
with open(gitignore_path, 'r') as f:
|
|
108
|
+
gitignore_content = f.read()
|
|
109
|
+
|
|
110
|
+
recommended = ['.env', '.env.*', '*.pem', '*.key', 'id_rsa', 'id_dsa',
|
|
111
|
+
'node_modules/', '__pycache__/', '*.pyc', '.DS_Store',
|
|
112
|
+
'credentials.json', '*.log', 'dist/', 'build/']
|
|
113
|
+
|
|
114
|
+
for entry in recommended:
|
|
115
|
+
if entry not in gitignore_content:
|
|
116
|
+
exists = False
|
|
117
|
+
tracked = self._run_git(['ls-files', '--', entry.rstrip('/')])
|
|
118
|
+
if tracked: exists = True
|
|
119
|
+
missing.append({'pattern': entry, 'tracked': exists})
|
|
120
|
+
|
|
121
|
+
return missing
|
|
122
|
+
|
|
123
|
+
def find_large_files(self, threshold_mb=10):
|
|
124
|
+
"""Find large files in repository history."""
|
|
125
|
+
output = self._run_git(['rev-list', '--objects', '--all'])
|
|
126
|
+
large_files = []
|
|
127
|
+
if not output: return large_files
|
|
128
|
+
|
|
129
|
+
for line in output.split('\n')[:500]:
|
|
130
|
+
parts = line.split(None, 1)
|
|
131
|
+
if len(parts) < 2: continue
|
|
132
|
+
obj_hash, path = parts
|
|
133
|
+
size_output = self._run_git(['cat-file', '-s', obj_hash])
|
|
134
|
+
if size_output and size_output.isdigit():
|
|
135
|
+
size_bytes = int(size_output)
|
|
136
|
+
if size_bytes > threshold_mb * 1024 * 1024:
|
|
137
|
+
large_files.append({
|
|
138
|
+
'path': path,
|
|
139
|
+
'size_mb': round(size_bytes / 1024 / 1024, 2),
|
|
140
|
+
'hash': obj_hash[:8],
|
|
141
|
+
})
|
|
142
|
+
return sorted(large_files, key=lambda x: x['size_mb'], reverse=True)[:20]
|
|
143
|
+
|
|
144
|
+
def check_sensitive_files(self):
|
|
145
|
+
"""Check for tracked sensitive files."""
|
|
146
|
+
tracked = self._run_git(['ls-files'])
|
|
147
|
+
found = []
|
|
148
|
+
for filepath in tracked.split('\n'):
|
|
149
|
+
basename = os.path.basename(filepath)
|
|
150
|
+
for pattern in self.SENSITIVE_FILES:
|
|
151
|
+
if pattern.startswith('*.'):
|
|
152
|
+
if basename.endswith(pattern[1:]):
|
|
153
|
+
found.append({'file': filepath, 'pattern': pattern, 'severity': 'high'})
|
|
154
|
+
break
|
|
155
|
+
elif basename == pattern:
|
|
156
|
+
found.append({'file': filepath, 'pattern': pattern, 'severity': 'critical'})
|
|
157
|
+
break
|
|
158
|
+
return found
|
|
159
|
+
|
|
160
|
+
def repo_stats(self):
|
|
161
|
+
"""Get repository statistics."""
|
|
162
|
+
commit_count = self._run_git(['rev-list', '--count', 'HEAD'])
|
|
163
|
+
branch_count = self._run_git(['branch', '-a', '--list'])
|
|
164
|
+
contributor_count = self._run_git(['shortlog', '-sn', '--all'])
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
'commits': int(commit_count) if commit_count and commit_count.isdigit() else 0,
|
|
168
|
+
'branches': len([b for b in branch_count.split('\n') if b.strip()]) if branch_count else 0,
|
|
169
|
+
'contributors': len([c for c in contributor_count.split('\n') if c.strip()]) if contributor_count else 0,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
def audit(self):
|
|
173
|
+
"""Run full Git security audit."""
|
|
174
|
+
issues = []
|
|
175
|
+
|
|
176
|
+
for s in self.scan_working_secrets():
|
|
177
|
+
issues.append({'severity': 'critical', 'category': 'secret',
|
|
178
|
+
'message': f"Secret ({s['type']}) in {s['file']}"})
|
|
179
|
+
|
|
180
|
+
for f in self.check_sensitive_files():
|
|
181
|
+
issues.append({'severity': f['severity'], 'category': 'sensitive_file',
|
|
182
|
+
'message': f"Sensitive file tracked: {f['file']}"})
|
|
183
|
+
|
|
184
|
+
gitignore_gaps = self.check_gitignore()
|
|
185
|
+
tracked_gaps = [g for g in gitignore_gaps if g['tracked']]
|
|
186
|
+
if tracked_gaps:
|
|
187
|
+
issues.append({'severity': 'warning', 'category': 'gitignore',
|
|
188
|
+
'message': f"{len(tracked_gaps)} sensitive patterns tracked but not in .gitignore"})
|
|
189
|
+
|
|
190
|
+
return issues
|
|
191
|
+
|
|
192
|
+
def print_report(self):
|
|
193
|
+
"""Print formatted Git audit report."""
|
|
194
|
+
stats = self.repo_stats()
|
|
195
|
+
issues = self.audit()
|
|
196
|
+
|
|
197
|
+
print(f"\n{'='*60}")
|
|
198
|
+
print(f" Git Repository Security Audit")
|
|
199
|
+
print(f" Path: {self.repo_path}")
|
|
200
|
+
print(f"{'='*60}")
|
|
201
|
+
print(f"\n Commits: {stats['commits']}")
|
|
202
|
+
print(f" Branches: {stats['branches']}")
|
|
203
|
+
print(f" Contributors: {stats['contributors']}")
|
|
204
|
+
|
|
205
|
+
secrets = self.scan_working_secrets()
|
|
206
|
+
if secrets:
|
|
207
|
+
print(f"\n Secrets Found ({len(secrets)}):")
|
|
208
|
+
for s in secrets[:10]:
|
|
209
|
+
print(f" [CRITICAL] {s['file']}: {s['type']}")
|
|
210
|
+
|
|
211
|
+
sensitive = self.check_sensitive_files()
|
|
212
|
+
if sensitive:
|
|
213
|
+
print(f"\n Sensitive Files ({len(sensitive)}):")
|
|
214
|
+
for f in sensitive[:10]:
|
|
215
|
+
print(f" [{f['severity'].upper()}] {f['file']}")
|
|
216
|
+
|
|
217
|
+
if issues:
|
|
218
|
+
print(f"\n Total Issues ({len(issues)}):")
|
|
219
|
+
for i in issues:
|
|
220
|
+
print(f" [{i['severity'].upper():8s}] {i['message']}")
|
|
221
|
+
else:
|
|
222
|
+
print("\n No security issues found.")
|
|
223
|
+
|
|
224
|
+
print(f"\n{'='*60}")
|
|
225
|
+
print(f" More tools: https://dargslan.com")
|
|
226
|
+
print(f" eBooks: https://dargslan.com/books")
|
|
227
|
+
print(f"{'='*60}\n")
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
__all__ = ["GitAudit"]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""CLI for dargslan-git-audit — https://dargslan.com"""
|
|
2
|
+
import argparse
|
|
3
|
+
|
|
4
|
+
def main():
|
|
5
|
+
parser = argparse.ArgumentParser(
|
|
6
|
+
description="Dargslan Git Audit — Git repository security auditor",
|
|
7
|
+
epilog="More tools at https://dargslan.com | eBooks: https://dargslan.com/books",
|
|
8
|
+
)
|
|
9
|
+
parser.add_argument("command", nargs="?", default="report",
|
|
10
|
+
choices=["report", "secrets", "sensitive", "gitignore", "large", "stats", "issues", "json"],
|
|
11
|
+
help="Command (default: report)")
|
|
12
|
+
parser.add_argument("-p", "--path", help="Repository path")
|
|
13
|
+
parser.add_argument("-s", "--size", type=int, default=10, help="Large file threshold (MB)")
|
|
14
|
+
args = parser.parse_args()
|
|
15
|
+
|
|
16
|
+
from dargslan_git_audit import GitAudit
|
|
17
|
+
ga = GitAudit(repo_path=args.path)
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
if args.command == 'report': ga.print_report()
|
|
21
|
+
elif args.command == 'secrets':
|
|
22
|
+
for s in ga.scan_working_secrets(): print(f" [{s['severity'].upper()}] {s['file']}: {s['type']}")
|
|
23
|
+
elif args.command == 'sensitive':
|
|
24
|
+
for f in ga.check_sensitive_files(): print(f" [{f['severity'].upper()}] {f['file']}")
|
|
25
|
+
elif args.command == 'gitignore':
|
|
26
|
+
for g in ga.check_gitignore():
|
|
27
|
+
tracked = " [TRACKED!]" if g['tracked'] else ""
|
|
28
|
+
print(f" Missing: {g['pattern']}{tracked}")
|
|
29
|
+
elif args.command == 'large':
|
|
30
|
+
for f in ga.find_large_files(args.size): print(f" {f['size_mb']:.1f} MB: {f['path']}")
|
|
31
|
+
elif args.command == 'stats': print(json.dumps(ga.repo_stats(), indent=2))
|
|
32
|
+
elif args.command == 'issues':
|
|
33
|
+
for i in ga.audit(): print(f" [{i['severity'].upper()}] {i['message']}")
|
|
34
|
+
elif args.command == 'json': print(json.dumps(ga.audit(), indent=2))
|
|
35
|
+
|
|
36
|
+
if __name__ == "__main__": main()
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dargslan-git-audit
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Git repository security auditor — scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks
|
|
5
|
+
Author-email: Dargslan <info@dargslan.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://dargslan.com
|
|
8
|
+
Project-URL: Documentation, https://dargslan.com/blog
|
|
9
|
+
Project-URL: Repository, https://github.com/Dargslan
|
|
10
|
+
Project-URL: Free Cheat Sheets, https://dargslan.com/cheat-sheets
|
|
11
|
+
Project-URL: Linux & DevOps Books, https://dargslan.com/books
|
|
12
|
+
Keywords: git,security,audit,secrets,gitignore,devops,linux,sysadmin
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
20
|
+
Requires-Python: >=3.7
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# dargslan-git-audit
|
|
26
|
+
|
|
27
|
+
**Git Repository Security Auditor** — Scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks. Zero external dependencies.
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/dargslan-git-audit/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install dargslan-git-audit
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## CLI Usage
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dargslan-git report # Full security report
|
|
42
|
+
dargslan-git secrets # Scan for secrets
|
|
43
|
+
dargslan-git sensitive # Check sensitive files
|
|
44
|
+
dargslan-git gitignore # Check .gitignore gaps
|
|
45
|
+
dargslan-git large # Find large files
|
|
46
|
+
dargslan-git stats # Repository statistics
|
|
47
|
+
dargslan-git json # JSON output
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Python API
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from dargslan_git_audit import GitAudit
|
|
54
|
+
ga = GitAudit()
|
|
55
|
+
secrets = ga.scan_working_secrets()
|
|
56
|
+
issues = ga.audit()
|
|
57
|
+
ga.print_report()
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## More from Dargslan
|
|
61
|
+
|
|
62
|
+
- [Dargslan.com](https://dargslan.com) — Linux & DevOps eBook Store
|
|
63
|
+
- [Free Cheat Sheets](https://dargslan.com/cheat-sheets)
|
|
64
|
+
- [Blog & Tutorials](https://dargslan.com/blog)
|
|
65
|
+
|
|
66
|
+
## License
|
|
67
|
+
|
|
68
|
+
MIT — see [LICENSE](LICENSE)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
dargslan_git_audit/__init__.py
|
|
5
|
+
dargslan_git_audit/cli.py
|
|
6
|
+
dargslan_git_audit.egg-info/PKG-INFO
|
|
7
|
+
dargslan_git_audit.egg-info/SOURCES.txt
|
|
8
|
+
dargslan_git_audit.egg-info/dependency_links.txt
|
|
9
|
+
dargslan_git_audit.egg-info/entry_points.txt
|
|
10
|
+
dargslan_git_audit.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dargslan_git_audit
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dargslan-git-audit"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Git repository security auditor — scan for secrets in commits, large files, .gitignore gaps, and sensitive data leaks"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.7"
|
|
12
|
+
authors = [{name = "Dargslan", email = "info@dargslan.com"}]
|
|
13
|
+
keywords = ["git", "security", "audit", "secrets", "gitignore", "devops", "linux", "sysadmin"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 5 - Production/Stable",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: POSIX :: Linux",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Topic :: Security",
|
|
21
|
+
"Topic :: Software Development :: Version Control :: Git",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://dargslan.com"
|
|
26
|
+
Documentation = "https://dargslan.com/blog"
|
|
27
|
+
Repository = "https://github.com/Dargslan"
|
|
28
|
+
"Free Cheat Sheets" = "https://dargslan.com/cheat-sheets"
|
|
29
|
+
"Linux & DevOps Books" = "https://dargslan.com/books"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
dargslan-git = "dargslan_git_audit.cli:main"
|