leftblock 0.3.4__tar.gz → 0.3.5__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 (26) hide show
  1. {leftblock-0.3.4 → leftblock-0.3.5}/PKG-INFO +2 -2
  2. {leftblock-0.3.4 → leftblock-0.3.5}/README.md +1 -1
  3. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/cli.py +37 -3
  4. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/PKG-INFO +2 -2
  5. {leftblock-0.3.4 → leftblock-0.3.5}/pyproject.toml +1 -1
  6. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_branding.py +2 -2
  7. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_recorded_overrides.py +11 -1
  8. {leftblock-0.3.4 → leftblock-0.3.5}/LICENSE +0 -0
  9. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/__init__.py +0 -0
  10. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/allow.py +0 -0
  11. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/core.py +0 -0
  12. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/data/gitleaks.toml +0 -0
  13. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/hooks.py +0 -0
  14. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock/merge.py +0 -0
  15. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/SOURCES.txt +0 -0
  16. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/dependency_links.txt +0 -0
  17. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/entry_points.txt +0 -0
  18. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/requires.txt +0 -0
  19. {leftblock-0.3.4 → leftblock-0.3.5}/leftblock.egg-info/top_level.txt +0 -0
  20. {leftblock-0.3.4 → leftblock-0.3.5}/setup.cfg +0 -0
  21. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_commit_gate.py +0 -0
  22. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_default_config.py +0 -0
  23. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_false_positives.py +0 -0
  24. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_install.py +0 -0
  25. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_local_install.py +0 -0
  26. {leftblock-0.3.4 → leftblock-0.3.5}/tests/test_sensitive_rules.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leftblock
3
- Version: 0.3.4
3
+ Version: 0.3.5
4
4
  Summary: LeftBlock: a pluggable inspection gate for Git commits
5
5
  License: MIT License
6
6
 
@@ -124,7 +124,7 @@ configures the integration; it does not install scanner binaries.
124
124
  In the intended Python environment:
125
125
 
126
126
  ```bash
127
- python -m pip install leftblock==0.3.4
127
+ python -m pip install leftblock==0.3.5
128
128
  python -m leftblock.cli --help
129
129
  ```
130
130
 
@@ -91,7 +91,7 @@ configures the integration; it does not install scanner binaries.
91
91
  In the intended Python environment:
92
92
 
93
93
  ```bash
94
- python -m pip install leftblock==0.3.4
94
+ python -m pip install leftblock==0.3.5
95
95
  python -m leftblock.cli --help
96
96
  ```
97
97
 
@@ -5,6 +5,7 @@ import json
5
5
  import subprocess
6
6
  import getpass
7
7
  import shlex
8
+ import shutil
8
9
  import yaml
9
10
  from datetime import datetime, timezone
