Repository: gitguardian/ggshield
Issue: ggshield fails with long paths

## Environment

- ggshield version: 1.13.5
- Operating system (Linux, macOS, Windows): any
- Operating system version: any
- Python version: 3.8.10

## Describe the bug

When scanning a file whose path is longer than 255, ggshield fails.

Steps to reproduce:

1. Create a long file. Can be done with:
   ```
   mkdir tmp  # use a dir because Python does not want to create a file longer than 255 chars
   python -c 'open("tmp/" + "l" * 255, "w").write("foo")'
   ```
3. Run command `ggshield secret scan path tmp/l*`

Actual result:

```
Scanning Path... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 1 files scanned out of 1 0:00:00
Error: Error scanning, network error occurred: {0: {'filename': ['Longer than maximum length 256.']}}
```

Expected result: Scan should succeed

Changed files:
ggshield/scan/scannable.py, tests/functional/secret/test_scan_path.py

diff --git a/ggshield/scan/scannable.py b/ggshield/scan/scannable.py
index f30bd12..b7f4a76 100644
--- a/ggshield/scan/scannable.py
+++ b/ggshield/scan/scannable.py
@@ -33,6 +33,9 @@ logger = logging.getLogger(__name__)
 
 _RX_HEADER_LINE_SEPARATOR = re.compile("[\\n\\0]:", re.MULTILINE)
 
+# GitGuardian API does not accept paths longer than this
+_API_PATH_MAX_LENGTH = 256
+
 
 def _parse_patch_header_line(line: str) -> Tuple[str, Filemode]:
     """
@@ -313,7 +316,10 @@ class Scanner:
         Sends a chunk of files to scan to the API
         """
         # `documents` is a version of `chunk` suitable for `GGClient.multi_content_scan()`
-        documents = [{"document": x.document, "filename": x.filename} for x in chunk]
+        documents = [
+            {"document": x.document, "filename": x.filename[-_API_PATH_MAX_LENGTH:]}
+            for x in chunk
+        ]
         return executor.submit(
             self.client.multi_content_scan,
             documents,
diff --git a/tests/functional/secret/test_scan_path.py b/tests/functional/secret/test_scan_path.py
index 0d89484..5633f9f 100644
--- a/tests/functional/secret/test_scan_path.py
+++ b/tests/functional/secret/test_scan_path.py
@@ -1,7 +1,7 @@
 from pathlib import Path
 
 from tests.conftest import GG_VALID_TOKEN
-from tests.functional.utils import run_ggshield_scan
+from tests.functional.utils import recreate_censored_content, run_ggshield_scan
 
 
 def test_scan_path(tmp_path: Path) -> None:
@@ -10,3 +10,20 @@ def test_scan_path(tmp_path: Path) -> None:
 
     result = run_ggshield_scan("path", str(test_file), cwd=tmp_path, expected_code=1)
     assert "SECRET=" in result.stdout
+
+
+def test_scan_path_does_not_fail_on_long_paths(tmp_path: Path) -> None:
+    # GIVEN a secret stored in a file whose path is longer than 256 characters
+    secret_content = f"SECRET='{GG_VALID_TOKEN}'"
+
+    # Create the file in a subdir because filenames cannot be longer than 255
+    # characters. What we care here is the length of the path.
+    test_file = tmp_path / ("d" * 255) / ("f" * 255)
+    test_file.parent.mkdir()
+    test_file.write_text(secret_content)
+
+    # WHEN ggshield scans it
+    result = run_ggshield_scan("path", str(test_file), cwd=tmp_path, expected_code=1)
+
+    # THEN it finds the secret in it
+    assert recreate_censored_content(secret_content, GG_VALID_TOKEN) in result.stdout