feat: add test-preflight runner and deployer prepare adapters

agent-runtime executes fixed tester node operations over JSON stdin.
deployer prepare brings up the local test Compose service the same way.
test-preflight now passes the tester binding; tester select skips
unauthorized cases before creating a runner.
This commit is contained in:
2026-10-19 09:28:50 +08:00
parent 9075ff6a5a
commit adaa8e4edd
9 changed files with 1179 additions and 11 deletions
+7 -1
View File
@@ -777,6 +777,10 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
selected: list[dict[str, Any]] = []
skipped: list[dict[str, str]] = []
missing = set(wanted)
# Resolve authorization gates during selection so an explicit safety or
# mutating request is represented as skipped before any runner/session is
# created. run-script keeps the same check as a defense in depth.
vars_map = resolve_vars(root, meta)
for case in cases:
cid = str(case.get("id") or "")
@@ -824,6 +828,9 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
if r_i > max_i:
skipped.append({"id": cid, "reason": f"risk={risk} 超过上限 {max_risk}"})
continue
if not authorized(vars_map, meta, case):
skipped.append({"id": cid, "reason": f"风险 {risk} 未授权"})
continue
selected.append(public_case(case))
if wanted and missing:
@@ -855,7 +862,6 @@ def cmd_select(args: argparse.Namespace, root: Path) -> int:
return 2
# 按分类解析生效的 status_probe,让 Agent 不再自己按 catalog 猜作用范围。
vars_map = resolve_vars(root, meta)
status_probes: dict[str, dict[str, Any]] = {}
for case in selected:
cat = str(case.get("category") or "")
+3
View File
@@ -210,6 +210,9 @@ def android_identity(path: Path, context: RuntimeContext) -> str:
for command in commands:
result = run_command(command, context=context)
if result.code == 0:
plain = result.output.strip()
if re.fullmatch(r"[A-Za-z][A-Za-z0-9_.-]*", plain):
return plain
match = re.search(r"(?:name|application-id)[=:]['\"]?([A-Za-z0-9_.]+)", result.output)
if match:
return match.group(1)