142 lines
4.6 KiB
Python
Executable File
142 lines
4.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
|
|
def load_json(path: Path) -> dict:
|
|
return json.loads(path.read_text())
|
|
|
|
|
|
def locale_rows(payload: dict) -> list[tuple[str, dict]]:
|
|
summary = payload.get("summary", {})
|
|
return [(locale, data) for locale, data in summary.items() if locale != "snippets"]
|
|
|
|
|
|
def print_error(payload: dict) -> int:
|
|
error = payload.get("error")
|
|
if error:
|
|
print(f"AUDIT ERROR: {error}")
|
|
return 2
|
|
return 0
|
|
|
|
|
|
def print_summary(payload: dict) -> tuple[int, int]:
|
|
total_block = 0
|
|
total_warn = 0
|
|
for locale, data in locale_rows(payload):
|
|
sev = data.get("by_severity", {})
|
|
block = int(sev.get("block", 0) or 0)
|
|
warn = int(sev.get("warn", 0) or 0)
|
|
log = int(sev.get("log", 0) or 0)
|
|
total_block += block
|
|
total_warn += warn
|
|
print(
|
|
f"LOCALE {locale}: issues_found={data.get('issues_found', 0)} "
|
|
f"issues_remaining={data.get('remaining_issues', 0)} "
|
|
f"block={block} warn={warn} log={log}"
|
|
)
|
|
return total_block, total_warn
|
|
|
|
|
|
def _cta_issue_is_allowed_now(locale: str, issue: dict) -> bool:
|
|
if issue.get("issue_type") != "cta_language_mismatch":
|
|
return False
|
|
if issue.get("severity") != "block":
|
|
return False
|
|
|
|
try:
|
|
from mandelblog_content_guard.validators.rules.cta import validate_cta
|
|
except Exception:
|
|
return False
|
|
|
|
bad_value = issue.get("bad_value") or ""
|
|
field_paths = issue.get("field_paths") or []
|
|
if not field_paths:
|
|
return False
|
|
|
|
for field_path in field_paths:
|
|
if validate_cta(locale, field_path, bad_value):
|
|
return False
|
|
return True
|
|
|
|
|
|
def effective_block_count(payload: dict) -> tuple[int, int]:
|
|
"""Return (effective_block, ignored_block) after applying allowlists."""
|
|
ignored = 0
|
|
block = 0
|
|
issues = payload.get("issues") or {}
|
|
for locale, data in locale_rows(payload):
|
|
locale_issues = issues.get(locale) or []
|
|
for issue in locale_issues:
|
|
if issue.get("severity") != "block":
|
|
continue
|
|
if _cta_issue_is_allowed_now(locale, issue):
|
|
ignored += int(issue.get("count") or 1)
|
|
continue
|
|
block += int(issue.get("count") or 1)
|
|
return block, ignored
|
|
|
|
|
|
def print_regressions(current: dict, previous: dict) -> None:
|
|
prev_summary = {locale: data for locale, data in locale_rows(previous)}
|
|
regressions = []
|
|
for locale, data in locale_rows(current):
|
|
prev = prev_summary.get(locale, {})
|
|
cur_remaining = int(data.get("remaining_issues", 0) or 0)
|
|
prev_remaining = int(prev.get("remaining_issues", 0) or 0)
|
|
cur_sev = data.get("by_severity", {})
|
|
prev_sev = prev.get("by_severity", {})
|
|
delta = {
|
|
"remaining": cur_remaining - prev_remaining,
|
|
"block": int(cur_sev.get("block", 0) or 0) - int(prev_sev.get("block", 0) or 0),
|
|
"warn": int(cur_sev.get("warn", 0) or 0) - int(prev_sev.get("warn", 0) or 0),
|
|
"log": int(cur_sev.get("log", 0) or 0) - int(prev_sev.get("log", 0) or 0),
|
|
}
|
|
if any(value > 0 for value in delta.values()):
|
|
regressions.append((locale, delta))
|
|
if regressions:
|
|
print("REGRESSIONS:")
|
|
for locale, delta in regressions:
|
|
print(
|
|
f"- {locale}: remaining={delta['remaining']:+d} block={delta['block']:+d} "
|
|
f"warn={delta['warn']:+d} log={delta['log']:+d}"
|
|
)
|
|
else:
|
|
print("REGRESSIONS: none")
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--json", required=True, help="Current multilingual audit JSON file")
|
|
parser.add_argument("--previous-json", help="Optional previous audit JSON file for regression comparison")
|
|
args = parser.parse_args()
|
|
|
|
current = load_json(Path(args.json))
|
|
error_status = print_error(current)
|
|
if error_status:
|
|
return error_status
|
|
total_block, total_warn = print_summary(current)
|
|
effective_block, ignored_block = effective_block_count(current)
|
|
if ignored_block:
|
|
print(f"IGNORED: {ignored_block} block issue(s) now allowed by current rules")
|
|
|
|
if args.previous_json:
|
|
prev_path = Path(args.previous_json)
|
|
if prev_path.exists():
|
|
print_regressions(current, load_json(prev_path))
|
|
else:
|
|
print("REGRESSIONS: previous artifact not found")
|
|
|
|
if effective_block > 0:
|
|
return 2
|
|
if total_warn > 0:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|