secretshield 0.7.0__tar.gz → 0.7.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.
Files changed (54) hide show
  1. {secretshield-0.7.0/secretshield.egg-info → secretshield-0.7.1}/PKG-INFO +2 -2
  2. {secretshield-0.7.0 → secretshield-0.7.1}/README.md +1 -1
  3. {secretshield-0.7.0 → secretshield-0.7.1}/pyproject.toml +1 -1
  4. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/__init__.py +1 -1
  5. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/cli.py +10 -4
  6. {secretshield-0.7.0 → secretshield-0.7.1/secretshield.egg-info}/PKG-INFO +2 -2
  7. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_custom_rules_cli_integration.py +54 -1
  8. {secretshield-0.7.0 → secretshield-0.7.1}/LICENSE +0 -0
  9. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/__init__.py +0 -0
  10. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/env.py +0 -0
  11. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/fixer.py +0 -0
  12. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/gitignore.py +0 -0
  13. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/javascript.py +0 -0
  14. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/autofix/python.py +0 -0
  15. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/baseline.py +0 -0
  16. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/color.py +0 -0
  17. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/config.py +0 -0
  18. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/custom_rules.py +0 -0
  19. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/detector.py +0 -0
  20. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/git/__init__.py +0 -0
  21. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/git/hooks.py +0 -0
  22. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/github/__init__.py +0 -0
  23. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/github/actions.py +0 -0
  24. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/guardian.py +0 -0
  25. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/ignorefile.py +0 -0
  26. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/notifications.py +0 -0
  27. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/patterns.py +0 -0
  28. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/project_config.py +0 -0
  29. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield/redactor.py +0 -0
  30. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield.egg-info/SOURCES.txt +0 -0
  31. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield.egg-info/dependency_links.txt +0 -0
  32. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield.egg-info/entry_points.txt +0 -0
  33. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield.egg-info/requires.txt +0 -0
  34. {secretshield-0.7.0 → secretshield-0.7.1}/secretshield.egg-info/top_level.txt +0 -0
  35. {secretshield-0.7.0 → secretshield-0.7.1}/setup.cfg +0 -0
  36. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_autofix.py +0 -0
  37. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_baseline.py +0 -0
  38. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_color.py +0 -0
  39. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_color_cli_integration.py +0 -0
  40. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_custom_rules.py +0 -0
  41. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_detector.py +0 -0
  42. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_git_hooks.py +0 -0
  43. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_github_action.py +0 -0
  44. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_ignorefile.py +0 -0
  45. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_ignorefile_cli_integration.py +0 -0
  46. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_javascript_autofix.py +0 -0
  47. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_logging.py +0 -0
  48. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_project_config.py +0 -0
  49. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_redactor.py +0 -0
  50. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_scan.py +0 -0
  51. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_ss_alias_and_creator.py +0 -0
  52. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_stdout.py +0 -0
  53. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_v030_cli_integration.py +0 -0
  54. {secretshield-0.7.0 → secretshield-0.7.1}/tests/test_v040_cli_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: secretshield
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Stop secrets before they leak -- runtime redaction, multi-language scanning, auto-fix, Git hooks, and CI, all in one CLI.
5
5
  Author: Samarth Chugh (Sam3360)
6
6
  License-Expression: MIT
@@ -32,7 +32,7 @@ Dynamic: license-file
32
32
 
