From 6b81045d085326b578495bb9244a7f6675e40e93 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:10:02 +0000 Subject: [PATCH] Refactor SARIF generation to eliminate O(N*M) list indexing bottleneck --- .jules/bolt.md | 4 ++++ appguardrail_core/sarif.py | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 8ce7ce8f7..45c89ada9 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -77,3 +77,7 @@ ## 2024-11-20 - Optimize multiple tuple generation from a single collection **Learning:** `build_rule_metadata` derives exactly two collections, `owasp` and `cwe`, from the same references. Replacing its two generator traversals with one explicit loop reduces element visits from about 2N to N. Both versions remain O(N), so this is a constant-factor optimization rather than an asymptotic complexity improvement. **Action:** Combine repeated traversal when fixed derived collections share one source, while preserving ordering and classification semantics. Benchmark the production hot path before claiming a material wall-clock improvement. + +## 2025-03-01 - O(N*M) List Indexing in SARIF Generation +**Learning:** Calling `list(dict).index(key)` inside a loop over findings to determine the rule index creates an O(N*M) performance bottleneck, allocating a new list and scanning it linearly for every item. +**Action:** Use a companion dictionary `rule_indices: dict[str, int] = {}` to map rule IDs to their integer index (e.g., `len(rules)`) when first encountered. This reduces the lookup time complexity to O(1). diff --git a/appguardrail_core/sarif.py b/appguardrail_core/sarif.py index ca4a9fb6b..654592fab 100644 --- a/appguardrail_core/sarif.py +++ b/appguardrail_core/sarif.py @@ -39,6 +39,7 @@ def findings_to_sarif( normalized = normalize_findings(findings) rules: dict[str, dict[str, Any]] = {} + rule_indices: dict[str, int] = {} results: list[dict[str, Any]] = [] for f in normalized: rule_id = f["rule_id"] @@ -63,12 +64,13 @@ def findings_to_sarif( "security-severity": _SECURITY_SEVERITY.get(severity, "2.0"), }, } + rule_indices[rule_id] = len(rules) rules[rule_id] = rule results.append( { "ruleId": rule_id, - "ruleIndex": list(rules).index(rule_id), + "ruleIndex": rule_indices[rule_id], "level": _LEVEL.get(severity, "note"), "message": {"text": f["message"].strip()}, "locations": [