credactor 2.3.2__tar.gz → 2.3.3__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.
Files changed (38) hide show
  1. credactor-2.3.3/PKG-INFO +152 -0
  2. credactor-2.3.3/README.md +125 -0
  3. {credactor-2.3.2 → credactor-2.3.3}/credactor/__init__.py +1 -1
  4. {credactor-2.3.2 → credactor-2.3.3}/credactor/config.py +32 -7
  5. {credactor-2.3.2 → credactor-2.3.3}/credactor/report.py +17 -7
  6. {credactor-2.3.2 → credactor-2.3.3}/credactor/scanner.py +9 -2
  7. credactor-2.3.3/credactor.egg-info/PKG-INFO +152 -0
  8. {credactor-2.3.2 → credactor-2.3.3}/pyproject.toml +1 -1
  9. credactor-2.3.3/tests/test_security.py +323 -0
  10. credactor-2.3.2/PKG-INFO +0 -81
  11. credactor-2.3.2/README.md +0 -54
  12. credactor-2.3.2/credactor.egg-info/PKG-INFO +0 -81
  13. credactor-2.3.2/tests/test_security.py +0 -128
  14. {credactor-2.3.2 → credactor-2.3.3}/LICENSE +0 -0
  15. {credactor-2.3.2 → credactor-2.3.3}/credactor/__main__.py +0 -0
  16. {credactor-2.3.2 → credactor-2.3.3}/credactor/cli.py +0 -0
  17. {credactor-2.3.2 → credactor-2.3.3}/credactor/gitignore.py +0 -0
  18. {credactor-2.3.2 → credactor-2.3.3}/credactor/patterns.py +0 -0
  19. {credactor-2.3.2 → credactor-2.3.3}/credactor/redactor.py +0 -0
  20. {credactor-2.3.2 → credactor-2.3.3}/credactor/suppressions.py +0 -0
  21. {credactor-2.3.2 → credactor-2.3.3}/credactor/utils.py +0 -0
  22. {credactor-2.3.2 → credactor-2.3.3}/credactor/walker.py +0 -0
  23. {credactor-2.3.2 → credactor-2.3.3}/credactor.egg-info/SOURCES.txt +0 -0
  24. {credactor-2.3.2 → credactor-2.3.3}/credactor.egg-info/dependency_links.txt +0 -0
  25. {credactor-2.3.2 → credactor-2.3.3}/credactor.egg-info/entry_points.txt +0 -0
  26. {credactor-2.3.2 → credactor-2.3.3}/credactor.egg-info/requires.txt +0 -0
  27. {credactor-2.3.2 → credactor-2.3.3}/credactor.egg-info/top_level.txt +0 -0
  28. {credactor-2.3.2 → credactor-2.3.3}/setup.cfg +0 -0
  29. {credactor-2.3.2 → credactor-2.3.3}/tests/test_cli.py +0 -0
  30. {credactor-2.3.2 → credactor-2.3.3}/tests/test_config.py +0 -0
  31. {credactor-2.3.2 → credactor-2.3.3}/tests/test_gitignore.py +0 -0
  32. {credactor-2.3.2 → credactor-2.3.3}/tests/test_patterns.py +0 -0
  33. {credactor-2.3.2 → credactor-2.3.3}/tests/test_redactor.py +0 -0
  34. {credactor-2.3.2 → credactor-2.3.3}/tests/test_report.py +0 -0
  35. {credactor-2.3.2 → credactor-2.3.3}/tests/test_safe_values.py +0 -0
  36. {credactor-2.3.2 → credactor-2.3.3}/tests/test_scanner.py +0 -0
  37. {credactor-2.3.2 → credactor-2.3.3}/tests/test_suppressions.py +0 -0
  38. {credactor-2.3.2 → credactor-2.3.3}/tests/test_walker.py +0 -0
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: credactor
3
+ Version: 2.3.3
4
+ Summary: Scan and redact hardcoded credentials in source code
5
+ Author: Rx
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Repository, https://github.com/rxb06/Credactor
8
+ Keywords: security,credentials,secrets,scanner,redactor
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Security
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: encoding
22
+ Requires-Dist: charset-normalizer>=3.0; extra == "encoding"
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.5; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/credactor)](https://pypi.org/project/credactor/)
29
+ [![CI](https://github.com/rxb06/Credactor/actions/workflows/ci.yml/badge.svg)](https://github.com/rxb06/Credactor/actions/workflows/ci.yml)
30
+ [![License](https://img.shields.io/badge/licence-Apache%202.0-blue)](LICENSE)
31
+
32
+ # Credactor
33
+
34
+ > **TL;DR:** Detect and redact hardcoded credentials before they hit version control. Regex + entropy + context-aware analysis, SARIF output, pre-commit hooks, parallel scanning, automated redaction.
35
+
36
+ Credactor scans source code for hardcoded secrets — API keys, tokens, passwords, private keys, connection strings — and replaces them with language-aware environment variable references before they reach version control. It runs as a CLI tool, a pre-commit hook, or in CI pipelines. SARIF output plugs straight into GitHub Code Scanning.
37
+
38
+ <img width="1280" height="640" alt="credactor" src="https://github.com/user-attachments/assets/f1f94a9c-feea-4b8b-9ea4-81f25f07c4df" />
39
+
40
+ ---
41
+
42
+ ## Why Credactor?
43
+
44
+ Most secret scanners stop at detection. Credactor redacts in place and replaces credentials with the right env var syntax for each language — `os.environ` in Python, `process.env` in JS, `System.getenv` in Java, and so on. It assigns severity levels so you can triage critical findings first instead of wading through noise.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install credactor
50
+ ```
51
+
52
+ From source:
53
+
54
+ ```bash
55
+ git clone https://github.com/rxb06/Credactor.git
56
+ cd Credactor
57
+ pip install -e .
58
+ ```
59
+
60
+ After either method, `credactor` works from any directory.
61
+
62
+ ## Quick Start
63
+
64
+ > Always run `--dry-run` first and review findings before redacting. False positives are possible — use `# credactor:ignore` or `.credactorignore` to suppress them.
65
+
66
+ ```bash
67
+ # Scan current directory (dry run)
68
+ credactor --dry-run .
69
+
70
+ # Scan and interactively redact
71
+ credactor .
72
+
73
+ # Redact everything without prompting
74
+ credactor --fix-all .
75
+
76
+ # CI mode — exit 1 on findings
77
+ credactor --ci .
78
+ ```
79
+
80
+ ### Pre-commit Hook
81
+
82
+ ```yaml
83
+ # .pre-commit-config.yaml
84
+ repos:
85
+ - repo: https://github.com/rxb06/Credactor
86
+ rev: v2.3.3
87
+ hooks:
88
+ - id: credactor
89
+ ```
90
+
91
+ Or run as a module:
92
+
93
+ ```bash
94
+ python -m credactor .
95
+ ```
96
+
97
+ ## Detection
98
+
99
+ | Category | Examples | Severity |
100
+ |---|---|---|
101
+ | Cloud provider keys | AWS (`AKIA...`), GCP (`AIza...`), Stripe (`sk_live_...`), Slack (`xoxb-...`) | Critical |
102
+ | Platform tokens | GitHub (`ghp_`, `github_pat_`), GitLab (`glpat-`), npm (`npm_`), PyPI (`pypi-`) | Critical |
103
+ | Private keys | PEM blocks (`-----BEGIN RSA PRIVATE KEY-----`) | Critical |
104
+ | JWT tokens | `eyJ...` three-segment tokens | High |
105
+ | Connection strings | `postgresql://user:pass@host`, `mongodb+srv://...`, `redis://...` | High |
106
+ | Variable assignments | `password = "..."`, `api_key = "..."`, `db_password = "..."` | High/Medium |
107
+ | XML attributes | `<add key="Password" value="..." />` | High |
108
+ | High-entropy strings | Hex (32-64 chars), Base64 (60+ chars) | Medium/Low |
109
+
110
+ ## Features
111
+
112
+ - Entropy-based detection with per-pattern thresholds to cut false positives
113
+ - Interactive or batch redaction — review one-by-one, or `--fix-all`
114
+ - Language-aware replacements (`os.environ`, `process.env`, `System.getenv`, etc.)
115
+ - Git history scanning via `--scan-history`
116
+ - `.bak` backups before any file modification
117
+ - Inline `# credactor:ignore` suppression and `.credactorignore` allowlists
118
+ - Per-repo config via `.credactor.toml`
119
+ - Parallel scanning (8 workers) for large repos
120
+ - SARIF 2.1.0 output with column-level annotations for GitHub Code Scanning
121
+ - `--fail-on-error` to catch files that couldn't be scanned
122
+
123
+ ## Scanned File Types
124
+
125
+ `.py` `.js` `.ts` `.jsx` `.tsx` `.sh` `.bash` `.env` `.env.*` `.cfg` `.ini` `.toml` `.yaml` `.yml` `.rb` `.go` `.java` `.php` `.cs` `.kt` `.tf` `.hcl` `.conf` `.properties` `.xml`
126
+
127
+ JSON files are excluded by default (high false-positive rate from API responses). Use `--scan-json` to include them.
128
+
129
+ ## Exit Codes
130
+
131
+ | Code | Meaning |
132
+ |---|---|
133
+ | `0` | No findings, or all resolved |
134
+ | `1` | Unresolved findings |
135
+ | `2` | Error, or files skipped with `--fail-on-error` |
136
+
137
+ ## Docs
138
+
139
+ | Document | Description |
140
+ |----------|-------------|
141
+ | [Setup Guide](docs/setup.md) | Installation, configuration, CI/CD integration |
142
+ | [User Guide](docs/user-guide.md) | CLI reference, replacement modes, backup safety |
143
+ | [Examples](docs/examples.md) | Common workflows with output |
144
+ | [Integration](docs/integration.md) | Pre-commit hooks, CI pipelines |
145
+ | [Security](docs/security.md) | Threat model, hardening measures, known limitations |
146
+ | [Changelog](CHANGELOG.md) | Version history |
147
+ | [Contributing](CONTRIBUTING.md) | Development setup, code style, PR process |
148
+ | [Disclaimer](docs/DISCLAIMER.md) | Limitations, safe usage, warranty |
149
+
150
+ ## Licence
151
+
152
+ Apache 2.0. See [LICENSE](LICENSE).
@@ -0,0 +1,125 @@
1
+ [![PyPI](https://img.shields.io/pypi/v/credactor)](https://pypi.org/project/credactor/)
2
+ [![CI](https://github.com/rxb06/Credactor/actions/workflows/ci.yml/badge.svg)](https://github.com/rxb06/Credactor/actions/workflows/ci.yml)
3
+ [![License](https://img.shields.io/badge/licence-Apache%202.0-blue)](LICENSE)
4
+
5
+ # Credactor
6
+
7
+ > **TL;DR:** Detect and redact hardcoded credentials before they hit version control. Regex + entropy + context-aware analysis, SARIF output, pre-commit hooks, parallel scanning, automated redaction.
8
+
9
+ Credactor scans source code for hardcoded secrets — API keys, tokens, passwords, private keys, connection strings — and replaces them with language-aware environment variable references before they reach version control. It runs as a CLI tool, a pre-commit hook, or in CI pipelines. SARIF output plugs straight into GitHub Code Scanning.
10
+
11
+ <img width="1280" height="640" alt="credactor" src="https://github.com/user-attachments/assets/f1f94a9c-feea-4b8b-9ea4-81f25f07c4df" />
12
+
13
+ ---
14
+
15
+ ## Why Credactor?
16
+
17
+ Most secret scanners stop at detection. Credactor redacts in place and replaces credentials with the right env var syntax for each language — `os.environ` in Python, `process.env` in JS, `System.getenv` in Java, and so on. It assigns severity levels so you can triage critical findings first instead of wading through noise.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pip install credactor
23
+ ```
24
+
25
+ From source:
26
+
27
+ ```bash
28
+ git clone https://github.com/rxb06/Credactor.git
29
+ cd Credactor
30
+ pip install -e .
31
+ ```
32
+
33
+ After either method, `credactor` works from any directory.
34
+
35
+ ## Quick Start
36
+
37
+ > Always run `--dry-run` first and review findings before redacting. False positives are possible — use `# credactor:ignore` or `.credactorignore` to suppress them.
38
+
39
+ ```bash
40
+ # Scan current directory (dry run)
41
+ credactor --dry-run .
42
+
43
+ # Scan and interactively redact
44
+ credactor .
45
+
46
+ # Redact everything without prompting
47
+ credactor --fix-all .
48
+
49
+ # CI mode — exit 1 on findings
50
+ credactor --ci .
51
+ ```
52
+
53
+ ### Pre-commit Hook
54
+
55
+ ```yaml
56
+ # .pre-commit-config.yaml
57
+ repos:
58
+ - repo: https://github.com/rxb06/Credactor
59
+ rev: v2.3.3
60
+ hooks:
61
+ - id: credactor
62
+ ```
63
+
64
+ Or run as a module:
65
+
66
+ ```bash
67
+ python -m credactor .
68
+ ```
69
+
70
+ ## Detection
71
+
72
+ | Category | Examples | Severity |
73
+ |---|---|---|
74
+ | Cloud provider keys | AWS (`AKIA...`), GCP (`AIza...`), Stripe (`sk_live_...`), Slack (`xoxb-...`) | Critical |
75
+ | Platform tokens | GitHub (`ghp_`, `github_pat_`), GitLab (`glpat-`), npm (`npm_`), PyPI (`pypi-`) | Critical |
76
+ | Private keys | PEM blocks (`-----BEGIN RSA PRIVATE KEY-----`) | Critical |
77
+ | JWT tokens | `eyJ...` three-segment tokens | High |
78
+ | Connection strings | `postgresql://user:pass@host`, `mongodb+srv://...`, `redis://...` | High |
79
+ | Variable assignments | `password = "..."`, `api_key = "..."`, `db_password = "..."` | High/Medium |
80
+ | XML attributes | `<add key="Password" value="..." />` | High |
81
+ | High-entropy strings | Hex (32-64 chars), Base64 (60+ chars) | Medium/Low |
82
+
83
+ ## Features
84
+
85
+ - Entropy-based detection with per-pattern thresholds to cut false positives
86
+ - Interactive or batch redaction — review one-by-one, or `--fix-all`
87
+ - Language-aware replacements (`os.environ`, `process.env`, `System.getenv`, etc.)
88
+ - Git history scanning via `--scan-history`
89
+ - `.bak` backups before any file modification
90
+ - Inline `# credactor:ignore` suppression and `.credactorignore` allowlists
91
+ - Per-repo config via `.credactor.toml`
92
+ - Parallel scanning (8 workers) for large repos
93
+ - SARIF 2.1.0 output with column-level annotations for GitHub Code Scanning
94
+ - `--fail-on-error` to catch files that couldn't be scanned
95
+
96
+ ## Scanned File Types
97
+
98
+ `.py` `.js` `.ts` `.jsx` `.tsx` `.sh` `.bash` `.env` `.env.*` `.cfg` `.ini` `.toml` `.yaml` `.yml` `.rb` `.go` `.java` `.php` `.cs` `.kt` `.tf` `.hcl` `.conf` `.properties` `.xml`
99
+
100
+ JSON files are excluded by default (high false-positive rate from API responses). Use `--scan-json` to include them.
101
+
102
+ ## Exit Codes
103
+
104
+ | Code | Meaning |
105
+ |---|---|
106
+ | `0` | No findings, or all resolved |
107
+ | `1` | Unresolved findings |
108
+ | `2` | Error, or files skipped with `--fail-on-error` |
109
+
110
+ ## Docs
111
+
112
+ | Document | Description |
113
+ |----------|-------------|
114
+ | [Setup Guide](docs/setup.md) | Installation, configuration, CI/CD integration |
115
+ | [User Guide](docs/user-guide.md) | CLI reference, replacement modes, backup safety |
116
+ | [Examples](docs/examples.md) | Common workflows with output |
117
+ | [Integration](docs/integration.md) | Pre-commit hooks, CI pipelines |
118
+ | [Security](docs/security.md) | Threat model, hardening measures, known limitations |
119
+ | [Changelog](CHANGELOG.md) | Version history |
120
+ | [Contributing](CONTRIBUTING.md) | Development setup, code style, PR process |
121
+ | [Disclaimer](docs/DISCLAIMER.md) | Limitations, safe usage, warranty |
122
+
123
+ ## Licence
124
+
125
+ Apache 2.0. See [LICENSE](LICENSE).
@@ -1,3 +1,3 @@
1
1
  """Credactor — credential redactor for source code."""
2
2
 
3
- __version__ = '2.3.2'
3
+ __version__ = '2.3.3'
@@ -94,10 +94,22 @@ def load_config_file(
94
94
  # Normpath for cross-platform separator normalisation, then
95
95
  # append os.sep AFTER normpath to prevent prefix collision.
96
96
  _cand = os.path.normpath(str(candidate.resolve()))
97
- _root = os.path.normpath(str(project_root))
98
- if project_root and not (
99
- _cand == _root or _cand.startswith(_root + os.sep)
100
- ):
97
+ _scan = os.path.normpath(str(Path(root).resolve()))
98
+
99
+ if project_root:
100
+ _root = os.path.normpath(str(project_root))
101
+ outside = not (
102
+ _cand == _root or _cand.startswith(_root + os.sep)
103
+ )
104
+ else:
105
+ # SEC-39: No project root found (no .git). Fall back to
106
+ # checking against the scan root — warn if config is in
107
+ # a parent directory, since we cannot verify trust.
108
+ outside = not (
109
+ _cand == _scan or _cand.startswith(_scan + os.sep)
110
+ )
111
+
112
+ if outside:
101
113
  if ci_mode:
102
114
  # SEC-29: Hard block in CI — never trust external config
103
115
  print(
@@ -106,9 +118,10 @@ def load_config_file(
106
118
  file=sys.stderr,
107
119
  )
108
120
  return {}
121
+ ref = project_root or root
109
122
  print(
110
123
  f'[WARN] Config loaded from outside project root: '
111
- f'{candidate} (project root: {project_root})',
124
+ f'{candidate} (project root: {ref})',
112
125
  file=sys.stderr,
113
126
  )
114
127
  return _parse_toml(candidate)
@@ -173,7 +186,13 @@ def _basic_toml_parse(path: Path) -> dict:
173
186
  def apply_config_file(config: Config, file_data: dict) -> None:
174
187
  """Merge values from a parsed config file into the Config object."""
175
188
  if 'entropy_threshold' in file_data:
176
- val = float(file_data['entropy_threshold'])
189
+ # SEC-38: Guard against type confusion (e.g. array where scalar expected).
190
+ try:
191
+ val = float(file_data['entropy_threshold'])
192
+ except (ValueError, TypeError):
193
+ print('[WARN] entropy_threshold has invalid type, using default 3.5',
194
+ file=sys.stderr)
195
+ val = 3.5
177
196
  # SEC-12: Bound entropy threshold to valid Shannon entropy range
178
197
  if not 0.0 <= val <= 6.0:
179
198
  print(f'[WARN] entropy_threshold={val} out of valid range (0.0-6.0), '
@@ -181,7 +200,13 @@ def apply_config_file(config: Config, file_data: dict) -> None:
181
200
  val = 3.5
182
201
  config.entropy_threshold = val
183
202
  if 'min_value_length' in file_data:
184
- val_i = int(file_data['min_value_length'])
203
+ # SEC-38: Guard against type confusion.
204
+ try:
205
+ val_i = int(file_data['min_value_length'])
206
+ except (ValueError, TypeError):
207
+ print('[WARN] min_value_length has invalid type, using default 8',
208
+ file=sys.stderr)
209
+ val_i = 8
185
210
  # SEC-12: Bound min_value_length to reasonable range
186
211
  if not 1 <= val_i <= 200:
187
212
  print(f'[WARN] min_value_length={val_i} out of valid range (1-200), '
@@ -14,7 +14,7 @@ from pathlib import Path
14
14
  from typing import TextIO
15
15
 
16
16
  from . import __version__
17
- from .utils import mask_secret
17
+ from .utils import mask_secret, sanitize_for_terminal
18
18
 
19
19
  # ---------------------------------------------------------------------------
20
20
  # ANSI color helpers (#31)
@@ -82,7 +82,10 @@ def print_report(
82
82
  rel = Path(filepath).relative_to(root_path)
83
83
  except ValueError:
84
84
  rel = Path(filepath)
85
- print(_c(f' FILE: {rel}', 'bold', use_color=color), file=stream)
85
+ # SEC-36: Sanitise file path for terminal output to prevent
86
+ # escape-sequence injection via crafted filenames.
87
+ safe_rel = sanitize_for_terminal(str(rel))
88
+ print(_c(f' FILE: {safe_rel}', 'bold', use_color=color), file=stream)
86
89
  print(f' {"─" * 60}', file=stream)
87
90
  for finding in file_findings:
88
91
  severity = finding.get('severity', 'medium')
@@ -91,9 +94,12 @@ def print_report(
91
94
  # #2/#29 — mask the credential in the raw line display
92
95
  masked_raw = _mask_in_line(finding['raw'], finding['full_value'])
93
96
 
97
+ # SEC-36: Sanitise type and raw line for terminal output.
98
+ safe_type = sanitize_for_terminal(finding['type'])
99
+ safe_raw = sanitize_for_terminal(masked_raw[:120])
94
100
  sev_label = _c(f'[{severity.upper()}]', sev_color, use_color=color)
95
- print(f' Line {finding["line"]:>4} {sev_label} [{finding["type"]}]', file=stream)
96
- print(f' {masked_raw[:120]}', file=stream)
101
+ print(f' Line {finding["line"]:>4} {sev_label} [{safe_type}]', file=stream)
102
+ print(f' {safe_raw}', file=stream)
97
103
  print(file=stream)
98
104
 
99
105
  print(f'{"=" * 70}', file=stream)
@@ -142,13 +148,17 @@ def sarif_report(findings: list[dict], root: str) -> str:
142
148
  results = []
143
149
 
144
150
  for f in findings:
145
- rule_id = f['type'].replace(':', '-')
151
+ # SEC-35: Sanitise finding type for SARIF rule fields. The type can
152
+ # contain attacker-controlled content (e.g. xml-attr keys), so escape
153
+ # HTML to prevent XSS in downstream SARIF viewers.
154
+ safe_type = html.escape(f['type'])
155
+ rule_id = safe_type.replace(':', '-')
146
156
  if rule_id not in rules:
147
157
  rules[rule_id] = {
148
158
  'id': rule_id,
149
- 'shortDescription': {'text': f['type']},
159
+ 'shortDescription': {'text': safe_type},
150
160
  'fullDescription': {
151
- 'text': f'Credactor detected a potential hardcoded credential ({f["type"]})',
161
+ 'text': f'Credactor detected a potential hardcoded credential ({safe_type})',
152
162
  },
153
163
  'help': {
154
164
  'text': ('Remove the hardcoded credential and use an'
@@ -105,8 +105,15 @@ def _is_safe_value(val: str, extra_safe: set[str] | None = None) -> bool:
105
105
  if cleaned.startswith('${') and '}' in cleaned:
106
106
  return True
107
107
  if cleaned.startswith('$') and not cleaned.startswith('${'):
108
- # Bare env var: $VAR or $VAR_NAME no braces, always safe
109
- return True
108
+ # SEC-37: Bare $VAR validate that the text after $ begins with a
109
+ # plausible POSIX env var name ([A-Za-z_][A-Za-z0-9_]*). Uses
110
+ # re.match (prefix) rather than fullmatch so that dynamic references
111
+ # with suffixes ($HOME/.aws/credentials, $TOKEN:prefix, $VAR-suffix)
112
+ # remain safe while pure non-identifier strings ($+foo, $/path,
113
+ # $123abc) are correctly rejected.
114
+ env_name = cleaned[1:]
115
+ if env_name and re.match(r'[A-Za-z_][A-Za-z0-9_]*', env_name):
116
+ return True
110
117
  if cleaned.startswith('{%') and '%}' in cleaned:
111
118
  return True
112
119
  if cleaned.startswith('{{') and '}}' in cleaned:
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: credactor
3
+ Version: 2.3.3
4
+ Summary: Scan and redact hardcoded credentials in source code
5
+ Author: Rx
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Repository, https://github.com/rxb06/Credactor
8
+ Keywords: security,credentials,secrets,scanner,redactor
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Topic :: Security
17
+ Classifier: Topic :: Software Development :: Quality Assurance
18
+ Requires-Python: >=3.10
19
+ Description-Content-Type: text/markdown
20
+ License-File: LICENSE
21
+ Provides-Extra: encoding
22
+ Requires-Dist: charset-normalizer>=3.0; extra == "encoding"
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8.0; extra == "dev"
25
+ Requires-Dist: ruff>=0.5; extra == "dev"
26
+ Dynamic: license-file
27
+
28
+ [![PyPI](https://img.shields.io/pypi/v/credactor)](https://pypi.org/project/credactor/)
29
+ [![CI](https://github.com/rxb06/Credactor/actions/workflows/ci.yml/badge.svg)](https://github.com/rxb06/Credactor/actions/workflows/ci.yml)
30
+ [![License](https://img.shields.io/badge/licence-Apache%202.0-blue)](LICENSE)
31
+
32
+ # Credactor
33
+
34
+ > **TL;DR:** Detect and redact hardcoded credentials before they hit version control. Regex + entropy + context-aware analysis, SARIF output, pre-commit hooks, parallel scanning, automated redaction.
35
+
36
+ Credactor scans source code for hardcoded secrets — API keys, tokens, passwords, private keys, connection strings — and replaces them with language-aware environment variable references before they reach version control. It runs as a CLI tool, a pre-commit hook, or in CI pipelines. SARIF output plugs straight into GitHub Code Scanning.
37
+
38
+ <img width="1280" height="640" alt="credactor" src="https://github.com/user-attachments/assets/f1f94a9c-feea-4b8b-9ea4-81f25f07c4df" />
39
+
40
+ ---
41
+
42
+ ## Why Credactor?
43
+
44
+ Most secret scanners stop at detection. Credactor redacts in place and replaces credentials with the right env var syntax for each language — `os.environ` in Python, `process.env` in JS, `System.getenv` in Java, and so on. It assigns severity levels so you can triage critical findings first instead of wading through noise.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install credactor
50
+ ```
51
+
52
+ From source:
53
+
54
+ ```bash
55
+ git clone https://github.com/rxb06/Credactor.git
56
+ cd Credactor
57
+ pip install -e .
58
+ ```
59
+
60
+ After either method, `credactor` works from any directory.
61
+
62
+ ## Quick Start
63
+
64
+ > Always run `--dry-run` first and review findings before redacting. False positives are possible — use `# credactor:ignore` or `.credactorignore` to suppress them.
65
+
66
+ ```bash
67
+ # Scan current directory (dry run)
68
+ credactor --dry-run .
69
+
70
+ # Scan and interactively redact
71
+ credactor .
72
+
73
+ # Redact everything without prompting
74
+ credactor --fix-all .
75
+
76
+ # CI mode — exit 1 on findings
77
+ credactor --ci .
78
+ ```
79
+
80
+ ### Pre-commit Hook
81
+
82
+ ```yaml
83
+ # .pre-commit-config.yaml
84
+ repos:
85
+ - repo: https://github.com/rxb06/Credactor
86
+ rev: v2.3.3
87
+ hooks:
88
+ - id: credactor
89
+ ```
90
+
91
+ Or run as a module:
92
+
93
+ ```bash
94
+ python -m credactor .
95
+ ```
96
+
97
+ ## Detection
98
+
99
+ | Category | Examples | Severity |
100
+ |---|---|---|
101
+ | Cloud provider keys | AWS (`AKIA...`), GCP (`AIza...`), Stripe (`sk_live_...`), Slack (`xoxb-...`) | Critical |
102
+ | Platform tokens | GitHub (`ghp_`, `github_pat_`), GitLab (`glpat-`), npm (`npm_`), PyPI (`pypi-`) | Critical |
103
+ | Private keys | PEM blocks (`-----BEGIN RSA PRIVATE KEY-----`) | Critical |
104
+ | JWT tokens | `eyJ...` three-segment tokens | High |
105
+ | Connection strings | `postgresql://user:pass@host`, `mongodb+srv://...`, `redis://...` | High |
106
+ | Variable assignments | `password = "..."`, `api_key = "..."`, `db_password = "..."` | High/Medium |
107
+ | XML attributes | `<add key="Password" value="..." />` | High |
108
+ | High-entropy strings | Hex (32-64 chars), Base64 (60+ chars) | Medium/Low |
109
+
110
+ ## Features
111
+
112
+ - Entropy-based detection with per-pattern thresholds to cut false positives
113
+ - Interactive or batch redaction — review one-by-one, or `--fix-all`
114
+ - Language-aware replacements (`os.environ`, `process.env`, `System.getenv`, etc.)
115
+ - Git history scanning via `--scan-history`
116
+ - `.bak` backups before any file modification
117
+ - Inline `# credactor:ignore` suppression and `.credactorignore` allowlists
118
+ - Per-repo config via `.credactor.toml`
119
+ - Parallel scanning (8 workers) for large repos
120
+ - SARIF 2.1.0 output with column-level annotations for GitHub Code Scanning
121
+ - `--fail-on-error` to catch files that couldn't be scanned
122
+
123
+ ## Scanned File Types
124
+
125
+ `.py` `.js` `.ts` `.jsx` `.tsx` `.sh` `.bash` `.env` `.env.*` `.cfg` `.ini` `.toml` `.yaml` `.yml` `.rb` `.go` `.java` `.php` `.cs` `.kt` `.tf` `.hcl` `.conf` `.properties` `.xml`
126
+
127
+ JSON files are excluded by default (high false-positive rate from API responses). Use `--scan-json` to include them.
128
+
129
+ ## Exit Codes
130
+
131
+ | Code | Meaning |
132
+ |---|---|
133
+ | `0` | No findings, or all resolved |
134
+ | `1` | Unresolved findings |
135
+ | `2` | Error, or files skipped with `--fail-on-error` |
136
+
137
+ ## Docs
138
+
139
+ | Document | Description |
140
+ |----------|-------------|
141
+ | [Setup Guide](docs/setup.md) | Installation, configuration, CI/CD integration |
142
+ | [User Guide](docs/user-guide.md) | CLI reference, replacement modes, backup safety |
143
+ | [Examples](docs/examples.md) | Common workflows with output |
144
+ | [Integration](docs/integration.md) | Pre-commit hooks, CI pipelines |
145
+ | [Security](docs/security.md) | Threat model, hardening measures, known limitations |
146
+ | [Changelog](CHANGELOG.md) | Version history |
147
+ | [Contributing](CONTRIBUTING.md) | Development setup, code style, PR process |
148
+ | [Disclaimer](docs/DISCLAIMER.md) | Limitations, safe usage, warranty |
149
+
150
+ ## Licence
151
+
152
+ Apache 2.0. See [LICENSE](LICENSE).
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "credactor"
7
- version = "2.3.2"
7
+ version = "2.3.3"
8
8
  description = "Scan and redact hardcoded credentials in source code"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"