33
33
  [![PyPI version](https://img.shields.io/pypi/v/secretshield?color=blue)](https://pypi.org/project/secretshield/)
34
34
  [![Python versions](https://img.shields.io/pypi/pyversions/secretshield)](https://pypi.org/project/secretshield/)
35
- [![PyPI downloads](https://img.shields.io/pypi/dm/secretshield)](https://pypi.org/project/secretshield/)
35
+ [![PyPI Downloads](https://api.pepy.tech/badge/secretshield/month)](https://pypi.org/project/secretshield/)
36
36
  [![License: MIT](https://img.shields.io/pypi/l/secretshield)](LICENSE)
37
37
 
38
38
  [Install](#install) · [Demo](#demo) · [Try it](#try-it) · [Full usage guide →](https://github.com/Sam3360/secretshield/blob/main/USAGE.md)
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![PyPI version](https://img.shields.io/pypi/v/secretshield?color=blue)](https://pypi.org/project/secretshield/)
8
8
  [![Python versions](https://img.shields.io/pypi/pyversions/secretshield)](https://pypi.org/project/secretshield/)
9
- [![PyPI downloads](https://img.shields.io/pypi/dm/secretshield)](https://pypi.org/project/secretshield/)
9
+ [![PyPI Downloads](https://api.pepy.tech/badge/secretshield/month)](https://pypi.org/project/secretshield/)
10
10
  [![License: MIT](https://img.shields.io/pypi/l/secretshield)](LICENSE)
11
11
 
12
12
  [Install](#install) · [Demo](#demo) · [Try it](#try-it) · [Full usage guide →](https://github.com/Sam3360/secretshield/blob/main/USAGE.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "secretshield"
7
- version = "0.7.0"
7
+ version = "0.7.1"
8
8
  description = "Stop secrets before they leak -- runtime redaction, multi-language scanning, auto-fix, Git hooks, and CI, all in one CLI."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -23,7 +23,7 @@ from .detector import Match, detect
23
23
  from .guardian import disable, enable, is_enabled
24
24
  from .redactor import redact
25
25
 
26
- __version__ = "0.7.0"
26
+ __version__ = "0.7.1"
27
27
 
28
28
  __all__ = [
29
29
  "__version__",
@@ -168,6 +168,12 @@ _KIND_DISPLAY: dict[str, tuple[str, str]] = {
168
168
  }
169
169
 
170
170
 
171
+ def _plural(count: int, word: str) -> str:
172
+ """`f"{count} {word}"`, pluralized properly -- "1 rule" / "2 rules" --
173
+ instead of the awkward literal "rule(s)" regardless of count."""
174
+ return f"{count} {word}" if count == 1 else f"{count} {word}s"
175
+
176
+
171
177
  def _kind_display(kind: str) -> tuple[str, str]:
172
178
  return _KIND_DISPLAY.get(kind, (kind, "possible secret"))
173
179
 
@@ -437,8 +443,8 @@ def _run_scan(args: argparse.Namespace) -> int:
437
443
  custom_rules, custom_rule_errors = load_custom_rules(Path.cwd())
438
444
  if custom_rule_errors:
439
445
  print(
440
- f"secretshield: warning: {len(custom_rule_errors)} invalid custom "
441
- f"rule(s) in .secretshield-rules.toml -- run `secretshield rules "
446
+ f"secretshield: warning: {_plural(len(custom_rule_errors), 'invalid custom rule')} "
447
+ f"in .secretshield-rules.toml -- run `secretshield rules "
442
448
  f"check` for details.",
443
449
  file=sys.stderr,
444
450
  )
@@ -787,7 +793,7 @@ def _cmd_rules_check(args: argparse.Namespace) -> int:
787
793
  return 1
788
794
 
789
795
  print(f"{green(chr(0x2713), use_color)} {path.name}")
790
- print(f"{green(chr(0x2713), use_color)} {len(rules)} rule(s) loaded")
796
+ print(f"{green(chr(0x2713), use_color)} {_plural(len(rules), 'rule')} loaded")
791
797
  print(f"{green(chr(0x2713), use_color)} All patterns are valid")
792
798
  return 0
793
799
 
@@ -815,7 +821,7 @@ def _cmd_rules_list(args: argparse.Namespace) -> int:
815
821
  if errors:
816
822
  use_color = supports_color(sys.stdout)
817
823
  print(
818
- f"\n{red(chr(0x2717), use_color)} {len(errors)} rule(s) failed to load "
824
+ f"\n{red(chr(0x2717), use_color)} {_plural(len(errors), 'rule')} failed to load "
819
825
  f"-- run `secretshield rules check` for details."
820
826
  )
821
827
  return 0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: secretshield
3
- Version: 0.7.0
3
+ Version: 0.7.1
4
4
  Summary: Stop secrets before they leak -- runtime redaction, multi-language scanning, auto-fix, Git hooks, and CI, all in one CLI.
5
5
  Author: Samarth Chugh (Sam3360)
6
6
  License-Expression: MIT
@@ -32,7 +32,7 @@ Dynamic: license-file
32
32
 
33
33
  [![PyPI version](https://img.shields.io/pypi/v/secretshield?color=blue)](https://pypi.org/project/secretshield/)
34
34
  [![Python versions](https://img.shields.io/pypi/pyversions/secretshield)](https://pypi.org/project/secretshield/)
35
- [![PyPI downloads](https://img.shields.io/pypi/dm/secretshield)](https://pypi.org/project/secretshield/)
35
+ [![PyPI Downloads](https://api.pepy.tech/badge/secretshield/month)](https://pypi.org/project/secretshield/)
36
36
  [![License: MIT](https://img.shields.io/pypi/l/secretshield)](LICENSE)
37
37
 
38
38
  [Install](#install) · [Demo](#demo) · [Try it](#try-it) · [Full usage guide →](https://github.com/Sam3360/secretshield/blob/main/USAGE.md)
@@ -129,10 +129,63 @@ def test_rules_check_success(tmp_path, monkeypatch, capsys):
129
129
  exit_code = main(["rules", "check"])
130
130
  assert exit_code == 0
131
131
  out = capsys.readouterr().out
132
- assert "2 rule(s) loaded" in out
132
+ assert "2 rules loaded" in out
133
133
  assert "All patterns are valid" in out
134
134
 
135
135
 
136
+ # --- Regression tests: singular/plural grammar in rule-count output --------
137
+ # (0.7.1: these counts used to always print the literal "rule(s)"
138
+ # regardless of count, e.g. "1 rule(s) loaded" -- fixed to pluralize
139
+ # properly.)
140
+
141
+
142
+ def test_rules_check_singular_grammar(tmp_path, monkeypatch, capsys):
143
+ monkeypatch.chdir(tmp_path)
144
+ (tmp_path / ".secretshield-rules.toml").write_text(
145
+ '[[rules]]\nname = "Only One"\npattern = "ONE_[0-9]{4}"\n'
146
+ )
147
+ main(["rules", "check"])
148
+ out = capsys.readouterr().out
149
+ assert "1 rule loaded" in out
150
+ assert "rule(s)" not in out
151
+
152
+
153
+ def test_rules_check_plural_grammar(tmp_path, monkeypatch, capsys):
154
+ monkeypatch.chdir(tmp_path)
155
+ (tmp_path / ".secretshield-rules.toml").write_text(
156
+ '[[rules]]\nname = "A"\npattern = "AAA_[0-9]{4}"\n'
157
+ '[[rules]]\nname = "B"\npattern = "BBB_[0-9]{4}"\n'
158
+ '[[rules]]\nname = "C"\npattern = "CCC_[0-9]{4}"\n'
159
+ )
160
+ main(["rules", "check"])
161
+ out = capsys.readouterr().out
162
+ assert "3 rules loaded" in out
163
+ assert "rule(s)" not in out
164
+
165
+
166
+ def test_rules_list_singular_error_grammar(tmp_path, monkeypatch, capsys):
167
+ monkeypatch.chdir(tmp_path)
168
+ (tmp_path / ".secretshield-rules.toml").write_text(
169
+ '[[rules]]\nname = "Broken"\npattern = "["\n'
170
+ )
171
+ main(["rules"])
172
+ out = capsys.readouterr().out
173
+ assert "1 rule failed to load" in out
174
+ assert "rule(s)" not in out
175
+
176
+
177
+ def test_scan_warning_singular_grammar(tmp_path, monkeypatch, capsys):
178
+ monkeypatch.chdir(tmp_path)
179
+ (tmp_path / ".secretshield-rules.toml").write_text(
180
+ '[[rules]]\nname = "Broken"\npattern = "["\n'
181
+ )
182
+ (tmp_path / "clean.py").write_text("print('hello')\n")
183
+ main(["scan", "."])
184
+ err = capsys.readouterr().err
185
+ assert "1 invalid custom rule in" in err
186
+ assert "rule(s)" not in err
187
+
188
+
136
189
  def test_rules_check_reports_errors(tmp_path, monkeypatch, capsys):
137
190
  monkeypatch.chdir(tmp_path)
138
191
  (tmp_path / ".secretshield-rules.toml").write_text(
File without changes
File without changes