Skip to content

Commit a608ca8

Browse files
authored
Merge pull request #1083 from GitGuardian/salomevoltz/scrt-5438-ggshield-for-each-detected-secret-add-a-link-towards-our
feat: Add extra scan results information
2 parents 39b6564 + 8ac31b6 commit a608ca8

38 files changed

+938
-1686
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<!--
2+
A new scriv changelog fragment.
3+
4+
Uncomment the section that is right (remove the HTML comment wrapper).
5+
-->
6+
7+
<!--
8+
### Removed
9+
10+
- A bullet item for the Removed category.
11+
12+
-->
13+
14+
### Added
15+
16+
- `ggshield secret scan` output now contains a link to the detector documentation for each secret found.
17+
18+
<!--
19+
### Changed
20+
21+
- A bullet item for the Changed category.
22+
23+
-->
24+
<!--
25+
### Deprecated
26+
27+
- A bullet item for the Deprecated category.
28+
29+
-->
30+
<!--
31+
### Fixed
32+
33+
- A bullet item for the Fixed category.
34+
35+
-->
36+
<!--
37+
### Security
38+
39+
- A bullet item for the Security category.
40+
41+
-->

ggshield/verticals/secret/output/schemas.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class FlattenedPolicyBreak(BaseSchema):
1414
policy = fields.String(required=True)
1515
occurrences = fields.List(fields.Nested(ExtendedMatchSchema), required=True)
1616
detector = fields.String(data_key="type", required=True)
17+
detector_documentation = fields.String(required=False, allow_none=True)
1718
validity = fields.String(required=False, allow_none=True)
1819
ignore_sha = fields.String(required=True)
1920
total_occurrences = fields.Integer(required=True)

ggshield/verticals/secret/output/secret_gitlab_webui_output_handler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def format_secret(secret: Secret) -> str:
1717
f'{x.match_type}: "{censor_match(x)}"' for x in secret.matches
1818
)
1919
validity = translate_validity(secret.validity)
20-
return f"{secret.detector} (Validity: {validity}, {match_str})"
20+
return f"{secret.detector_display_name} (Validity: {validity}, {match_str})"
2121

2222

2323
class SecretGitLabWebUIOutputHandler(SecretOutputHandler):

ggshield/verticals/secret/output/secret_json_output_handler.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,13 @@ def serialized_secret(
118118
"occurrences": [],
119119
"ignore_sha": ignore_sha,
120120
"policy": secrets[0].policy,
121-
"detector": secrets[0].detector,
121+
"detector": secrets[0].detector_display_name,
122122
"total_occurrences": len(secrets),
123123
}
124124

125+
if secrets[0].documentation_url:
126+
flattened_dict["detector_documentation"] = secrets[0].documentation_url
127+
125128
if secrets[0].validity:
126129
flattened_dict["validity"] = secrets[0].validity
127130

ggshield/verticals/secret/output/secret_sarif_output_handler.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,18 @@ def _create_sarif_result_dict(
7676
f"- [{m.match_type}]({id})" for id, m in enumerate(secret.matches)
7777
)
7878
extended_matches = cast(List[ExtendedMatch], secret.matches)
79-
message = f"Secret detected: {secret.detector}.\nMatches: {matches_str}"
80-
markdown_message = f"Secret detected: {secret.detector}\nMatches:\n{matches_li}"
79+
message = (
80+
f"Secret detected: {secret.detector_display_name}.\nMatches: {matches_str}"
81+
)
82+
if secret.documentation_url:
83+
markdown_message = f"Secret detected: [{secret.detector_display_name}]({secret.documentation_url})"
84+
else:
85+
markdown_message = f"Secret detected: {secret.detector_display_name}"
86+
markdown_message += f"\nMatches:\n{matches_li}"
8187

8288
# Create dict
8389
dct = {
84-
"ruleId": secret.detector,
90+
"ruleId": secret.detector_display_name,
8591
"level": "error",
8692
"message": {
8793
"text": message,

ggshield/verticals/secret/output/secret_text_output_handler.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ def secret_header(
297297
)
298298

299299
start_line = format_text(">>", STYLE["detector_line_start"])
300-
secret_type = format_text(secret.detector, STYLE["secret_type"])
300+
secret_type = format_text(secret.detector_display_name, STYLE["secret_type"])
301301
number_occurrences = format_text(str(len(secrets)), STYLE["occurrence_count"])
302302
ignore_sha = format_text(ignore_sha, STYLE["ignore_sha"])
303303

@@ -308,6 +308,8 @@ def secret_header(
308308
{indent}Incident URL: {secrets[0].incident_url if known_secret and secret.incident_url else "N/A"}
309309
{indent}Secret SHA: {ignore_sha}
310310
"""
311+
if secret.documentation_url is not None:
312+
message += f"{indent}Detector documentation: {secret.documentation_url}\n"
311313
if secret.ignore_reason is not None:
312314
message += f"{indent}Ignored: {secret.ignore_reason.to_human_readable()}\n"
313315

ggshield/verticals/secret/secret_scan_collection.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ class Secret:
8383
Named Secret since we are dropping other kind of policy breaks.
8484
"""
8585

86-
detector: str
86+
detector_display_name: str
87+
detector_name: str
88+
detector_group_name: str
89+
documentation_url: Optional[str]
8790
validity: str
8891
known_secret: bool
8992
incident_url: Optional[str]
@@ -186,7 +189,10 @@ def from_scan_result(
186189
validity=policy_break.validity,
187190
known_secret=policy_break.known_secret,
188191
incident_url=policy_break.incident_url,
189-
detector=policy_break.break_type,
192+
detector_display_name=policy_break.break_type,
193+
detector_name=policy_break.detector_name,
194+
detector_group_name=policy_break.detector_group_name,
195+
documentation_url=policy_break.documentation_url,
190196
matches=[
191197
ExtendedMatch.from_match(match, lines, result.is_on_patch)
192198
for match in policy_break.matches

ggshield/verticals/secret/secret_scanner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ def _collect_results(
216216
result = Result.from_scan_result(file, scan_result, self.secret_config)
217217
for secret in result.secrets:
218218
self.cache.add_found_policy_break(
219-
secret.detector,
219+
secret.detector_display_name,
220220
secret.get_ignore_sha(),
221221
file.filename,
222222
)

pdm.lock

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ dependencies = [
4141
"marshmallow~=3.18.0",
4242
"marshmallow-dataclass~=8.5.8",
4343
"oauthlib~=3.2.1",
44-
"pygitguardian~=1.20.0",
44+
"pygitguardian @ git+https://github.com/GitGuardian/py-gitguardian.git@933318c6a3fc7a5cce1fdbb663b4e90a2b7992a2",
4545
"pyjwt~=2.6.0",
4646
"python-dotenv~=0.21.0",
4747
"pyyaml~=6.0.1",

0 commit comments

Comments
 (0)