Files
cleveragents-core/robot/helper_validation_apply.py
T
2026-02-25 10:03:21 +00:00

164 lines
5.0 KiB
Python

"""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 \\
<plan_id> <val_name> <res_id> <mode> <ctx_key> <ctx_val>
python robot/helper_validation_apply.py summary \\
<plan_id> <n_req_pass> <n_req_fail>
python robot/helper_validation_apply.py check-block \\
<plan_id> <n_req_pass> <n_req_fail>
"""
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 <plan_id> <val_name> <res_id> <mode> <ctx_key> <ctx_val>"
)
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 <plan_id> <n_req_pass> <n_req_fail>")
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 <plan_id> <n_req_pass> <n_req_fail>")
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 <run-gate|summary|check-block> ...")
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())