diff --git a/.jules/bolt.md b/.jules/bolt.md index 420e6d7e2..a58b51a07 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -47,3 +47,6 @@ ## 2026-08-09 - [대용량 로그 스캔 시 정규표현식 실행 전 O(N) 서브스트링 검증 선행] **Learning:** `classify_testthat_failure`에서 테스트 실패 내역이 없는 2MB 로그 파일을 대상으로 정규표현식을 실행하면 약 20ms가 소요되지만, 단순 문자열 검색은 약 1ms만 소요됩니다. 문자열 존재 여부가 정규표현식 매칭의 전제 조건일 때, 콜드 패스(Cold Path)에서 순서 최적화는 매우 큰 성능 차이를 만듭니다. **Action:** 대용량 텍스트 입력(CI 로그 등)에서 복잡한 정규표현식을 파싱하기 전에 항상 빠른 O(N) 문자열 존재 여부 확인을 먼저 수행하십시오. +## 2024-06-25 - Redundant regex passes on large CI logs +**Learning:** In string-heavy processing scripts like `redact_sensitive_log.py`, sequentially applying multiple regexes to scan for static tokens in large strings causes severe O(N) overhead since Python's `re.sub` iterates the entire text anew for each pattern. +**Action:** Always combine mutually exclusive regex patterns using the `|` alternation operator (e.g., `re.compile(r"pattern1|pattern2")`) into a single pass to eliminate redundant N-length text iterations when applying multiple replacements over large log payloads. diff --git a/scripts/ci/redact_sensitive_log.py b/scripts/ci/redact_sensitive_log.py index 16e89f264..cf0f1e535 100644 --- a/scripts/ci/redact_sensitive_log.py +++ b/scripts/ci/redact_sensitive_log.py @@ -24,11 +24,12 @@ r"[^\s\"'\\]+", re.IGNORECASE, ) -PROVIDER_TOKEN_RES = ( - re.compile(r"\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b"), - re.compile(r"\bsk-[A-Za-z0-9_-]{20,}\b"), - re.compile(r"\bxox[baprs]-[A-Za-z0-9-]{20,}\b"), - re.compile(r"\bAKIA[0-9A-Z]{16}\b"), +# ⚡ Bolt: Combined regex pattern using | alternation to eliminate O(N) redundant passes over large CI logs +PROVIDER_TOKEN_RE = re.compile( + r"\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,})\b|" + r"\bsk-[A-Za-z0-9_-]{20,}\b|" + r"\bxox[baprs]-[A-Za-z0-9-]{20,}\b|" + r"\bAKIA[0-9A-Z]{16}\b" ) @@ -118,8 +119,7 @@ def _redact_unstructured(text: str) -> str: cleaned = _redact_assignments(text) cleaned = BEARER_RE.sub(lambda match: f"{match.group('prefix')}{REDACTED}", cleaned) cleaned = JWT_RE.sub(REDACTED, cleaned) - for pattern in PROVIDER_TOKEN_RES: - cleaned = pattern.sub(REDACTED, cleaned) + cleaned = PROVIDER_TOKEN_RE.sub(REDACTED, cleaned) return cleaned