secretshield 0.3.2__tar.gz → 0.4.1__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.
- {secretshield-0.3.2 → secretshield-0.4.1}/LICENSE +1 -1
- secretshield-0.4.1/PKG-INFO +353 -0
- secretshield-0.4.1/README.md +327 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/pyproject.toml +5 -3
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/__init__.py +1 -1
- secretshield-0.4.1/secretshield/baseline.py +56 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/cli.py +335 -42
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/git/__init__.py +2 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/git/hooks.py +19 -0
- secretshield-0.4.1/secretshield/project_config.py +121 -0
- secretshield-0.4.1/secretshield.egg-info/PKG-INFO +353 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield.egg-info/SOURCES.txt +6 -1
- secretshield-0.4.1/secretshield.egg-info/requires.txt +6 -0
- secretshield-0.4.1/tests/test_baseline.py +58 -0
- secretshield-0.4.1/tests/test_project_config.py +75 -0
- secretshield-0.4.1/tests/test_v040_cli_integration.py +219 -0
- secretshield-0.3.2/PKG-INFO +0 -515
- secretshield-0.3.2/README.md +0 -490
- secretshield-0.3.2/secretshield.egg-info/PKG-INFO +0 -515
- secretshield-0.3.2/secretshield.egg-info/requires.txt +0 -3
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/autofix/__init__.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/autofix/env.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/autofix/fixer.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/autofix/gitignore.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/autofix/python.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/config.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/detector.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/github/__init__.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/github/actions.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/guardian.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/notifications.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/patterns.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield/redactor.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield.egg-info/dependency_links.txt +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield.egg-info/entry_points.txt +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/secretshield.egg-info/top_level.txt +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/setup.cfg +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_autofix.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_detector.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_git_hooks.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_github_action.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_logging.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_redactor.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_scan.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_stdout.py +0 -0
- {secretshield-0.3.2 → secretshield-0.4.1}/tests/test_v030_cli_integration.py +0 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: secretshield
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Detect, redact, and prevent secret exposure in Python apps, source code, and Git commits — runtime protection, multi-language scanning, auto-fix, and CI integration in one tool.
|
|
5
|
+
Author: Samarth Chugh (Sam3360)
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Sam3360/secretshield
|
|
8
|
+
Project-URL: Repository, https://github.com/Sam3360/secretshield
|
|
9
|
+
Project-URL: Issues, https://github.com/Sam3360/secretshield/issues
|
|
10
|
+
Keywords: security,secrets,redaction,logging,stdout,credentials
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Security
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
|
|
29
|
+
# 🛡️ SecretShield
|
|
30
|
+
|
|
31
|
+
**Your secrets shouldn't end up in your terminal, your logs, or your commit history.**
|
|
32
|
+
**SecretShield makes sure they don't — automatically.**
|
|
33
|
+
|
|
34
|
+
[](https://pypi.org/project/secretshield/)
|
|
35
|
+
[](https://pypi.org/project/secretshield/)
|
|
36
|
+
[](https://pypi.org/project/secretshield/)
|
|
37
|
+
[](LICENSE)
|
|
38
|
+
|
|
39
|
+
[Install](#installation) · [Demo](#demo) · [Quick start](#quick-start) · [Features](#what-secretshield-does) · [Docs below](#cli-reference)
|
|
40
|
+
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## The problem
|
|
46
|
+
|
|
47
|
+
You've done this. Everyone has.
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
print("API key:", api_key) # ...now it's in your terminal history
|
|
51
|
+
logger.info("Token: %s", token) # ...now it's in your log files
|
|
52
|
+
API_KEY = "sk-live-abc123..." # ...now it's about to get committed
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
One `print()` left in from debugging. One log line that dumps a config
|
|
56
|
+
dict. One hardcoded key that slips past code review. That's usually all
|
|
57
|
+
it takes.
|
|
58
|
+
|
|
59
|
+
## The fix
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install secretshield
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import secretshield
|
|
67
|
+
|
|
68
|
+
api_key = "sk-example1234567890abcdefFAKEKEY"
|
|
69
|
+
print("API key:", api_key)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
API key: ********
|
|
74
|
+
⚠ secretshield: Potential secret detected and redacted.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**No configuration. No code changes. Just `pip install` and `import`.**
|
|
78
|
+
The moment you import it, your terminal output, your logs — protected.
|
|
79
|
+
|
|
80
|
+
## Demo
|
|
81
|
+
|
|
82
|
+
See SecretShield in action:
|
|
83
|
+
|
|
84
|
+
[](https://youtu.be/g95lNIhWsXM)
|
|
85
|
+
|
|
86
|
+
**[▶ Watch the full demo on YouTube](https://youtu.be/g95lNIhWsXM)**
|
|
87
|
+
|
|
88
|
+
## Quick start
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install secretshield
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Protect a running script:
|
|
95
|
+
```python
|
|
96
|
+
import secretshield # that's it — stdout, stderr, and logging are now protected
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Scan an entire project for hardcoded secrets:
|
|
100
|
+
```bash
|
|
101
|
+
secretshield scan .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Set a whole project up in one step (config file + Git hook + CI):
|
|
105
|
+
```bash
|
|
106
|
+
secretshield init
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## What SecretShield does
|
|
110
|
+
|
|
111
|
+
SecretShield isn't just one trick — it's five layers that cover the
|
|
112
|
+
whole path a secret takes from your keyboard to a place you can't take
|
|
113
|
+
it back from:
|
|
114
|
+
|
|
115
|
+
| | |
|
|
116
|
+
|---|---|
|
|
117
|
+
| 🖥️ **Runtime protection** | Automatically redacts secrets from `stdout`, `stderr`, and `logging` the instant you `import secretshield` |
|
|
118
|
+
| 🔍 **Static scanning** | `secretshield scan .` finds hardcoded secrets across Python, JS/TS, HTML, YAML, `.env`, and more |
|
|
119
|
+
| 🔧 **Auto-Fix** | `scan . --fix` interactively moves a hardcoded secret into `.env` and rewrites your code to use it — safely, and only when it's unambiguous |
|
|
120
|
+
| 🪝 **Git pre-commit hook** | `install-hook` blocks a commit before a secret ever reaches your repo's history |
|
|
121
|
+
| ⚙️ **GitHub Actions** | `github-action` generates a workflow that scans every push and PR automatically |
|
|
122
|
+
|
|
123
|
+
All of it: **zero required dependencies, no telemetry, no network calls, nothing sent anywhere.** Everything happens locally, in your own process.
|
|
124
|
+
|
|
125
|
+
## Why star this repo
|
|
126
|
+
|
|
127
|
+
If SecretShield has ever caught something before it hit your terminal
|
|
128
|
+
or your Git history — that's the whole point of the project working.
|
|
129
|
+
Starring it costs nothing and helps the next developer who's about to
|
|
130
|
+
`print()` an API key by accident actually find this before it's too
|
|
131
|
+
late.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Installation
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install secretshield
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Requires Python 3.10+. No required third-party runtime dependencies
|
|
142
|
+
(a tiny `tomli` backport is pulled in automatically, but only on Python 3.10).
|
|
143
|
+
|
|
144
|
+
## Basic usage
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
import secretshield
|
|
148
|
+
|
|
149
|
+
password = "hunter2-example-not-real"
|
|
150
|
+
print("Using password:", password)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
Using password: ********
|
|
155
|
+
⚠ secretshield: Potential secret detected and redacted.
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Toggle protection manually if you need to:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
import secretshield
|
|
162
|
+
|
|
163
|
+
secretshield.disable()
|
|
164
|
+
secretshield.enable() # idempotent, safe to call repeatedly
|
|
165
|
+
secretshield.is_enabled()
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Or use detection/redaction directly, without touching stdout at all:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from secretshield import detect, redact
|
|
172
|
+
|
|
173
|
+
detect("aws_key=AKIAABCDEFGHIJKLMNOP")
|
|
174
|
+
# [Match(start=8, end=28, value='AKIA...', kind='aws_access_key_id')]
|
|
175
|
+
|
|
176
|
+
redact("aws_key=AKIAABCDEFGHIJKLMNOP")
|
|
177
|
+
# ("aws_key=********", True)
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## CLI reference
|
|
181
|
+
|
|
182
|
+
### `secretshield init` — set a project up in one step
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
secretshield init
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Detects your project, then interactively offers to create a config
|
|
189
|
+
file, install the Git hook, and generate the GitHub Actions workflow —
|
|
190
|
+
all in one pass instead of discovering each command separately.
|
|
191
|
+
|
|
192
|
+
### `secretshield scan` — find hardcoded secrets
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
secretshield scan . # scan a directory
|
|
196
|
+
secretshield scan app.py # scan a single file
|
|
197
|
+
secretshield scan . --json # machine-readable, CI-safe
|
|
198
|
+
secretshield scan . --fix # interactively move secrets to .env
|
|
199
|
+
secretshield scan --staged # would this commit introduce a secret?
|
|
200
|
+
secretshield scan --diff HEAD~1 # did my changes introduce a secret?
|
|
201
|
+
secretshield scan . --baseline # adopt SecretShield without fixing everything today
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Scans Python, JavaScript/TypeScript, HTML, CSS, Vue, Svelte, JSON,
|
|
205
|
+
YAML, TOML/INI, `.env` files, shell scripts, and more — treating each
|
|
206
|
+
as text and running the same detection engine regardless of language.
|
|
207
|
+
Automatically skips `.git/`, `node_modules/`, `.venv/`, binary files,
|
|
208
|
+
and obvious documentation placeholders like `your_api_key_here`.
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
SecretShield scan
|
|
212
|
+
|
|
213
|
+
✗ src/app.js:82
|
|
214
|
+
Potential secret: Bearer token
|
|
215
|
+
Type: token
|
|
216
|
+
|
|
217
|
+
✓ 143 files scanned
|
|
218
|
+
✗ 1 potential secret(s) found
|
|
219
|
+
|
|
220
|
+
Exit code: 1
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### `secretshield run` — protect a script without editing it
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
secretshield run app.py
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### `secretshield install-hook` / `uninstall-hook` — stop secrets before they're committed
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
secretshield install-hook
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Scans **staged content** (not your whole working tree) before every
|
|
236
|
+
commit and blocks it if something looks like a secret. Never destroys
|
|
237
|
+
an existing pre-commit hook — backs it up and wraps it instead.
|
|
238
|
+
|
|
239
|
+
### `secretshield github-action` — catch what slips past locally
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
secretshield github-action
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Generates `.github/workflows/secretshield.yml`, scanning every push and
|
|
246
|
+
pull request automatically.
|
|
247
|
+
|
|
248
|
+
## Configuration file
|
|
249
|
+
|
|
250
|
+
Project-wide scan settings live in `secretshield.toml` (generate one
|
|
251
|
+
with `secretshield init`):
|
|
252
|
+
|
|
253
|
+
```toml
|
|
254
|
+
[scan]
|
|
255
|
+
entropy_threshold = 4.2
|
|
256
|
+
|
|
257
|
+
[scan.ignore]
|
|
258
|
+
paths = ["tests/fixtures/", "docs/examples/"]
|
|
259
|
+
|
|
260
|
+
[scan.include]
|
|
261
|
+
patterns = ["*.py", "*.js"]
|
|
262
|
+
|
|
263
|
+
[output]
|
|
264
|
+
format = "text"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
CLI flags always override the file.
|
|
268
|
+
|
|
269
|
+
## Runtime configuration
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
import secretshield
|
|
273
|
+
|
|
274
|
+
secretshield.configure(
|
|
275
|
+
enabled=True, # master on/off switch
|
|
276
|
+
redact_with="********", # placeholder used in place of a secret
|
|
277
|
+
entropy_threshold=4.2, # bits/char threshold for generic detection
|
|
278
|
+
notify=True, # print the "potential secret" warning
|
|
279
|
+
)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Detection methods
|
|
283
|
+
|
|
284
|
+
SecretShield combines two strategies:
|
|
285
|
+
|
|
286
|
+
1. **Known-format pattern matching** — AWS keys, GitHub tokens,
|
|
287
|
+
OpenAI-style keys, Slack tokens, Stripe keys, Google API keys, JWTs,
|
|
288
|
+
bearer tokens, PEM private-key blocks, and labeled generic secrets
|
|
289
|
+
(`password =`, `api_key:`, etc.)
|
|
290
|
+
2. **High-entropy detection** — catches random-looking secrets that
|
|
291
|
+
don't match a known format, used as a conservative supplement (not
|
|
292
|
+
the primary mechanism) to keep false positives low.
|
|
293
|
+
|
|
294
|
+
## Architecture
|
|
295
|
+
|
|
296
|
+
```text
|
|
297
|
+
secretshield/
|
|
298
|
+
├── patterns.py, detector.py, redactor.py # detection & redaction engine
|
|
299
|
+
├── guardian.py # stdout/stderr + logging protection
|
|
300
|
+
├── config.py, notifications.py # runtime settings & safe warnings
|
|
301
|
+
├── project_config.py, baseline.py # secretshield.toml, --baseline
|
|
302
|
+
├── cli.py # command-line interface
|
|
303
|
+
├── autofix/ # interactive scan --fix
|
|
304
|
+
├── git/ # pre-commit hook
|
|
305
|
+
└── github/ # Actions workflow generation
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
## Testing
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
pip install -e ".[dev]"
|
|
312
|
+
pytest
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
176+ tests covering detection, redaction, runtime protection, static
|
|
316
|
+
scanning across languages, Auto-Fix, Git hooks, and CI integration. All
|
|
317
|
+
secrets used in tests and examples are fake.
|
|
318
|
+
|
|
319
|
+
## Limitations
|
|
320
|
+
|
|
321
|
+
Be honest about what this is and isn't:
|
|
322
|
+
|
|
323
|
+
- Runtime protection covers **this Python process's** `stdout`,
|
|
324
|
+
`stderr`, and `logging` — not screenshots, clipboard, arbitrary file
|
|
325
|
+
writes, other applications, or network traffic.
|
|
326
|
+
- **Auto-Fix (`--fix`)** only rewrites Python, and only unambiguous
|
|
327
|
+
simple assignments (checked via Python's own `ast` module, not a
|
|
328
|
+
regex). Anything less certain is reported but left untouched.
|
|
329
|
+
- The pre-commit hook needs `secretshield` resolvable on `PATH` at
|
|
330
|
+
commit time — keep your virtual environment active.
|
|
331
|
+
|
|
332
|
+
Treat SecretShield as a strong defense-in-depth safety net, not a
|
|
333
|
+
replacement for proper secret management (vaults, least-privilege
|
|
334
|
+
credentials, secret scanning in CI, etc.).
|
|
335
|
+
|
|
336
|
+
## Security considerations
|
|
337
|
+
|
|
338
|
+
No network calls. No telemetry. Nothing sent anywhere — detection and
|
|
339
|
+
redaction happen entirely locally, in-process.
|
|
340
|
+
|
|
341
|
+
## Contributing
|
|
342
|
+
|
|
343
|
+
Issues and PRs welcome. Please add tests for new detection patterns or
|
|
344
|
+
behavior changes, use only fake credentials in tests/examples, and run
|
|
345
|
+
`pytest` before opening a PR.
|
|
346
|
+
|
|
347
|
+
## [☕](https://github.com/sponsors/Sam3360/) Get me a coffee
|
|
348
|
+
|
|
349
|
+
If you find this project useful, consider [supporting its development through GitHub Sponsors](https://github.com/sponsors/Sam3360/).
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🛡️ SecretShield
|
|
4
|
+
|
|
5
|
+
**Your secrets shouldn't end up in your terminal, your logs, or your commit history.**
|
|
6
|
+
**SecretShield makes sure they don't — automatically.**
|
|
7
|
+
|
|
8
|
+
[](https://pypi.org/project/secretshield/)
|
|
9
|
+
[](https://pypi.org/project/secretshield/)
|
|
10
|
+
[](https://pypi.org/project/secretshield/)
|
|
11
|
+
[](LICENSE)
|
|
12
|
+
|
|
13
|
+
[Install](#installation) · [Demo](#demo) · [Quick start](#quick-start) · [Features](#what-secretshield-does) · [Docs below](#cli-reference)
|
|
14
|
+
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## The problem
|
|
20
|
+
|
|
21
|
+
You've done this. Everyone has.
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
print("API key:", api_key) # ...now it's in your terminal history
|
|
25
|
+
logger.info("Token: %s", token) # ...now it's in your log files
|
|
26
|
+
API_KEY = "sk-live-abc123..." # ...now it's about to get committed
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
One `print()` left in from debugging. One log line that dumps a config
|
|
30
|
+
dict. One hardcoded key that slips past code review. That's usually all
|
|
31
|
+
it takes.
|
|
32
|
+
|
|
33
|
+
## The fix
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install secretshield
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import secretshield
|
|
41
|
+
|
|
42
|
+
api_key = "sk-example1234567890abcdefFAKEKEY"
|
|
43
|
+
print("API key:", api_key)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
API key: ********
|
|
48
|
+
⚠ secretshield: Potential secret detected and redacted.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**No configuration. No code changes. Just `pip install` and `import`.**
|
|
52
|
+
The moment you import it, your terminal output, your logs — protected.
|
|
53
|
+
|
|
54
|
+
## Demo
|
|
55
|
+
|
|
56
|
+
See SecretShield in action:
|
|
57
|
+
|
|
58
|
+
[](https://youtu.be/g95lNIhWsXM)
|
|
59
|
+
|
|
60
|
+
**[▶ Watch the full demo on YouTube](https://youtu.be/g95lNIhWsXM)**
|
|
61
|
+
|
|
62
|
+
## Quick start
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install secretshield
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Protect a running script:
|
|
69
|
+
```python
|
|
70
|
+
import secretshield # that's it — stdout, stderr, and logging are now protected
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Scan an entire project for hardcoded secrets:
|
|
74
|
+
```bash
|
|
75
|
+
secretshield scan .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Set a whole project up in one step (config file + Git hook + CI):
|
|
79
|
+
```bash
|
|
80
|
+
secretshield init
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## What SecretShield does
|
|
84
|
+
|
|
85
|
+
SecretShield isn't just one trick — it's five layers that cover the
|
|
86
|
+
whole path a secret takes from your keyboard to a place you can't take
|
|
87
|
+
it back from:
|
|
88
|
+
|
|
89
|
+
| | |
|
|
90
|
+
|---|---|
|
|
91
|
+
| 🖥️ **Runtime protection** | Automatically redacts secrets from `stdout`, `stderr`, and `logging` the instant you `import secretshield` |
|
|
92
|
+
| 🔍 **Static scanning** | `secretshield scan .` finds hardcoded secrets across Python, JS/TS, HTML, YAML, `.env`, and more |
|
|
93
|
+
| 🔧 **Auto-Fix** | `scan . --fix` interactively moves a hardcoded secret into `.env` and rewrites your code to use it — safely, and only when it's unambiguous |
|
|
94
|
+
| 🪝 **Git pre-commit hook** | `install-hook` blocks a commit before a secret ever reaches your repo's history |
|
|
95
|
+
| ⚙️ **GitHub Actions** | `github-action` generates a workflow that scans every push and PR automatically |
|
|
96
|
+
|
|
97
|
+
All of it: **zero required dependencies, no telemetry, no network calls, nothing sent anywhere.** Everything happens locally, in your own process.
|
|
98
|
+
|
|
99
|
+
## Why star this repo
|
|
100
|
+
|
|
101
|
+
If SecretShield has ever caught something before it hit your terminal
|
|
102
|
+
or your Git history — that's the whole point of the project working.
|
|
103
|
+
Starring it costs nothing and helps the next developer who's about to
|
|
104
|
+
`print()` an API key by accident actually find this before it's too
|
|
105
|
+
late.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Installation
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
pip install secretshield
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Requires Python 3.10+. No required third-party runtime dependencies
|
|
116
|
+
(a tiny `tomli` backport is pulled in automatically, but only on Python 3.10).
|
|
117
|
+
|
|
118
|
+
## Basic usage
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
import secretshield
|
|
122
|
+
|
|
123
|
+
password = "hunter2-example-not-real"
|
|
124
|
+
print("Using password:", password)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```text
|
|
128
|
+
Using password: ********
|
|
129
|
+
⚠ secretshield: Potential secret detected and redacted.
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Toggle protection manually if you need to:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
import secretshield
|
|
136
|
+
|
|
137
|
+
secretshield.disable()
|
|
138
|
+
secretshield.enable() # idempotent, safe to call repeatedly
|
|
139
|
+
secretshield.is_enabled()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Or use detection/redaction directly, without touching stdout at all:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from secretshield import detect, redact
|
|
146
|
+
|
|
147
|
+
detect("aws_key=AKIAABCDEFGHIJKLMNOP")
|
|
148
|
+
# [Match(start=8, end=28, value='AKIA...', kind='aws_access_key_id')]
|
|
149
|
+
|
|
150
|
+
redact("aws_key=AKIAABCDEFGHIJKLMNOP")
|
|
151
|
+
# ("aws_key=********", True)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## CLI reference
|
|
155
|
+
|
|
156
|
+
### `secretshield init` — set a project up in one step
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
secretshield init
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Detects your project, then interactively offers to create a config
|
|
163
|
+
file, install the Git hook, and generate the GitHub Actions workflow —
|
|
164
|
+
all in one pass instead of discovering each command separately.
|
|
165
|
+
|
|
166
|
+
### `secretshield scan` — find hardcoded secrets
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
secretshield scan . # scan a directory
|
|
170
|
+
secretshield scan app.py # scan a single file
|
|
171
|
+
secretshield scan . --json # machine-readable, CI-safe
|
|
172
|
+
secretshield scan . --fix # interactively move secrets to .env
|
|
173
|
+
secretshield scan --staged # would this commit introduce a secret?
|
|
174
|
+
secretshield scan --diff HEAD~1 # did my changes introduce a secret?
|
|
175
|
+
secretshield scan . --baseline # adopt SecretShield without fixing everything today
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Scans Python, JavaScript/TypeScript, HTML, CSS, Vue, Svelte, JSON,
|
|
179
|
+
YAML, TOML/INI, `.env` files, shell scripts, and more — treating each
|
|
180
|
+
as text and running the same detection engine regardless of language.
|
|
181
|
+
Automatically skips `.git/`, `node_modules/`, `.venv/`, binary files,
|
|
182
|
+
and obvious documentation placeholders like `your_api_key_here`.
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
SecretShield scan
|
|
186
|
+
|
|
187
|
+
✗ src/app.js:82
|
|
188
|
+
Potential secret: Bearer token
|
|
189
|
+
Type: token
|
|
190
|
+
|
|
191
|
+
✓ 143 files scanned
|
|
192
|
+
✗ 1 potential secret(s) found
|
|
193
|
+
|
|
194
|
+
Exit code: 1
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### `secretshield run` — protect a script without editing it
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
secretshield run app.py
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `secretshield install-hook` / `uninstall-hook` — stop secrets before they're committed
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
secretshield install-hook
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Scans **staged content** (not your whole working tree) before every
|
|
210
|
+
commit and blocks it if something looks like a secret. Never destroys
|
|
211
|
+
an existing pre-commit hook — backs it up and wraps it instead.
|
|
212
|
+
|
|
213
|
+
### `secretshield github-action` — catch what slips past locally
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
secretshield github-action
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Generates `.github/workflows/secretshield.yml`, scanning every push and
|
|
220
|
+
pull request automatically.
|
|
221
|
+
|
|
222
|
+
## Configuration file
|
|
223
|
+
|
|
224
|
+
Project-wide scan settings live in `secretshield.toml` (generate one
|
|
225
|
+
with `secretshield init`):
|
|
226
|
+
|
|
227
|
+
```toml
|
|
228
|
+
[scan]
|
|
229
|
+
entropy_threshold = 4.2
|
|
230
|
+
|
|
231
|
+
[scan.ignore]
|
|
232
|
+
paths = ["tests/fixtures/", "docs/examples/"]
|
|
233
|
+
|
|
234
|
+
[scan.include]
|
|
235
|
+
patterns = ["*.py", "*.js"]
|
|
236
|
+
|
|
237
|
+
[output]
|
|
238
|
+
format = "text"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
CLI flags always override the file.
|
|
242
|
+
|
|
243
|
+
## Runtime configuration
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
import secretshield
|
|
247
|
+
|
|
248
|
+
secretshield.configure(
|
|
249
|
+
enabled=True, # master on/off switch
|
|
250
|
+
redact_with="********", # placeholder used in place of a secret
|
|
251
|
+
entropy_threshold=4.2, # bits/char threshold for generic detection
|
|
252
|
+
notify=True, # print the "potential secret" warning
|
|
253
|
+
)
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Detection methods
|
|
257
|
+
|
|
258
|
+
SecretShield combines two strategies:
|
|
259
|
+
|
|
260
|
+
1. **Known-format pattern matching** — AWS keys, GitHub tokens,
|
|
261
|
+
OpenAI-style keys, Slack tokens, Stripe keys, Google API keys, JWTs,
|
|
262
|
+
bearer tokens, PEM private-key blocks, and labeled generic secrets
|
|
263
|
+
(`password =`, `api_key:`, etc.)
|
|
264
|
+
2. **High-entropy detection** — catches random-looking secrets that
|
|
265
|
+
don't match a known format, used as a conservative supplement (not
|
|
266
|
+
the primary mechanism) to keep false positives low.
|
|
267
|
+
|
|
268
|
+
## Architecture
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
secretshield/
|
|
272
|
+
├── patterns.py, detector.py, redactor.py # detection & redaction engine
|
|
273
|
+
├── guardian.py # stdout/stderr + logging protection
|
|
274
|
+
├── config.py, notifications.py # runtime settings & safe warnings
|
|
275
|
+
├── project_config.py, baseline.py # secretshield.toml, --baseline
|
|
276
|
+
├── cli.py # command-line interface
|
|
277
|
+
├── autofix/ # interactive scan --fix
|
|
278
|
+
├── git/ # pre-commit hook
|
|
279
|
+
└── github/ # Actions workflow generation
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Testing
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
pip install -e ".[dev]"
|
|
286
|
+
pytest
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
176+ tests covering detection, redaction, runtime protection, static
|
|
290
|
+
scanning across languages, Auto-Fix, Git hooks, and CI integration. All
|
|
291
|
+
secrets used in tests and examples are fake.
|
|
292
|
+
|
|
293
|
+
## Limitations
|
|
294
|
+
|
|
295
|
+
Be honest about what this is and isn't:
|
|
296
|
+
|
|
297
|
+
- Runtime protection covers **this Python process's** `stdout`,
|
|
298
|
+
`stderr`, and `logging` — not screenshots, clipboard, arbitrary file
|
|
299
|
+
writes, other applications, or network traffic.
|
|
300
|
+
- **Auto-Fix (`--fix`)** only rewrites Python, and only unambiguous
|
|
301
|
+
simple assignments (checked via Python's own `ast` module, not a
|
|
302
|
+
regex). Anything less certain is reported but left untouched.
|
|
303
|
+
- The pre-commit hook needs `secretshield` resolvable on `PATH` at
|
|
304
|
+
commit time — keep your virtual environment active.
|
|
305
|
+
|
|
306
|
+
Treat SecretShield as a strong defense-in-depth safety net, not a
|
|
307
|
+
replacement for proper secret management (vaults, least-privilege
|
|
308
|
+
credentials, secret scanning in CI, etc.).
|
|
309
|
+
|
|
310
|
+
## Security considerations
|
|
311
|
+
|
|
312
|
+
No network calls. No telemetry. Nothing sent anywhere — detection and
|
|
313
|
+
redaction happen entirely locally, in-process.
|
|
314
|
+
|
|
315
|
+
## Contributing
|
|
316
|
+
|
|
317
|
+
Issues and PRs welcome. Please add tests for new detection patterns or
|
|
318
|
+
behavior changes, use only fake credentials in tests/examples, and run
|
|
319
|
+
`pytest` before opening a PR.
|
|
320
|
+
|
|
321
|
+
## [☕](https://github.com/sponsors/Sam3360/) Get me a coffee
|
|
322
|
+
|
|
323
|
+
If you find this project useful, consider [supporting its development through GitHub Sponsors](https://github.com/sponsors/Sam3360/).
|
|
324
|
+
|
|
325
|
+
## License
|
|
326
|
+
|
|
327
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "secretshield"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Detect
|
|
7
|
+
version = "0.4.1"
|
|
8
|
+
description = "Detect, redact, and prevent secret exposure in Python apps, source code, and Git commits — runtime protection, multi-language scanning, auto-fix, and CI integration in one tool."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -23,7 +23,9 @@ classifiers = [
|
|
|
23
23
|
"Topic :: Security",
|
|
24
24
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
25
|
]
|
|
26
|
-
dependencies = [
|
|
26
|
+
dependencies = [
|
|
27
|
+
"tomli>=2.0; python_version < \"3.11\"",
|
|
28
|
+
]
|
|
27
29
|
|
|
28
30
|
[project.optional-dependencies]
|
|
29
31
|
dev = [
|