feat(orc): centralize host-aware routing
This commit is contained in:
+166
-42
@@ -18,7 +18,7 @@ from unittest import mock
|
||||
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||
ORC_DIR = REPO_ROOT / "skills" / "orc"
|
||||
SCRIPT = ORC_DIR / "scripts" / "resolve_profile.py"
|
||||
CONFIG = ORC_DIR / "templates" / "config.template.yaml"
|
||||
CONFIG = ORC_DIR / "config.yaml"
|
||||
|
||||
spec = importlib.util.spec_from_file_location("orc_resolve_profile", SCRIPT)
|
||||
assert spec is not None and spec.loader is not None
|
||||
@@ -36,7 +36,13 @@ class OrcSkillTests(unittest.TestCase):
|
||||
self.assertIn("low", skill)
|
||||
self.assertIn("mid", skill)
|
||||
self.assertIn("high", skill)
|
||||
self.assertIn("只支持 `cli: codex`", skill)
|
||||
self.assertIn("`codex` 和 `cursor-agent`", skill)
|
||||
self.assertIn("<orc-skill-dir>/config.yaml", skill)
|
||||
self.assertIn("不得在项目中创建 `docs/orc/config.yaml`", skill)
|
||||
self.assertIn("薄路由器", skill)
|
||||
self.assertIn("不做领域判断", skill)
|
||||
self.assertNotIn("用户未指定档位时采用以下判断", skill)
|
||||
self.assertNotIn("若该档位不足以安全完成", skill)
|
||||
for child in ("$ack", "$manage-release", "$deb-publisher", "$publish-docker-image"):
|
||||
self.assertIn(child, routing)
|
||||
|
||||
@@ -64,12 +70,20 @@ class OrcSkillTests(unittest.TestCase):
|
||||
self.assertIn("最多到", routing)
|
||||
self.assertIn("review_ready", routing)
|
||||
self.assertIn("当前 task 粒度无法安全表达", routing)
|
||||
self.assertRegex(
|
||||
routing,
|
||||
r"不判断版本号、\s*实现方案、发布风险或产物策略",
|
||||
)
|
||||
|
||||
def test_template_and_cli_validate(self) -> None:
|
||||
def test_shared_config_and_cli_validate(self) -> None:
|
||||
config = orc_profiles.load_config(CONFIG)
|
||||
self.assertEqual(set(config["profiles"]), {"low", "mid", "high"})
|
||||
self.assertEqual(config["version"], 2)
|
||||
self.assertEqual(config["cliPolicy"], "current-host")
|
||||
self.assertEqual(set(config["profiles"]), {"codex", "cursor-agent"})
|
||||
for cli in ("codex", "cursor-agent"):
|
||||
self.assertEqual(set(config["profiles"][cli]), {"low", "mid", "high"})
|
||||
completed = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "validate", str(CONFIG)],
|
||||
[sys.executable, str(SCRIPT), "validate"],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
@@ -77,8 +91,16 @@ class OrcSkillTests(unittest.TestCase):
|
||||
self.assertEqual(completed.returncode, 0, completed.stderr)
|
||||
self.assertIn('"ok": true', completed.stdout)
|
||||
|
||||
project_config_argument = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "validate", str(CONFIG)],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
self.assertEqual(project_config_argument.returncode, 2)
|
||||
|
||||
clean_python = subprocess.run(
|
||||
[sys.executable, "-I", "-S", str(SCRIPT), "validate", str(CONFIG)],
|
||||
[sys.executable, "-I", "-S", str(SCRIPT), "validate"],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
@@ -88,24 +110,39 @@ class OrcSkillTests(unittest.TestCase):
|
||||
def test_level_precedence_is_stage_then_global_then_config(self) -> None:
|
||||
config = orc_profiles.load_config(CONFIG)
|
||||
stage = orc_profiles.resolve_profile(
|
||||
config, stage="docker", global_level="mid", stage_level="high"
|
||||
config,
|
||||
stage="docker",
|
||||
host_cli="codex",
|
||||
global_level="mid",
|
||||
stage_level="high",
|
||||
)
|
||||
global_choice = orc_profiles.resolve_profile(
|
||||
config, stage="docker", global_level="mid"
|
||||
config, stage="docker", host_cli="codex", global_level="mid"
|
||||
)
|
||||
configured = orc_profiles.resolve_profile(
|
||||
config, stage="docker", host_cli="codex"
|
||||
)
|
||||
configured = orc_profiles.resolve_profile(config, stage="docker")
|
||||
fallback_config = copy.deepcopy(config)
|
||||
del fallback_config["stageDefaults"]["docker"]
|
||||
fallback = orc_profiles.resolve_profile(fallback_config, stage="docker")
|
||||
fallback = orc_profiles.resolve_profile(
|
||||
fallback_config, stage="docker", host_cli="codex"
|
||||
)
|
||||
|
||||
self.assertEqual((stage["level"], stage["selectionSource"]), ("high", "request.stage"))
|
||||
self.assertEqual((global_choice["level"], global_choice["selectionSource"]), ("mid", "request.global"))
|
||||
self.assertEqual((configured["level"], configured["selectionSource"]), ("low", "config.stageDefaults.docker"))
|
||||
self.assertEqual((fallback["level"], fallback["selectionSource"]), ("mid", "config.defaultLevel"))
|
||||
self.assertEqual(configured["cli"], "codex")
|
||||
self.assertEqual(configured["cliSelectionSource"], "runtime.host")
|
||||
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "host CLI is required"):
|
||||
orc_profiles.resolve_profile(config, stage="docker")
|
||||
|
||||
def test_resolver_builds_fixed_worker_args_without_free_command_fields(self) -> None:
|
||||
config = orc_profiles.load_config(CONFIG)
|
||||
plan = orc_profiles.resolve_profile(config, stage="release")
|
||||
plan = orc_profiles.resolve_profile(
|
||||
config, stage="release", host_cli="codex"
|
||||
)
|
||||
|
||||
self.assertEqual(plan["workerArgs"][:2], ["--model", "gpt-5.6-terra"])
|
||||
self.assertIn("--strict-config", plan["workerArgs"])
|
||||
@@ -113,6 +150,40 @@ class OrcSkillTests(unittest.TestCase):
|
||||
self.assertNotIn("env", plan["profile"])
|
||||
self.assertNotIn("command", plan["profile"])
|
||||
|
||||
cursor = orc_profiles.resolve_profile(
|
||||
config,
|
||||
stage="release",
|
||||
host_cli="cursor-agent",
|
||||
stage_level="low",
|
||||
)
|
||||
self.assertEqual(cursor["cli"], "cursor-agent")
|
||||
self.assertEqual(cursor["cliSelectionSource"], "runtime.host")
|
||||
self.assertEqual(cursor["modelAuth"], "cursor-login")
|
||||
self.assertEqual(
|
||||
cursor["workerArgs"],
|
||||
[
|
||||
"--model",
|
||||
"auto",
|
||||
"--auto-review",
|
||||
"--sandbox",
|
||||
"enabled",
|
||||
],
|
||||
)
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "not valid for cursor-agent"):
|
||||
orc_profiles.resolve_profile(
|
||||
config,
|
||||
stage="release",
|
||||
host_cli="cursor-agent",
|
||||
model_auth="openai",
|
||||
)
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "not valid for codex"):
|
||||
orc_profiles.resolve_profile(
|
||||
config,
|
||||
stage="release",
|
||||
host_cli="codex",
|
||||
model_auth="cursor-api-key",
|
||||
)
|
||||
|
||||
def test_worker_environment_selects_one_model_and_remote_auth(self) -> None:
|
||||
ambient = {
|
||||
"OPENAI_API_KEY": "openai-secret",
|
||||
@@ -145,6 +216,19 @@ class OrcSkillTests(unittest.TestCase):
|
||||
):
|
||||
self.assertNotIn(rejected, environment)
|
||||
|
||||
cursor_ambient = {
|
||||
"CURSOR_API_KEY": "cursor-secret",
|
||||
"OPENAI_API_KEY": "openai-secret",
|
||||
}
|
||||
with mock.patch.dict(os.environ, cursor_ambient, clear=True):
|
||||
cursor_environment = orc_profiles.worker_environment(
|
||||
"release",
|
||||
model_auth="cursor-api-key",
|
||||
remote_auth="none",
|
||||
)
|
||||
self.assertEqual(cursor_environment["CURSOR_API_KEY"], "cursor-secret")
|
||||
self.assertNotIn("OPENAI_API_KEY", cursor_environment)
|
||||
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "deb remote auth"):
|
||||
orc_profiles.worker_environment(
|
||||
"deb",
|
||||
@@ -240,35 +324,60 @@ class OrcSkillTests(unittest.TestCase):
|
||||
base = orc_profiles.load_config(CONFIG)
|
||||
|
||||
free_command = copy.deepcopy(base)
|
||||
free_command["profiles"]["low"]["command"] = "codex --dangerously-bypass"
|
||||
free_command["profiles"]["codex"]["low"]["command"] = "codex --dangerously-bypass"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "unknown fields"):
|
||||
orc_profiles.validate_config(free_command)
|
||||
|
||||
full_access = copy.deepcopy(base)
|
||||
full_access["profiles"]["high"]["permissionMode"] = "danger-full-access"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "workspace-write in ORC v1"):
|
||||
full_access["profiles"]["codex"]["high"]["permissionMode"] = "danger-full-access"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "workspace-write in ORC v2"):
|
||||
orc_profiles.validate_config(full_access)
|
||||
|
||||
read_only = copy.deepcopy(base)
|
||||
read_only["profiles"]["low"]["permissionMode"] = "read-only"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "workspace-write in ORC v1"):
|
||||
read_only["profiles"]["codex"]["low"]["permissionMode"] = "read-only"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "workspace-write in ORC v2"):
|
||||
orc_profiles.validate_config(read_only)
|
||||
|
||||
missing_level = copy.deepcopy(base)
|
||||
del missing_level["profiles"]["mid"]
|
||||
del missing_level["profiles"]["cursor-agent"]["mid"]
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "missing fields: mid"):
|
||||
orc_profiles.validate_config(missing_level)
|
||||
|
||||
option_model = copy.deepcopy(base)
|
||||
option_model["profiles"]["low"]["model"] = "--model"
|
||||
option_model["profiles"]["codex"]["low"]["model"] = "--model"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "safe exact model ID"):
|
||||
orc_profiles.validate_config(option_model)
|
||||
|
||||
list_policy = copy.deepcopy(base)
|
||||
list_policy["profiles"]["low"]["approvalPolicy"] = ["never"]
|
||||
list_policy["profiles"]["codex"]["low"]["approvalPolicy"] = ["never"]
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "approvalPolicy"):
|
||||
orc_profiles.validate_config(list_policy)
|
||||
|
||||
cursor_effort = copy.deepcopy(base)
|
||||
cursor_effort["profiles"]["cursor-agent"]["low"]["reasoningEffort"] = "low"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "Cursor requires null"):
|
||||
orc_profiles.validate_config(cursor_effort)
|
||||
|
||||
mislabeled_cursor = copy.deepcopy(base)
|
||||
mislabeled_cursor["profiles"]["cursor-agent"]["low"]["model"] = (
|
||||
"gpt-5.6-sol-high"
|
||||
)
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "encode the low"):
|
||||
orc_profiles.validate_config(mislabeled_cursor)
|
||||
|
||||
project_specific = copy.deepcopy(base)
|
||||
project_specific["worktreePolicy"] = ["."]
|
||||
with self.assertRaisesRegex(
|
||||
orc_profiles.ConfigError,
|
||||
"registered-same-repository",
|
||||
):
|
||||
orc_profiles.validate_config(project_specific)
|
||||
|
||||
default_cli = copy.deepcopy(base)
|
||||
default_cli["cliPolicy"] = "default-codex"
|
||||
with self.assertRaisesRegex(orc_profiles.ConfigError, "current-host"):
|
||||
orc_profiles.validate_config(default_cli)
|
||||
|
||||
def test_config_reader_rejects_symlinks_and_redacts_parser_input(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
@@ -282,16 +391,11 @@ class OrcSkillTests(unittest.TestCase):
|
||||
malformed = root / "malformed.yaml"
|
||||
secret_marker = "PRIVATE_MATERIAL_MUST_NOT_APPEAR"
|
||||
malformed.write_text(f"{secret_marker}: [unterminated\n", encoding="utf-8")
|
||||
completed = subprocess.run(
|
||||
[sys.executable, str(SCRIPT), "validate", str(malformed)],
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=False,
|
||||
)
|
||||
self.assertEqual(completed.returncode, 1)
|
||||
self.assertNotIn(secret_marker, completed.stderr)
|
||||
with self.assertRaises(orc_profiles.ConfigError) as error:
|
||||
orc_profiles.load_config(malformed)
|
||||
self.assertNotIn(secret_marker, str(error.exception))
|
||||
|
||||
def test_bound_plan_enforces_registered_allowlisted_worktree(self) -> None:
|
||||
def test_bound_plan_enforces_registered_same_repository_worktree(self) -> None:
|
||||
git = shutil.which("git")
|
||||
self.assertIsNotNone(git)
|
||||
assert git is not None
|
||||
@@ -306,13 +410,14 @@ class OrcSkillTests(unittest.TestCase):
|
||||
check=True,
|
||||
capture_output=True,
|
||||
)
|
||||
config_path = root / "docs" / "orc" / "config.yaml"
|
||||
config_path.parent.mkdir(parents=True)
|
||||
config_path.write_text(CONFIG.read_text(encoding="utf-8"), encoding="utf-8")
|
||||
fake_codex = root / "trusted-codex" / "codex"
|
||||
fake_codex.parent.mkdir()
|
||||
fake_codex.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8")
|
||||
fake_codex.chmod(0o700)
|
||||
fake_cursor = root / "trusted-cursor" / "cursor-agent"
|
||||
fake_cursor.parent.mkdir()
|
||||
fake_cursor.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8")
|
||||
fake_cursor.chmod(0o700)
|
||||
fake_orca = root / "trusted-orca" / "orca"
|
||||
fake_orca.parent.mkdir()
|
||||
fake_orca.write_text("#!/bin/sh\nexit 0\n", encoding="utf-8")
|
||||
@@ -322,9 +427,20 @@ class OrcSkillTests(unittest.TestCase):
|
||||
return {
|
||||
"git": git_path,
|
||||
"codex": fake_codex,
|
||||
"cursor-agent": fake_cursor,
|
||||
"orca": fake_orca,
|
||||
}[name]
|
||||
|
||||
def executable_facts(path: Path) -> dict[str, object]:
|
||||
return {
|
||||
"path": str(path),
|
||||
"device": 1,
|
||||
"inode": 2,
|
||||
"size": 3,
|
||||
"mtimeNs": 4,
|
||||
"version": f"{path.name}-test 1",
|
||||
}
|
||||
|
||||
with (
|
||||
mock.patch.object(
|
||||
orc_profiles,
|
||||
@@ -339,25 +455,33 @@ class OrcSkillTests(unittest.TestCase):
|
||||
mock.patch.object(
|
||||
orc_profiles,
|
||||
"_executable_facts",
|
||||
return_value={
|
||||
"path": str(fake_codex),
|
||||
"device": 1,
|
||||
"inode": 2,
|
||||
"size": 3,
|
||||
"mtimeNs": 4,
|
||||
"version": "codex-test 1",
|
||||
},
|
||||
side_effect=executable_facts,
|
||||
),
|
||||
):
|
||||
plan = orc_profiles.build_launch_plan(
|
||||
config_path,
|
||||
project_root=root,
|
||||
worktree=root,
|
||||
stage="code",
|
||||
host_cli="codex",
|
||||
stage_level="high",
|
||||
)
|
||||
|
||||
cursor_plan = orc_profiles.build_launch_plan(
|
||||
project_root=root,
|
||||
worktree=root,
|
||||
stage="release",
|
||||
host_cli="cursor-agent",
|
||||
stage_level="low",
|
||||
)
|
||||
|
||||
self.assertEqual(plan["argv"][0], str(fake_codex))
|
||||
self.assertEqual(plan["config"]["path"], str(CONFIG))
|
||||
self.assertEqual(cursor_plan["argv"][0], str(fake_cursor))
|
||||
self.assertEqual(cursor_plan["executable"]["path"], str(fake_cursor))
|
||||
self.assertEqual(cursor_plan["argv"][1:3], ["--model", "auto"])
|
||||
self.assertIn("--auto-review", cursor_plan["argv"])
|
||||
self.assertEqual(cursor_plan["modelAuth"], "cursor-login")
|
||||
self.assertIn("--host-cli", cursor_plan["launcherArgv"])
|
||||
self.assertEqual(plan["terminalCreateArgv"][0], str(fake_orca))
|
||||
self.assertEqual(plan["worktree"], str(root))
|
||||
self.assertEqual(plan["selectionSource"], "request.stage")
|
||||
@@ -392,10 +516,10 @@ class OrcSkillTests(unittest.TestCase):
|
||||
):
|
||||
with self.assertRaisesRegex(
|
||||
orc_profiles.ConfigError,
|
||||
"not in allowedWorktrees",
|
||||
"not registered in the project repository",
|
||||
):
|
||||
orc_profiles.validate_worktree(
|
||||
orc_profiles.load_config(config_path),
|
||||
orc_profiles.load_config(CONFIG),
|
||||
project_root_value=root,
|
||||
worktree_value=outside,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user