feat(ack): add grok workers and allow --always-approve

Grok is a first-class worker CLI. Launcher argv includes --always-approve so
unattended tool calls are not blocked; sandbox stays required.
This commit is contained in:
2026-08-23 19:08:54 +08:00
parent c113f68bf4
commit 7dfdf80e9e
28 changed files with 679 additions and 78 deletions
+37
View File
@@ -303,6 +303,7 @@ class AckDeliveryValidationTests(unittest.TestCase):
{
"enabled": False,
"defaultProfile": None,
"intents": {"testEnvironment": None, "release": None},
"entrypoints": {},
"artifacts": {},
"destinations": {},
@@ -313,6 +314,42 @@ class AckDeliveryValidationTests(unittest.TestCase):
self.assertEqual(validate_delivery.validate_builtin(contract), [])
def test_intents_must_point_at_matching_stop_points(self) -> None:
contract = valid_contract()
contract["intents"] = {
"testEnvironment": "review",
"release": None,
}
errors = validate_delivery.validate_builtin(contract)
self.assertTrue(
any("intents.testEnvironment" in item and "validation_ready" in item for item in errors)
)
contract["intents"]["testEnvironment"] = "local-validation"
contract["profiles"]["local-validation"] = {
"stopAt": "validation_ready",
"steps": [
{"id": "build-local", "action": "build", "artifact": "service-deb"},
{
"id": "deploy-local",
"action": "deploy",
"artifact": "service-deb",
"environment": "test-server",
},
{
"id": "health-local",
"action": "health-check",
"environment": "test-server",
},
],
}
self.assertEqual(validate_delivery.validate_builtin(contract), [])
contract["intents"]["release"] = "missing-release"
errors = validate_delivery.validate_builtin(contract)
self.assertTrue(any("未定义 profile 'missing-release'" in item for item in errors))
if __name__ == "__main__":
unittest.main()
+59 -2
View File
@@ -324,6 +324,9 @@ class EnvironmentAndExecutableTests(unittest.TestCase):
"OPENAI_API_KEY": "test-token",
"AZURE_OPENAI_API_KEY": "azure-token",
"CURSOR_API_KEY": "cursor-token",
"XAI_API_KEY": "xai-token",
"GROK_HOME": "/tmp/evil-grok",
"GROK_SANDBOX": "off",
"ANTHROPIC_API_KEY": "anthropic-token",
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/tmp/dbus",
"DISPLAY": ":99",
@@ -336,17 +339,24 @@ class EnvironmentAndExecutableTests(unittest.TestCase):
control = launch_worker.control_environment()
codex = launch_worker.worker_environment("codex")
cursor = launch_worker.worker_environment("cursor-agent")
grok = launch_worker.worker_environment("grok")
for environment in (control, codex, cursor):
for environment in (control, codex, cursor, grok):
self.assertNotIn(hostile_path, environment["PATH"].split(os.pathsep))
self.assertEqual(environment["LANG"], "C.UTF-8")
self.assertNotIn("OPENAI_API_KEY", control)
self.assertNotIn("CURSOR_API_KEY", control)
self.assertNotIn("XAI_API_KEY", control)
self.assertEqual(codex["OPENAI_API_KEY"], "test-token")
self.assertEqual(codex["AZURE_OPENAI_API_KEY"], "azure-token")
self.assertNotIn("CURSOR_API_KEY", codex)
self.assertNotIn("XAI_API_KEY", codex)
self.assertEqual(cursor["CURSOR_API_KEY"], "cursor-token")
self.assertNotIn("OPENAI_API_KEY", cursor)
self.assertNotIn("XAI_API_KEY", cursor)
self.assertEqual(grok["XAI_API_KEY"], "xai-token")
self.assertNotIn("OPENAI_API_KEY", grok)
self.assertNotIn("CURSOR_API_KEY", grok)
for forbidden in (
"ANTHROPIC_API_KEY",
"DBUS_SESSION_BUS_ADDRESS",
@@ -356,11 +366,13 @@ class EnvironmentAndExecutableTests(unittest.TestCase):
"NODE_OPTIONS",
"PYTHONPATH",
"CODEX_HOME",
"GROK_HOME",
"GROK_SANDBOX",
"GIT_SSH_COMMAND",
"WAYLAND_DISPLAY",
"XDG_RUNTIME_DIR",
):
for environment in (control, codex, cursor):
for environment in (control, codex, cursor, grok):
self.assertNotIn(forbidden, environment)
def test_executable_resolution_ignores_hostile_path(self) -> None:
@@ -373,6 +385,51 @@ class EnvironmentAndExecutableTests(unittest.TestCase):
self.assertEqual(resolved, Path("/usr/bin/git"))
def test_grok_vendor_layout_is_trusted_and_outside_artifacts_are_not(self) -> None:
with tempfile.TemporaryDirectory() as temporary:
home = Path(temporary) / "home"
downloads = home / ".grok" / "downloads"
downloads.mkdir(parents=True)
artifact = downloads / "grok-linux-x86_64"
artifact.write_text("#!/bin/sh\n", encoding="utf-8")
artifact.chmod(0o775)
bindir = home / ".local" / "bin"
bindir.mkdir(parents=True)
(bindir / "grok").symlink_to(artifact)
hostile_dir = Path(temporary) / "tmp"
hostile_dir.mkdir()
hostile = hostile_dir / "grok-linux-x86_64"
hostile.write_text("#!/bin/sh\n", encoding="utf-8")
hostile.chmod(0o775)
hostile_bin = Path(temporary) / "hostile-bin"
hostile_bin.mkdir()
(hostile_bin / "grok").symlink_to(hostile)
with mock.patch.object(
launch_worker,
"account_identity",
return_value=(home.resolve(strict=True), "ace"),
), mock.patch.object(
launch_worker,
"trusted_path_entries",
return_value=[bindir.resolve(strict=True)],
):
resolved = launch_worker.resolve_executable("grok")
self.assertEqual(resolved, artifact.resolve(strict=True))
with mock.patch.object(
launch_worker,
"account_identity",
return_value=(home.resolve(strict=True), "ace"),
), mock.patch.object(
launch_worker,
"trusted_path_entries",
return_value=[hostile_bin.resolve(strict=True)],
):
with self.assertRaises(launch_worker.LaunchError):
launch_worker.resolve_executable("grok")
class PlanTests(unittest.TestCase):
def test_authoritative_board_is_derived_from_project_root_without_repo_path(self) -> None:
+4 -1
View File
@@ -27,6 +27,9 @@ class AckSkillContentTests(unittest.TestCase):
"references/kickoff.md",
"不要修改项目的 `AGENTS.md`",
"当前会话担任 Coordinator",
"intents.testEnvironment",
"运行测试环境",
"运行版本发布",
):
self.assertIn(expected, content)
@@ -128,7 +131,7 @@ class AckSkillContentTests(unittest.TestCase):
):
self.assertTrue((ack_dir / relative_path).is_file(), relative_path)
version = (ack_dir / "VERSION").read_text(encoding="utf-8").strip()
self.assertEqual(version, "0.15.0")
self.assertEqual(version, "0.17.1")
self.assertIn(
f'ackVersion: "{version}"',
(ack_dir / "examples" / "tasks.example.yaml").read_text(encoding="utf-8"),
+41
View File
@@ -438,6 +438,47 @@ class AckTaskValidationTests(unittest.TestCase):
self.assert_board_accepted_in_all_modes(board)
def test_intent_delivery_run_allows_empty_task_ids(self) -> None:
board = valid_manual_routing_board()
board["project"]["deliveryFile"] = "docs/ack/delivery.yaml"
board["deliveryRuns"] = [
{
"id": "DR-test-env-1",
"profile": "test-local",
"intent": "testEnvironment",
"taskIds": [],
"status": "validation_ready",
"sourceRevision": "a" * 40,
"configRevision": "b" * 40,
"pullRequest": None,
"artifacts": [
{
"id": "garden-bin",
"type": "file",
"reference": "garden",
"digest": "sha256:" + "c" * 64,
}
],
"deployments": [
{
"environment": "local-write",
"result": "succeeded",
"evidence": "GET /login returned 200",
}
],
"evidence": ["http://write.localhost:8080/ ready"],
"updatedAt": "2026-08-23T00:57:00+08:00",
}
]
self.assert_board_accepted_in_all_modes(board)
del board["deliveryRuns"][0]["intent"]
self.assert_board_rejected_in_all_modes(
board,
"taskIds: 必须是非空任务 ID 列表",
)
def test_delivery_runs_and_delivery_file_must_appear_together(self) -> None:
board = valid_manual_routing_board()
board["deliveryRuns"] = []
+115
View File
@@ -30,6 +30,13 @@ def valid_orchestration() -> dict:
"developer": {"standard": ["cursor-auto"]},
"test": {"standard": ["cursor-auto"]},
},
"grok": {
"developer": {
"standard": ["grok-4.5"],
"strong": ["grok-4.6"],
},
"test": {"standard": ["grok-4.5"]},
},
},
"profiles": {
"codex-dev-standard": {
@@ -64,6 +71,30 @@ def valid_orchestration() -> dict:
"reasoningEffort": None,
"permissionMode": "workspace-write",
},
"grok-dev-standard": {
"role": "developer",
"cli": "grok",
"tier": "standard",
"model": "grok-4.5",
"reasoningEffort": "medium",
"permissionMode": "workspace-write",
},
"grok-dev-strong": {
"role": "developer",
"cli": "grok",
"tier": "strong",
"model": "grok-4.6",
"reasoningEffort": "high",
"permissionMode": "workspace-write",
},
"grok-test-readonly": {
"role": "test",
"cli": "grok",
"tier": "standard",
"model": "grok-4.5",
"reasoningEffort": "low",
"permissionMode": "read-only",
},
},
"defaults": {
"developer": "codex-dev-standard",
@@ -278,12 +309,16 @@ class ProfileValidationTests(unittest.TestCase):
codex["profiles"]["codex-dev-standard"]["reasoningEffort"] = None
cursor = valid_orchestration()
cursor["profiles"]["cursor-test-standard"]["reasoningEffort"] = "low"
grok = valid_orchestration()
grok["profiles"]["grok-dev-standard"]["reasoningEffort"] = None
codex_errors = worker_profiles.validate_orchestration(codex)
cursor_errors = worker_profiles.validate_orchestration(cursor)
grok_errors = worker_profiles.validate_orchestration(grok)
self.assertTrue(any("Codex requires" in error for error in codex_errors))
self.assertTrue(any("Cursor requires null" in error for error in cursor_errors))
self.assertTrue(any("Grok requires" in error for error in grok_errors))
def test_test_cannot_use_strong_tier(self) -> None:
routing = valid_orchestration()
@@ -444,6 +479,86 @@ class ArgvRendererTests(unittest.TestCase):
self.assertNotIn("--yolo", argv)
self.assertNotIn("--force", argv)
def test_grok_workspace_write_exact_safe_argv(self) -> None:
profile = valid_orchestration()["profiles"]["grok-dev-standard"]
argv = worker_profiles.render_worker_argv(
profile,
"/usr/local/bin/grok",
"/repo/demo",
)
self.assertEqual(
argv,
[
"/usr/local/bin/grok",
"--model",
"grok-4.5",
"--reasoning-effort",
"medium",
"--permission-mode",
"acceptEdits",
"--always-approve",
"--sandbox",
"workspace",
"--cwd",
"/repo/demo",
],
)
for forbidden in (
"--yolo",
"bypassPermissions",
"auto",
"dontAsk",
"off",
):
self.assertNotIn(forbidden, argv)
def test_grok_read_only_uses_plan_and_read_only_sandbox(self) -> None:
profile = valid_orchestration()["profiles"]["grok-test-readonly"]
argv = worker_profiles.render_worker_argv(
profile,
"/usr/local/bin/grok",
"/repo/demo",
)
self.assertEqual(
argv,
[
"/usr/local/bin/grok",
"--model",
"grok-4.5",
"--reasoning-effort",
"low",
"--permission-mode",
"plan",
"--always-approve",
"--sandbox",
"read-only",
"--cwd",
"/repo/demo",
],
)
self.assertNotIn("--yolo", argv)
self.assertNotIn("bypassPermissions", argv)
def test_grok_accepts_vendor_artifact_basename(self) -> None:
profile = valid_orchestration()["profiles"]["grok-dev-standard"]
artifact = "/home/ace/.grok/downloads/grok-linux-x86_64"
argv = worker_profiles.render_worker_argv(profile, artifact, "/repo/demo")
self.assertEqual(argv[0], artifact)
self.assertTrue(
worker_profiles.executable_basename_matches_cli(artifact, "grok")
)
self.assertFalse(
worker_profiles.executable_basename_matches_cli(
artifact, "cursor-agent"
)
)
def test_renderer_rejects_wrong_executable_or_unsafe_worktree(self) -> None:
profile = valid_orchestration()["profiles"]["codex-dev-standard"]