10
11
  from leftblock.merge import (
@@ -193,12 +194,45 @@ def _run_configured_checks(repo_root, config_path=None):
193
194
  os.remove(scoped_index)
194
195
 
195
196
 
197
+ def _plain(text):
198
+ """Printable ASCII as-is; anything else JSON-escaped so it cannot drive the terminal."""
199
+ text = str(text)
200
+ if text.isascii() and text.isprintable():
201
+ return text
202
+ return json.dumps(text, ensure_ascii=True)
203
+
204
+
205
+ def command_prefix():
206
+ """How to invoke this LeftBlock in printed advice, without leaking a home path.
207
+
208
+ Uses `leftblock` when that name on PATH runs this same installation;
209
+ otherwise this interpreter with the home directory shortened to `~`.
210
+ """
211
+ here = os.path.dirname(os.path.abspath(sys.executable))
212
+ found = shutil.which("leftblock")
213
+ if found and os.path.dirname(os.path.realpath(found)) in (here, os.path.realpath(here)):
214
+ return "leftblock"
215
+ return shell_path(sys.executable) + " -I -B -m leftblock.cli"
216
+
217
+
218
+ def shell_path(path):
219
+ """A shell-quoted path with the home directory shown as `~`."""
220
+ path = os.path.abspath(path)
221
+ home = os.path.expanduser("~")
222
+ if home and path.startswith(home + os.sep):
223
+ return "~/" + shlex.quote(path[len(home) + 1:])
224
+ return shlex.quote(path)
225
+
226
+
196
227
  def print_failures(failures):
197
228
  for result in failures:
198
229
  print_warn(f"Checker {json.dumps(str(result.name))} did not pass.")
199
230
  if isinstance(result.findings, list):
200
231
  for finding in result.findings:
201
- print(" " + json.dumps(finding, ensure_ascii=True), file=sys.stderr)
232
+ line = f"{_plain(finding.get('File', 'unknown file'))}: {_plain(finding.get('RuleID', 'finding'))}"
233
+ if finding.get("id"):
234
+ line += f" [id {finding['id']}]"
235
+ print(" " + line, file=sys.stderr)
202
236
  else:
203
237
  print_warn(str(result.findings))
204
238
 
@@ -248,10 +282,10 @@ def print_override_instructions(failures, repo_root, config_path):
248
282
  if findings:
249
283
  steps.append("remove the flagged content")
250
284
  if ids:
251
- command = f"{shlex.quote(sys.executable)} -I -B -m leftblock.cli allow {' '.join(dict.fromkeys(ids))}"
285
+ command = f"{command_prefix()} allow {' '.join(dict.fromkeys(ids))}"
252
286
  default = default_local_policy(repo_root) or os.path.join(repo_root, ".leftblock.yml")
253
287
  if config_path and os.path.abspath(config_path) != os.path.abspath(default):
254
- command += f" --config {shlex.quote(config_path)}"
288
+ command += f" --config {shell_path(config_path)}"
255
289
  command += ' --reason "<why this is not sensitive>"'
256
290
  print_info(
257
291
  "An override adds the finding to .leftblock-allow.yml and stages it, so it "
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leftblock
3
- Version: 0.3.4
3
+ Version: 0.3.5
4
4
  Summary: LeftBlock: a pluggable inspection gate for Git commits
5
5
  License: MIT License
6
6
 
@@ -124,7 +124,7 @@ configures the integration; it does not install scanner binaries.
124
124
  In the intended Python environment:
125
125
 
126
126
  ```bash
127
- python -m pip install leftblock==0.3.4
127
+ python -m pip install leftblock==0.3.5
128
128
  python -m leftblock.cli --help
129
129
  ```
130
130
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "leftblock"
7
- version = "0.3.4"
7
+ version = "0.3.5"
8
8
  description = "LeftBlock: a pluggable inspection gate for Git commits"
9
9
  readme = "README.md"
10
10
  license = {file = "LICENSE"}
@@ -196,7 +196,7 @@ class DistributionOwnershipTests(unittest.TestCase):
196
196
 
197
197
  def test_distribution_owns_only_leftblock_command(self):
198
198
  self.assertIn("\nName: leftblock\n", "\n" + self.metadata)
199
- self.assertIn("\nVersion: 0.3.4\n", "\n" + self.metadata)
199
+ self.assertIn("\nVersion: 0.3.5\n", "\n" + self.metadata)
200
200
  self.assertIn("\nLicense-File: LICENSE\n", "\n" + self.metadata)
201
201
  self.assertEqual(dict(self.entry_points["console_scripts"]), {"leftblock": "leftblock.cli:main"})
202
202
 
@@ -208,7 +208,7 @@ class DistributionOwnershipTests(unittest.TestCase):
208
208
  self.assertIn(name, self.names)
209
209
  self.assertEqual(
210
210
  {name.split("/")[0] for name in self.names},
211
- {"leftblock", "leftblock-0.3.4.dist-info"},
211
+ {"leftblock", "leftblock-0.3.5.dist-info"},
212
212
  )
213
213
  self.assertEqual(self.rules, (PROJECT_ROOT / "leftblock/data/gitleaks.toml").read_bytes())
214
214
  self.assertEqual(self.license, (PROJECT_ROOT / "LICENSE").read_bytes())
@@ -31,7 +31,8 @@ class RecordedOverrideTests(RepositoryFixture):
31
31
  return self.leftblock("check", "--config", str(policy))
32
32
 
33
33
  def ids(self, proc):
34
- return re.findall(r'"id": "([0-9a-f]{16})"', proc.stderr)
34
+ # Per-finding detail lines (the final summary line repeats the ids).
35
+ return re.findall(r"^ .*\[id ([0-9a-f]{16})\]$", proc.stderr, re.MULTILINE)
35
36
 
36
37
  def blocked_id(self, text=None):
37
38
  self.write_stage(text or f"a\nContact: {EMAIL}\n")
@@ -251,3 +252,12 @@ class OverrideNeverCoversErrorsTests(RepositoryFixture):
251
252
 
252
253
  if __name__ == "__main__":
253
254
  unittest.main()
255
+
256
+
257
+ class CommandPrefixTests(unittest.TestCase):
258
+ def test_printed_command_never_contains_the_home_directory(self):
259
+ import os
260
+ from leftblock import cli
261
+ home = os.path.expanduser("~")
262
+ for prefix in (cli.command_prefix(), cli.shell_path(os.path.join(home, "x", "policy.json"))):
263
+ self.assertNotIn(home + os.sep, prefix)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes