Initial SQL-only 1C adapter baseline

This commit is contained in:
2026-07-22 03:03:47 +03:00
commit e2503b77e7
545 changed files with 184711 additions and 0 deletions
+156
View File
@@ -0,0 +1,156 @@
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
import scripts.compare_1c_access_role_audit as compare_script
import scripts.export_1c_access_role_audit as export_script
def compare_stem(old_path: Path, new_path: Path) -> str:
return f"compare-{old_path.stem.replace('.summary', '')}-{new_path.stem.replace('.summary', '')}"
def verdict_for(export_summary: dict[str, Any], compare_result: dict[str, Any] | None) -> str:
counts = compare_result.get("counts") if isinstance(compare_result, dict) and isinstance(compare_result.get("counts"), dict) else {}
if any(int(counts.get(key) or 0) > 0 for key in ("added_users", "removed_users", "changed_access_paths")):
return "changed"
if str(export_summary.get("risk_level") or "").lower() in {"medium", "high"}:
return "risk"
return "ok"
def audit_role(
*,
adapter_url: str,
base_id: str,
role: str,
report_root: Path,
timeout: int,
user_threshold: int,
limit: int,
include_html: bool = True,
) -> dict[str, Any]:
export_summary = export_script.export_role_audit(
adapter_url=adapter_url,
base_id=base_id,
role=role,
report_root=report_root,
timeout=timeout,
user_threshold=user_threshold,
include_analysis=True,
limit=limit,
include_html=include_html,
)
latest = compare_script.find_latest_summaries(report_root, base_id, role=role, count=2)
compare_result: dict[str, Any] | None = None
if len(latest) >= 2:
new_path, old_path = latest[0], latest[1]
folder = report_root / compare_script.slugify(base_id, max_length=60)
stem = compare_stem(old_path, new_path)
compare_result = compare_script.compare_files(
old_path,
new_path,
output=folder / f"{stem}.json",
html_output=folder / f"{stem}.html",
)
export_script.update_index(report_root, base_id)
return {
"schema": "onec_access_role_audit_run.v1",
"status": export_summary.get("status"),
"base_id": base_id,
"role": role,
"verdict": verdict_for(export_summary, compare_result),
"export": export_summary,
"compare": compare_result,
}
def audit_config(
*,
config_path: Path,
adapter_url: str,
report_root: Path,
timeout: int,
limit: int,
include_html: bool = True,
) -> dict[str, Any]:
config = json.loads(config_path.read_text(encoding="utf-8"))
roles = config.get("roles") if isinstance(config.get("roles"), list) else []
default_base_id = str(config.get("base_id") or "upo_test")
results: list[dict[str, Any]] = []
for item in roles:
if not isinstance(item, dict) or not item.get("role"):
continue
results.append(
audit_role(
adapter_url=adapter_url,
base_id=str(item.get("base_id") or default_base_id),
role=str(item.get("role")),
report_root=report_root,
timeout=timeout,
user_threshold=int(item.get("user_threshold") or 50),
limit=limit,
include_html=include_html,
)
)
verdicts = [str(item.get("verdict") or "") for item in results]
overall = "changed" if "changed" in verdicts else "risk" if "risk" in verdicts else "ok"
return {
"schema": "onec_access_role_audit_batch.v1",
"status": "ok" if all(item.get("status") == "ok" for item in results) else "error",
"config": str(config_path),
"overall_verdict": overall,
"counts": {"roles": len(results), "changed": verdicts.count("changed"), "risk": verdicts.count("risk"), "ok": verdicts.count("ok")},
"results": results,
}
def main() -> int:
parser = argparse.ArgumentParser(description="Run 1C role access audit: export, analyze, update index, compare with previous.")
parser.add_argument("--adapter-url", default=export_script.DEFAULT_BASE_URL)
parser.add_argument("--base-id", default="upo_test")
parser.add_argument("--role")
parser.add_argument("--config", type=Path, help="Run all roles from an access critical roles JSON config.")
parser.add_argument("--report-root", type=Path, default=export_script.DEFAULT_REPORT_ROOT)
parser.add_argument("--timeout", type=int, default=120)
parser.add_argument("--limit", type=int, default=20000)
parser.add_argument("--user-threshold", type=int, default=50)
parser.add_argument("--no-html", action="store_true")
args = parser.parse_args()
if args.config:
result = audit_config(
config_path=args.config,
adapter_url=args.adapter_url,
report_root=args.report_root,
timeout=args.timeout,
limit=args.limit,
include_html=not args.no_html,
)
else:
if not args.role:
parser.error("--role is required unless --config is used.")
result = audit_role(
adapter_url=args.adapter_url,
base_id=args.base_id,
role=args.role,
report_root=args.report_root,
timeout=args.timeout,
user_threshold=args.user_threshold,
limit=args.limit,
include_html=not args.no_html,
)
print(json.dumps(result, ensure_ascii=False, indent=2))
return 0 if result.get("status") == "ok" else 1
if __name__ == "__main__":
raise SystemExit(main())