"""Robot Framework helper for validation apply gate. Provides a CLI-style interface for Robot to invoke validation attachment creation, runner execution, and gate evaluation. Exit code 0 = success, 1 = failure. Usage:: python robot/helper_validation_apply.py run-gate \\ python robot/helper_validation_apply.py summary \\ python robot/helper_validation_apply.py check-block \\ """ from __future__ import annotations import json import sys from pathlib import Path # Ensure the src directory is on the import path. _SRC = str(Path(__file__).resolve().parents[1] / "src") if _SRC not in sys.path: sys.path.insert(0, _SRC) from cleveragents.application.services.validation_apply import ( # noqa: E402 ApplyValidationGate, ApplyValidationResult, ApplyValidationSummary, DefaultValidationRunner, ValidationAttachment, ) from cleveragents.domain.models.core.tool import ValidationMode # noqa: E402 def _cmd_run_gate(args: list[str]) -> int: """Run the validation gate with a single attachment.""" if len(args) < 6: print( "Usage: run-gate " ) return 1 plan_id = args[0] att = ValidationAttachment( attachment_id="01ATT000000000000000000000", validation_name=args[1], resource_id=args[2], mode=ValidationMode(args[3]), ) ctx = {args[4]: args[5]} runner = DefaultValidationRunner() gate = ApplyValidationGate(runner=runner) summary = gate.run(plan_id, [att], ctx) blocked = gate.should_block_apply(summary) status = "BLOCKED" if blocked else "ALLOWED" print(f"val-gate-ok: {status}") print(f" total={summary.total}") print(f" required_passed={summary.required_passed}") print(f" required_failed={summary.required_failed}") return 0 def _cmd_summary(args: list[str]) -> int: """Build a summary and print metadata.""" if len(args) < 3: print("Usage: summary ") return 1 plan_id = args[0] n_pass, n_fail = int(args[1]), int(args[2]) results: list[ApplyValidationResult] = [] for i in range(n_pass): results.append( ApplyValidationResult( attachment_id=f"01ATT{i:021d}", validation_name=f"val-{i}", resource_id=f"res-{i}", mode=ValidationMode.REQUIRED, passed=True, message="ok", ) ) for i in range(n_fail): results.append( ApplyValidationResult( attachment_id=f"01ATT{n_pass + i:021d}", validation_name=f"val-{n_pass + i}", resource_id=f"res-{n_pass + i}", mode=ValidationMode.REQUIRED, passed=False, message="failed", ) ) summary = ApplyValidationSummary(plan_id=plan_id, results=results) md = summary.to_plan_metadata() print(f"val-summary-ok: {json.dumps(md, default=str)}") return 0 def _cmd_check_block(args: list[str]) -> int: """Check if gate blocks apply.""" if len(args) < 3: print("Usage: check-block ") return 1 plan_id = args[0] n_pass, n_fail = int(args[1]), int(args[2]) results: list[ApplyValidationResult] = [] for i in range(n_pass): results.append( ApplyValidationResult( attachment_id=f"01ATT{i:021d}", validation_name=f"val-{i}", resource_id=f"res-{i}", mode=ValidationMode.REQUIRED, passed=True, message="ok", ) ) for i in range(n_fail): results.append( ApplyValidationResult( attachment_id=f"01ATT{n_pass + i:021d}", validation_name=f"val-{n_pass + i}", resource_id=f"res-{n_pass + i}", mode=ValidationMode.REQUIRED, passed=False, message="failed", ) ) summary = ApplyValidationSummary(plan_id=plan_id, results=results) gate = ApplyValidationGate(runner=DefaultValidationRunner()) blocked = gate.should_block_apply(summary) status = "BLOCKED" if blocked else "ALLOWED" print(f"val-check-block-ok: {status}") return 0 def main() -> int: """Entry point called by Robot Framework ``Run Process``.""" if len(sys.argv) < 2: print("Usage: helper_validation_apply.py ...") return 1 command = sys.argv[1] args = sys.argv[2:] dispatch = { "run-gate": _cmd_run_gate, "summary": _cmd_summary, "check-block": _cmd_check_block, } handler = dispatch.get(command) if handler is None: print(f"Unknown command: {command}") return 1 return handler(args) if __name__ == "__main__": sys.exit(main())