@@ -312,13 +312,21 @@ def clip(text: str, keep_around: str = "", limit: int = MAX_LINE_CHARS) -> str:
312312 return text [:limit ] + "…"
313313
314314
315- def build_evidence (repo : str , token : str , findings : list [dict ]):
315+ def build_evidence (repo : str , token : str , findings : list [dict ],
316+ mask_also : list [dict ] = ()):
316317 """Turn scanner findings into redacted windows. Returns (evidence, errors).
317318
318- Any error fails the gate: an unreadable window is an unjudged detection.
319+ `mask_also` holds detections past the triage cap: they get no window, but
320+ are blanked wherever they fall inside one. Any error fails the gate: an
321+ unreadable window is an unjudged detection.
319322 """
320323 evidence , errors = [], []
321324
325+ masks : dict [tuple [str , str ], dict [int , dict ]] = {}
326+ for f in [* findings , * mask_also ]:
327+ if f ["location_kind" ] != "archive" :
328+ masks .setdefault ((f ["blob_sha" ], f ["file" ]), {})[f ["id" ]] = f
329+
322330 # Grouped by (blob, path) so identical files each get their own markers;
323331 # fetched once per blob.
324332 by_path : dict [tuple [str , str ], list [dict ]] = {}
@@ -331,7 +339,7 @@ def build_evidence(repo: str, token: str, findings: list[dict]):
331339 by_path .setdefault ((f ["blob_sha" ], f ["file" ]), []).append (f )
332340
333341 blobs : dict [str , tuple [bytes | None , str ]] = {}
334- for (blob_sha , _path ), group in by_path .items ():
342+ for (blob_sha , path ), group in by_path .items ():
335343 if blob_sha not in blobs :
336344 blobs [blob_sha ] = fetch_blob (repo , blob_sha , token , MAX_BLOB_BYTES )
337345 raw , reason = blobs [blob_sha ]
@@ -343,8 +351,8 @@ def build_evidence(repo: str, token: str, findings: list[dict]):
343351 # Split on b"\n" only, to match the scanner's line numbers; decode
344352 # after masking.
345353 lines = raw .split (b"\n " )
346- masked = [ m . decode ( "utf-8" , "replace" )
347- for m in mask_detections (lines , group )]
354+ in_file = list ( masks [( blob_sha , path )]. values () )
355+ masked = [ m . decode ( "utf-8" , "replace" ) for m in mask_detections (lines , in_file )]
348356
349357 for f in group :
350358 if f ["location_kind" ] == "path" :
@@ -684,7 +692,8 @@ def render_comment(review, scan_conclusion, blocked, note=""):
684692 findings = review ["findings" ]
685693 if not findings :
686694 # No green tick under a red banner.
687- clean = not (review ["injection" ] or review ["unanswered" ] or blocked )
695+ clean = not (review ["injection" ] or review ["unanswered" ] or blocked
696+ or scan_conclusion == "failure" )
688697 L += ["✅ No secrets in the changed files." if clean
689698 else "No secrets among the detections that *were* triaged." , "" ]
690699 for f in findings :
@@ -804,7 +813,7 @@ def main() -> int:
804813 else :
805814 # Runs even when `blocked`: the status stays red, but reviewers still
806815 # need verdicts on what was scanned.
807- evidence , errors = build_evidence (repo , gh_token , findings )
816+ evidence , errors = build_evidence (repo , gh_token , findings , scan [ "findings" ] )
808817 if errors :
809818 blocked = blocked or f"{ len (errors )} detection(s) could not be read"
810819 for e in errors [:10 ]:
0 commit comments