You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tooling.apache.org by ak...@apache.org on 2026/05/05 10:53:26 UTC

(tooling-agents) branch main updated: Critical redaction

This is an automated email from the ASF dual-hosted git repository.

andrewmusselman pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-agents.git


The following commit(s) were added to refs/heads/main by this push:
     new 5061ae9  Critical redaction
5061ae9 is described below

commit 5061ae9798f5edbefa86b30afad04aa092d4b9b8
Author: Andrew Musselman <an...@gmail.com>
AuthorDate: Tue May 5 03:53:14 2026 -0700

    Critical redaction
---
 ASVS/agents/asvs_orchestrate.py | 144 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/ASVS/agents/asvs_orchestrate.py b/ASVS/agents/asvs_orchestrate.py
index ddc1c99..2913d22 100644
--- a/ASVS/agents/asvs_orchestrate.py
+++ b/ASVS/agents/asvs_orchestrate.py
@@ -360,6 +360,150 @@ async def run(input_dict, tools):
             )
 
             if critical_findings:
+                # Build a set of redacted Finding IDs for cross-reference scrubbing
+                redacted_ids = set()
+                for cf in critical_findings:
+                    fid = cf["id"]
+                    redacted_ids.add(fid)
+                    # Also add the FINDING-NNN form if it's an ASVS-style ID
+                    # (consolidated.md cross-refs always use the FINDING-NNN form
+                    # regardless of which form appears in the per-section reports)
+                    m = re.match(r'FINDING-(\d+)', fid)
+                    if m:
+                        redacted_ids.add(fid)
+
+                # 1. Recompute the Severity Distribution table.
+                # Pattern: a markdown table row with Critical count as first cell.
+                # Match both formats:
+                #   | 6 | 16 | 34 | 21 | 0 |
+                #   | 6 | 16 | 34 | 21 | 0 | **77** |
+                def _zero_critical_count(m):
+                    # Replace the Critical count (first numeric cell after `|`)
+                    # with 0, leaving the other counts and Total intact.
+                    row = m.group(0)
+                    # Subtract redacted count from total if present
+                    redacted_count = len(critical_findings)
+                    # Replace first numeric cell with 0
+                    new_row = re.sub(r'(\|\s*)\d+(\s*\|)', r'\g<1>0\g<2>', row, count=1)
+                    # Try to find a Total cell (bold-wrapped number) and decrement it
+                    total_m = re.search(r'\*\*(\d+)\*\*', new_row)
+                    if total_m:
+                        old_total = int(total_m.group(1))
+                        new_total = max(0, old_total - redacted_count)
+                        new_row = new_row.replace(f'**{old_total}**', f'**{new_total}**')
+                    return new_row
+                # Find Severity Distribution table rows. They follow a header
+                # like "| Critical | High | Medium | Low | Info |" and the
+                # numeric row immediately follows the alignment row.
+                sev_table_pattern = re.compile(
+                    r'(\|\s*Critical\s*\|\s*High\s*\|\s*Medium\s*\|\s*Low\s*\|\s*Info[^\n]*\|\n'
+                    r'\|[\s:|-]+\|\n)'
+                    r'(\|[^\n]+\|)',
+                    re.IGNORECASE,
+                )
+                def _sev_table_replace(m):
+                    return m.group(1) + _zero_critical_count(re.match(r'.*', m.group(2)))
+                redacted = sev_table_pattern.sub(_sev_table_replace, redacted)
+
+                # 2. Strip ASCII bar chart Critical line if present (e.g.
+                #    "Critical  ████░░  6  ( 7.8%)")
+                redacted = re.sub(
+                    r'^[ \t]*Critical[ \t]+[█░▓▒]+[^\n]*\n',
+                    '',
+                    redacted,
+                    flags=re.MULTILINE | re.IGNORECASE,
+                )
+
+                # 3. Scrub references to redacted Finding IDs in Top Risks /
+                #    Cross-Reference Matrix tables. These appear in cells like:
+                #    "FINDING-001 through FINDING-004, FINDING-010, ..."
+                #    Drop only the redacted IDs, preserving the rest.
+                #    Do not touch tables in code blocks or per-finding blocks
+                #    (those have already been removed).
+                if redacted_ids:
+                    sorted_ids = sorted(redacted_ids,
+                                         key=lambda s: int(re.search(r'(\d+)', s).group(1)) if re.search(r'(\d+)', s) else 0)
+
+                    # Drop "FINDING-A through FINDING-B" ranges. If the entire
+                    # range is redacted, drop the whole expression. Otherwise
+                    # rewrite to "FINDING-X, FINDING-Y, ..." with only the
+                    # surviving IDs, then let the per-ID stripping below clean
+                    # up redacted ones.
+                    def _strip_range(m):
+                        a = m.group(1)
+                        b = m.group(2)
+                        try:
+                            a_num = int(re.search(r'(\d+)', a).group(1))
+                            b_num = int(re.search(r'(\d+)', b).group(1))
+                        except Exception:
+                            return m.group(0)
+                        survivors = [
+                            f"FINDING-{n:03d}"
+                            for n in range(a_num, b_num + 1)
+                            if f"FINDING-{n:03d}" not in redacted_ids
+                        ]
+                        if not survivors:
+                            return ""
+                        return ", ".join(survivors)
+                    redacted = re.sub(
+                        r'(FINDING-\d+)\s+through\s+(FINDING-\d+)',
+                        _strip_range,
+                        redacted,
+                    )
+
+                    # Drop comma-separated occurrences of redacted IDs
+                    for fid in sorted_ids:
+                        redacted = re.sub(
+                            r',\s*' + re.escape(fid) + r'\b',
+                            '',
+                            redacted,
+                        )
+                        redacted = re.sub(
+                            r'\b' + re.escape(fid) + r'\s*,\s*',
+                            '',
+                            redacted,
+                        )
+                        # Bare leftover - could be in a table cell on its own
+                        redacted = re.sub(
+                            r'\b' + re.escape(fid) + r'\b',
+                            '',
+                            redacted,
+                        )
+
+                    # Scrub "Nx Critical" / "N× Critical" / "N Critical" phrases
+                    # in surviving table cells — the count is now wrong and
+                    # naming the redacted severity defeats the purpose of the
+                    # carve-out. Preserve other severity counts in the cell.
+                    def _strip_critical_phrases(m):
+                        cell = m.group(0)
+                        # Drop the "Nx Critical, " or "N× Critical, " segments
+                        cell = re.sub(
+                            r'\d+\s*[x×]\s*Critical\s*,?\s*',
+                            '',
+                            cell,
+                            flags=re.IGNORECASE,
+                        )
+                        # Tidy up trailing/leading commas
+                        cell = re.sub(r',\s*\|', ' |', cell)
+                        cell = re.sub(r'\|\s*,', '| ', cell)
+                        return cell
+                    # Apply to lines that look like table rows
+                    redacted = re.sub(
+                        r'\|[^\n]*Critical[^\n]*\|',
+                        _strip_critical_phrases,
+                        redacted,
+                    )
+
+                    # Clean up leftover artifacts: empty list items,
+                    # cells starting with stray ", ", double commas, leading
+                    # whitespace from removed ranges, and full Cross-Reference
+                    # Matrix rows whose Finding ID col is now empty.
+                    redacted = re.sub(r'\|\s*,\s*', '| ', redacted)
+                    redacted = re.sub(r',\s*,', ',', redacted)
+                    # Collapse multiple spaces inside cells (not at line start)
+                    redacted = re.sub(r'\|\s{2,}', '| ', redacted)
+                    redacted = re.sub(r'\|\s+\|\s+(Critical|High|Medium|Low)\b[^\n]*\n', '', redacted)
+
                 notice = (
                     f"\n\n> **Note:** {len(critical_findings)} Critical "
                     f"{'finding has' if len(critical_findings) == 1 else 'findings have'} "


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tooling.apache.org
For additional commands, e-mail: commits-help@tooling.apache.org