git-secret-sentinel 0.2.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.
- git_secret_sentinel-0.2.0/LICENSE +21 -0
- git_secret_sentinel-0.2.0/PKG-INFO +305 -0
- git_secret_sentinel-0.2.0/README.md +280 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/PKG-INFO +305 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/SOURCES.txt +32 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/dependency_links.txt +1 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/entry_points.txt +2 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/requires.txt +6 -0
- git_secret_sentinel-0.2.0/git_secret_sentinel.egg-info/top_level.txt +1 -0
- git_secret_sentinel-0.2.0/pyproject.toml +61 -0
- git_secret_sentinel-0.2.0/secret_sentinel/__init__.py +1 -0
- git_secret_sentinel-0.2.0/secret_sentinel/__main__.py +4 -0
- git_secret_sentinel-0.2.0/secret_sentinel/ai_validator.py +217 -0
- git_secret_sentinel-0.2.0/secret_sentinel/baseline.py +92 -0
- git_secret_sentinel-0.2.0/secret_sentinel/cli.py +1333 -0
- git_secret_sentinel-0.2.0/secret_sentinel/config.py +167 -0
- git_secret_sentinel-0.2.0/secret_sentinel/formatters.py +530 -0
- git_secret_sentinel-0.2.0/secret_sentinel/history.py +177 -0
- git_secret_sentinel-0.2.0/secret_sentinel/remediation.py +137 -0
- git_secret_sentinel-0.2.0/secret_sentinel/risk_scoring.py +98 -0
- git_secret_sentinel-0.2.0/secret_sentinel/scanner.py +1313 -0
- git_secret_sentinel-0.2.0/secret_sentinel/utils.py +73 -0
- git_secret_sentinel-0.2.0/setup.cfg +4 -0
- git_secret_sentinel-0.2.0/tests/test_ai_validator.py +225 -0
- git_secret_sentinel-0.2.0/tests/test_baseline.py +90 -0
- git_secret_sentinel-0.2.0/tests/test_cli.py +1499 -0
- git_secret_sentinel-0.2.0/tests/test_config.py +140 -0
- git_secret_sentinel-0.2.0/tests/test_detection_quality.py +792 -0
- git_secret_sentinel-0.2.0/tests/test_formatters.py +396 -0
- git_secret_sentinel-0.2.0/tests/test_github_workflow.py +105 -0
- git_secret_sentinel-0.2.0/tests/test_risk_and_history.py +142 -0
- git_secret_sentinel-0.2.0/tests/test_scanner.py +1223 -0
- git_secret_sentinel-0.2.0/tests/test_security.py +158 -0
- git_secret_sentinel-0.2.0/tests/test_utils.py +69 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Secret Sentinel Team
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: git-secret-sentinel
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Local secret scanner for Git repositories, hooks, and CI.
|
|
5
|
+
Author: Tajamul Wani
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/tajamul-wani/secret-sentinel
|
|
8
|
+
Keywords: secret,scanner,git,pre-commit,security
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
22
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
23
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# Secret Sentinel
|
|
27
|
+
|
|
28
|
+
A local secret scanner for Git repositories. It finds hardcoded credentials
|
|
29
|
+
in files, staged changes, and commit history before they reach a remote.
|
|
30
|
+
|
|
31
|
+
- Runs offline with no runtime dependencies
|
|
32
|
+
- Works as a pre-commit hook, a pre-push hook, or a GitHub Action
|
|
33
|
+
- Never prints detected values; reports are always redacted
|
|
34
|
+
- Requires Python 3.10 or later
|
|
35
|
+
|
|
36
|
+
## Contents
|
|
37
|
+
|
|
38
|
+
- [Install](#install)
|
|
39
|
+
- [Quick start](#quick-start)
|
|
40
|
+
- [Scan modes](#scan-modes)
|
|
41
|
+
- [Git hooks](#git-hooks)
|
|
42
|
+
- [CI](#ci)
|
|
43
|
+
- [Configuration](#configuration)
|
|
44
|
+
- [Suppressing findings](#suppressing-findings)
|
|
45
|
+
- [Baseline](#baseline)
|
|
46
|
+
- [Detection](#detection)
|
|
47
|
+
- [AI validation](#ai-validation)
|
|
48
|
+
- [Development](#development)
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pipx install git-secret-sentinel
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or with pip:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python -m pip install git-secret-sentinel
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
The package is named `git-secret-sentinel`; the command it installs is
|
|
63
|
+
`secret-sentinel`.
|
|
64
|
+
|
|
65
|
+
## Quick start
|
|
66
|
+
|
|
67
|
+
Run these from the root of your repository.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
secret-sentinel --setup
|
|
71
|
+
secret-sentinel .
|
|
72
|
+
secret-sentinel --doctor
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
| Command | What it does |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `--setup` | Guided setup for hooks, baseline, and CI |
|
|
78
|
+
| `.` | Scans the working tree |
|
|
79
|
+
| `--doctor` | Checks the repository, config, and hooks |
|
|
80
|
+
|
|
81
|
+
## Scan modes
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
secret-sentinel .
|
|
85
|
+
secret-sentinel src/ config.yaml
|
|
86
|
+
secret-sentinel --staged
|
|
87
|
+
secret-sentinel --diff origin/main
|
|
88
|
+
secret-sentinel --commit-range origin/main HEAD
|
|
89
|
+
secret-sentinel --git-history
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
| Mode | Scans |
|
|
93
|
+
|---|---|
|
|
94
|
+
| paths | Files and folders on disk |
|
|
95
|
+
| `--staged` | The Git index (default when no paths are given) |
|
|
96
|
+
| `--diff BASE` | Lines added since `BASE` |
|
|
97
|
+
| `--commit-range BASE HEAD` | Every commit in the range, including secrets added and later removed |
|
|
98
|
+
| `--git-history` | All commits reachable from `HEAD` (add `--all-refs` for all branches) |
|
|
99
|
+
|
|
100
|
+
### Output
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
secret-sentinel . --format json
|
|
104
|
+
secret-sentinel . --format sarif --output results.sarif
|
|
105
|
+
secret-sentinel . --coverage
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `--format` accepts `text` (default), `json`, or `sarif`.
|
|
109
|
+
- `--coverage` lists scanned and skipped file counts for path scans.
|
|
110
|
+
|
|
111
|
+
### Exit codes
|
|
112
|
+
|
|
113
|
+
| Code | Meaning |
|
|
114
|
+
|---|---|
|
|
115
|
+
| `0` | No findings at or above the threshold |
|
|
116
|
+
| `1` | Findings at or above the threshold, or a scan error |
|
|
117
|
+
| `2` | Invalid arguments or configuration |
|
|
118
|
+
|
|
119
|
+
## Git hooks
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
secret-sentinel --install-hook
|
|
123
|
+
secret-sentinel --install-pre-push-hook
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- The pre-commit hook scans staged changes.
|
|
127
|
+
- The pre-push hook scans commits that are not yet on the remote.
|
|
128
|
+
- Remove them with `--uninstall-hook` and `--uninstall-pre-push-hook`.
|
|
129
|
+
- Existing hooks that Secret Sentinel did not create are never replaced.
|
|
130
|
+
|
|
131
|
+
### pre-commit framework
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
repos:
|
|
135
|
+
- repo: https://github.com/tajamul-wani/secret-sentinel
|
|
136
|
+
rev: v0.2.0
|
|
137
|
+
hooks:
|
|
138
|
+
- id: secret-sentinel
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## CI
|
|
142
|
+
|
|
143
|
+
Add the GitHub Action to a workflow:
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
on:
|
|
147
|
+
push:
|
|
148
|
+
pull_request:
|
|
149
|
+
|
|
150
|
+
permissions:
|
|
151
|
+
contents: read
|
|
152
|
+
|
|
153
|
+
jobs:
|
|
154
|
+
secrets:
|
|
155
|
+
runs-on: ubuntu-latest
|
|
156
|
+
steps:
|
|
157
|
+
- uses: actions/checkout@v5
|
|
158
|
+
- uses: tajamul-wani/secret-sentinel@v0.2.0
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Optional inputs:
|
|
162
|
+
|
|
163
|
+
| Input | Default | Description |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| `fail-on` | `LOW` | Minimum severity that fails the job |
|
|
166
|
+
| `sarif` | `false` | Send results to code scanning (needs `security-events: write`) |
|
|
167
|
+
|
|
168
|
+
What the action scans:
|
|
169
|
+
|
|
170
|
+
| Event | Scan |
|
|
171
|
+
|---|---|
|
|
172
|
+
| Pull request | All commits between the base branch and `HEAD` |
|
|
173
|
+
| Push | The pushed commits |
|
|
174
|
+
| New branch or force push | The working tree |
|
|
175
|
+
|
|
176
|
+
Notes:
|
|
177
|
+
|
|
178
|
+
- Shallow checkouts are handled automatically.
|
|
179
|
+
- The action installs Python 3.12, which later steps in the job will use.
|
|
180
|
+
- Make the scan a required status check. Local hooks can be skipped with
|
|
181
|
+
`--no-verify`; CI cannot.
|
|
182
|
+
- The baseline key is only passed to trusted pushes on `main`;
|
|
183
|
+
pull-request scans run without it.
|
|
184
|
+
|
|
185
|
+
## Configuration
|
|
186
|
+
|
|
187
|
+
Create `.secret-sentinel.ini` in the repository root:
|
|
188
|
+
|
|
189
|
+
```ini
|
|
190
|
+
[secret-sentinel]
|
|
191
|
+
fail_on = HIGH
|
|
192
|
+
ignore_paths = tests/fixtures/*, docs/*.md
|
|
193
|
+
|
|
194
|
+
[custom_rules]
|
|
195
|
+
Internal Token = CRITICAL | \bcorp_[A-Za-z0-9]{32}\b
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
| Setting | Description |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `fail_on` | `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL`. Default `LOW`. Override with `--fail-on`. |
|
|
201
|
+
| `ignore_paths` | Comma-separated globs, relative to the repository root |
|
|
202
|
+
| `custom_rules` | One rule per line: `NAME = SEVERITY \| REGEX` |
|
|
203
|
+
|
|
204
|
+
You can also list ignore globs in `.secretignore`, one per line.
|
|
205
|
+
|
|
206
|
+
Ignored by default:
|
|
207
|
+
|
|
208
|
+
- `.git`, `node_modules`, `venv`, `.venv`, and `__pycache__` at any depth
|
|
209
|
+
- `env/` and `.env/` at the repository root
|
|
210
|
+
- Minified bundles and source maps: `*.min.js`, `*.min.css`, `*.map`
|
|
211
|
+
|
|
212
|
+
Lockfiles are still scanned because registry URLs can contain tokens.
|
|
213
|
+
|
|
214
|
+
## Suppressing findings
|
|
215
|
+
|
|
216
|
+
Add a comment on the same line:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
key = "..." # secret-sentinel: ignore reason: fixture
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Or on the line before:
|
|
223
|
+
|
|
224
|
+
```python
|
|
225
|
+
# secret-sentinel: disable-next-line reason: fixture
|
|
226
|
+
key = "..."
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
- Add `expires: YYYY-MM-DD` to make a suppression temporary.
|
|
230
|
+
- `#`, `//`, and `/* */` comments are supported.
|
|
231
|
+
- Run `secret-sentinel --audit-suppressions` to find suppressions that are
|
|
232
|
+
missing a reason, expired, or no longer needed.
|
|
233
|
+
|
|
234
|
+
## Baseline
|
|
235
|
+
|
|
236
|
+
Use a baseline to accept existing findings and fail only on new ones.
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
secret-sentinel --update-baseline .
|
|
240
|
+
secret-sentinel --baseline .
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- Fingerprints are stored in `.secret-sentinel/baseline.json`. Secret
|
|
244
|
+
values are never stored.
|
|
245
|
+
- Baseline commands need a shared key of at least 32 bytes in
|
|
246
|
+
`SECRET_SENTINEL_BASELINE_KEY`. Store it as a CI secret and never
|
|
247
|
+
commit it.
|
|
248
|
+
- Renaming a file makes its findings appear as new.
|
|
249
|
+
|
|
250
|
+
Generate a key:
|
|
251
|
+
|
|
252
|
+
```bash
|
|
253
|
+
python -c "import secrets; print(secrets.token_hex(32))"
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Detection
|
|
257
|
+
|
|
258
|
+
| Severity | Detects |
|
|
259
|
+
|---|---|
|
|
260
|
+
| Critical | Cloud and SaaS keys: AWS, Google, Azure Storage, Stripe, GitHub, GitLab, Slack, Twilio, SendGrid, Shopify, DigitalOcean, Databricks, OpenAI, Anthropic, Hugging Face, PyPI, npm |
|
|
261
|
+
| Critical | Private keys, database URLs with passwords, `.netrc`, `.pgpass`, Docker registry auth |
|
|
262
|
+
| High | JWTs, Slack webhooks, Telegram bot tokens, Mailchimp keys |
|
|
263
|
+
| High | Generic `key`, `token`, `secret`, and `password` assignments |
|
|
264
|
+
| Medium | AWS access key IDs and high-entropy values in secret fields |
|
|
265
|
+
|
|
266
|
+
How scanning works:
|
|
267
|
+
|
|
268
|
+
- Base64 values in secret fields are decoded and checked again.
|
|
269
|
+
- Placeholders such as `${VAR}`, `<value>`, and `your_key_here` are skipped.
|
|
270
|
+
- Binary files are skipped. UTF-8 and Latin-1 text files are scanned.
|
|
271
|
+
- Files larger than 5 MB are skipped and counted in `--coverage`.
|
|
272
|
+
|
|
273
|
+
## AI validation
|
|
274
|
+
|
|
275
|
+
AI validation is optional and disabled by default. When enabled, a model can
|
|
276
|
+
discard generic findings that look like test data. Provider-specific matches,
|
|
277
|
+
such as a GitHub token, are always kept.
|
|
278
|
+
|
|
279
|
+
```ini
|
|
280
|
+
[secret-sentinel]
|
|
281
|
+
ai_enabled = true
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
| Backend | Setup |
|
|
285
|
+
|---|---|
|
|
286
|
+
| Ollama (local) | Install Ollama. Optional: `OLLAMA_MODEL`, `OLLAMA_TIMEOUT` |
|
|
287
|
+
| Gemini (cloud) | Also set `ai_cloud_enabled = true` and `GEMINI_API_KEY` |
|
|
288
|
+
|
|
289
|
+
- Detected values are redacted before any context is sent.
|
|
290
|
+
- If the model is unavailable or unclear, the finding is kept.
|
|
291
|
+
- Use `--no-ai` to skip validation for a single run.
|
|
292
|
+
|
|
293
|
+
## Development
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
python -m pip install -e ".[dev]"
|
|
297
|
+
python -m unittest discover -s tests
|
|
298
|
+
python tests/run_coverage.py
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The coverage check fails below 80%.
|
|
302
|
+
|
|
303
|
+
## License
|
|
304
|
+
|
|
305
|
+
MIT
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Secret Sentinel
|
|
2
|
+
|
|
3
|
+
A local secret scanner for Git repositories. It finds hardcoded credentials
|
|
4
|
+
in files, staged changes, and commit history before they reach a remote.
|
|
5
|
+
|
|
6
|
+
- Runs offline with no runtime dependencies
|
|
7
|
+
- Works as a pre-commit hook, a pre-push hook, or a GitHub Action
|
|
8
|
+
- Never prints detected values; reports are always redacted
|
|
9
|
+
- Requires Python 3.10 or later
|
|
10
|
+
|
|
11
|
+
## Contents
|
|
12
|
+
|
|
13
|
+
- [Install](#install)
|
|
14
|
+
- [Quick start](#quick-start)
|
|
15
|
+
- [Scan modes](#scan-modes)
|
|
16
|
+
- [Git hooks](#git-hooks)
|
|
17
|
+
- [CI](#ci)
|
|
18
|
+
- [Configuration](#configuration)
|
|
19
|
+
- [Suppressing findings](#suppressing-findings)
|
|
20
|
+
- [Baseline](#baseline)
|
|
21
|
+
- [Detection](#detection)
|
|
22
|
+
- [AI validation](#ai-validation)
|
|
23
|
+
- [Development](#development)
|
|
24
|
+
|
|
25
|
+
## Install
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pipx install git-secret-sentinel
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Or with pip:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
python -m pip install git-secret-sentinel
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The package is named `git-secret-sentinel`; the command it installs is
|
|
38
|
+
`secret-sentinel`.
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Run these from the root of your repository.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
secret-sentinel --setup
|
|
46
|
+
secret-sentinel .
|
|
47
|
+
secret-sentinel --doctor
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Command | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `--setup` | Guided setup for hooks, baseline, and CI |
|
|
53
|
+
| `.` | Scans the working tree |
|
|
54
|
+
| `--doctor` | Checks the repository, config, and hooks |
|
|
55
|
+
|
|
56
|
+
## Scan modes
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
secret-sentinel .
|
|
60
|
+
secret-sentinel src/ config.yaml
|
|
61
|
+
secret-sentinel --staged
|
|
62
|
+
secret-sentinel --diff origin/main
|
|
63
|
+
secret-sentinel --commit-range origin/main HEAD
|
|
64
|
+
secret-sentinel --git-history
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Mode | Scans |
|
|
68
|
+
|---|---|
|
|
69
|
+
| paths | Files and folders on disk |
|
|
70
|
+
| `--staged` | The Git index (default when no paths are given) |
|
|
71
|
+
| `--diff BASE` | Lines added since `BASE` |
|
|
72
|
+
| `--commit-range BASE HEAD` | Every commit in the range, including secrets added and later removed |
|
|
73
|
+
| `--git-history` | All commits reachable from `HEAD` (add `--all-refs` for all branches) |
|
|
74
|
+
|
|
75
|
+
### Output
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
secret-sentinel . --format json
|
|
79
|
+
secret-sentinel . --format sarif --output results.sarif
|
|
80
|
+
secret-sentinel . --coverage
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- `--format` accepts `text` (default), `json`, or `sarif`.
|
|
84
|
+
- `--coverage` lists scanned and skipped file counts for path scans.
|
|
85
|
+
|
|
86
|
+
### Exit codes
|
|
87
|
+
|
|
88
|
+
| Code | Meaning |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `0` | No findings at or above the threshold |
|
|
91
|
+
| `1` | Findings at or above the threshold, or a scan error |
|
|
92
|
+
| `2` | Invalid arguments or configuration |
|
|
93
|
+
|
|
94
|
+
## Git hooks
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
secret-sentinel --install-hook
|
|
98
|
+
secret-sentinel --install-pre-push-hook
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
- The pre-commit hook scans staged changes.
|
|
102
|
+
- The pre-push hook scans commits that are not yet on the remote.
|
|
103
|
+
- Remove them with `--uninstall-hook` and `--uninstall-pre-push-hook`.
|
|
104
|
+
- Existing hooks that Secret Sentinel did not create are never replaced.
|
|
105
|
+
|
|
106
|
+
### pre-commit framework
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
repos:
|
|
110
|
+
- repo: https://github.com/tajamul-wani/secret-sentinel
|
|
111
|
+
rev: v0.2.0
|
|
112
|
+
hooks:
|
|
113
|
+
- id: secret-sentinel
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## CI
|
|
117
|
+
|
|
118
|
+
Add the GitHub Action to a workflow:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
on:
|
|
122
|
+
push:
|
|
123
|
+
pull_request:
|
|
124
|
+
|
|
125
|
+
permissions:
|
|
126
|
+
contents: read
|
|
127
|
+
|
|
128
|
+
jobs:
|
|
129
|
+
secrets:
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v5
|
|
133
|
+
- uses: tajamul-wani/secret-sentinel@v0.2.0
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Optional inputs:
|
|
137
|
+
|
|
138
|
+
| Input | Default | Description |
|
|
139
|
+
|---|---|---|
|
|
140
|
+
| `fail-on` | `LOW` | Minimum severity that fails the job |
|
|
141
|
+
| `sarif` | `false` | Send results to code scanning (needs `security-events: write`) |
|
|
142
|
+
|
|
143
|
+
What the action scans:
|
|
144
|
+
|
|
145
|
+
| Event | Scan |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Pull request | All commits between the base branch and `HEAD` |
|
|
148
|
+
| Push | The pushed commits |
|
|
149
|
+
| New branch or force push | The working tree |
|
|
150
|
+
|
|
151
|
+
Notes:
|
|
152
|
+
|
|
153
|
+
- Shallow checkouts are handled automatically.
|
|
154
|
+
- The action installs Python 3.12, which later steps in the job will use.
|
|
155
|
+
- Make the scan a required status check. Local hooks can be skipped with
|
|
156
|
+
`--no-verify`; CI cannot.
|
|
157
|
+
- The baseline key is only passed to trusted pushes on `main`;
|
|
158
|
+
pull-request scans run without it.
|
|
159
|
+
|
|
160
|
+
## Configuration
|
|
161
|
+
|
|
162
|
+
Create `.secret-sentinel.ini` in the repository root:
|
|
163
|
+
|
|
164
|
+
```ini
|
|
165
|
+
[secret-sentinel]
|
|
166
|
+
fail_on = HIGH
|
|
167
|
+
ignore_paths = tests/fixtures/*, docs/*.md
|
|
168
|
+
|
|
169
|
+
[custom_rules]
|
|
170
|
+
Internal Token = CRITICAL | \bcorp_[A-Za-z0-9]{32}\b
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
| Setting | Description |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `fail_on` | `LOW`, `MEDIUM`, `HIGH`, or `CRITICAL`. Default `LOW`. Override with `--fail-on`. |
|
|
176
|
+
| `ignore_paths` | Comma-separated globs, relative to the repository root |
|
|
177
|
+
| `custom_rules` | One rule per line: `NAME = SEVERITY \| REGEX` |
|
|
178
|
+
|
|
179
|
+
You can also list ignore globs in `.secretignore`, one per line.
|
|
180
|
+
|
|
181
|
+
Ignored by default:
|
|
182
|
+
|
|
183
|
+
- `.git`, `node_modules`, `venv`, `.venv`, and `__pycache__` at any depth
|
|
184
|
+
- `env/` and `.env/` at the repository root
|
|
185
|
+
- Minified bundles and source maps: `*.min.js`, `*.min.css`, `*.map`
|
|
186
|
+
|
|
187
|
+
Lockfiles are still scanned because registry URLs can contain tokens.
|
|
188
|
+
|
|
189
|
+
## Suppressing findings
|
|
190
|
+
|
|
191
|
+
Add a comment on the same line:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
key = "..." # secret-sentinel: ignore reason: fixture
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Or on the line before:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
# secret-sentinel: disable-next-line reason: fixture
|
|
201
|
+
key = "..."
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
- Add `expires: YYYY-MM-DD` to make a suppression temporary.
|
|
205
|
+
- `#`, `//`, and `/* */` comments are supported.
|
|
206
|
+
- Run `secret-sentinel --audit-suppressions` to find suppressions that are
|
|
207
|
+
missing a reason, expired, or no longer needed.
|
|
208
|
+
|
|
209
|
+
## Baseline
|
|
210
|
+
|
|
211
|
+
Use a baseline to accept existing findings and fail only on new ones.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
secret-sentinel --update-baseline .
|
|
215
|
+
secret-sentinel --baseline .
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- Fingerprints are stored in `.secret-sentinel/baseline.json`. Secret
|
|
219
|
+
values are never stored.
|
|
220
|
+
- Baseline commands need a shared key of at least 32 bytes in
|
|
221
|
+
`SECRET_SENTINEL_BASELINE_KEY`. Store it as a CI secret and never
|
|
222
|
+
commit it.
|
|
223
|
+
- Renaming a file makes its findings appear as new.
|
|
224
|
+
|
|
225
|
+
Generate a key:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
python -c "import secrets; print(secrets.token_hex(32))"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Detection
|
|
232
|
+
|
|
233
|
+
| Severity | Detects |
|
|
234
|
+
|---|---|
|
|
235
|
+
| Critical | Cloud and SaaS keys: AWS, Google, Azure Storage, Stripe, GitHub, GitLab, Slack, Twilio, SendGrid, Shopify, DigitalOcean, Databricks, OpenAI, Anthropic, Hugging Face, PyPI, npm |
|
|
236
|
+
| Critical | Private keys, database URLs with passwords, `.netrc`, `.pgpass`, Docker registry auth |
|
|
237
|
+
| High | JWTs, Slack webhooks, Telegram bot tokens, Mailchimp keys |
|
|
238
|
+
| High | Generic `key`, `token`, `secret`, and `password` assignments |
|
|
239
|
+
| Medium | AWS access key IDs and high-entropy values in secret fields |
|
|
240
|
+
|
|
241
|
+
How scanning works:
|
|
242
|
+
|
|
243
|
+
- Base64 values in secret fields are decoded and checked again.
|
|
244
|
+
- Placeholders such as `${VAR}`, `<value>`, and `your_key_here` are skipped.
|
|
245
|
+
- Binary files are skipped. UTF-8 and Latin-1 text files are scanned.
|
|
246
|
+
- Files larger than 5 MB are skipped and counted in `--coverage`.
|
|
247
|
+
|
|
248
|
+
## AI validation
|
|
249
|
+
|
|
250
|
+
AI validation is optional and disabled by default. When enabled, a model can
|
|
251
|
+
discard generic findings that look like test data. Provider-specific matches,
|
|
252
|
+
such as a GitHub token, are always kept.
|
|
253
|
+
|
|
254
|
+
```ini
|
|
255
|
+
[secret-sentinel]
|
|
256
|
+
ai_enabled = true
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
| Backend | Setup |
|
|
260
|
+
|---|---|
|
|
261
|
+
| Ollama (local) | Install Ollama. Optional: `OLLAMA_MODEL`, `OLLAMA_TIMEOUT` |
|
|
262
|
+
| Gemini (cloud) | Also set `ai_cloud_enabled = true` and `GEMINI_API_KEY` |
|
|
263
|
+
|
|
264
|
+
- Detected values are redacted before any context is sent.
|
|
265
|
+
- If the model is unavailable or unclear, the finding is kept.
|
|
266
|
+
- Use `--no-ai` to skip validation for a single run.
|
|
267
|
+
|
|
268
|
+
## Development
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
python -m pip install -e ".[dev]"
|
|
272
|
+
python -m unittest discover -s tests
|
|
273
|
+
python tests/run_coverage.py
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The coverage check fails below 80%.
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|