Harden transports and state files

- Executors and relay helpers get an environment without any configured
  Plane token / webhook secret (design 8: executors hold no Plane credentials).
- Windows runner: Set-Location -LiteralPath, and a failed cd writes exit=97
  instead of running the agent in the wrong directory.
- schtasks launch: escape apostrophes and pass the script path as \"...\" so
  paths with spaces survive PowerShell 5.1 native quoting.
- State and heartbeat files are written temp + fsync + rename.
- Tests for the above plus codex run/resume command shapes and unique run dirs.
This commit is contained in:
jj.wang
2026-10-21 07:10:41 +00:00
parent 08e3a7cc55
commit 00d42267e5
5 changed files with 163 additions and 14 deletions
+122
View File
@@ -0,0 +1,122 @@
"""Transport hardening: secrets never reach executors, Windows script quoting, command shapes, atomic state files."""
import json
import os
import tempfile
import time
import unittest
from pathlib import Path
from unittest import mock
from agentd import ROOT, config
from agentd.config import Config
from agentd.executors import Run, make_executor
from agentd.store import Store
from agentd.transports.local import LocalTransport
from agentd.transports.warpgate_ssh import WarpgateSshTransport
from tests.fakes import config_data
class RecordingWin(WarpgateSshTransport):
"""Windows transport with the relay replaced by an in-memory recorder."""
def __init__(self, cfg, terminal):
super().__init__(cfg, terminal)
self.files, self.launched = {}, []
def mkdir(self, path, clean=False):
pass
def write_text(self, path, text):
self.files[path] = text
def launch(self, task, script_path, run_dir):
self.launched.append((task, script_path, run_dir))
class LocalSecretsTest(unittest.TestCase):
def test_executor_env_has_no_plane_tokens(self):
with tempfile.TemporaryDirectory() as tmp:
data = config_data()
data["agentd"]["state_dir"] = str(Path(tmp) / "state")
data["terminals"]["oregon"]["repo"] = tmp
data["projects"]["GWENT"]["webhook_secret_key"] = "HOOK_GW"
cfg = Config(data)
self.assertEqual(cfg.secret_keys(), {"TOK_OR", "TOK_W10", "HOOK_GW"})
t = LocalTransport(cfg, "oregon")
ex = make_executor(cfg, "oregon", "shell", t)
script = 'echo "or=${TOK_OR:-none} w10=${TOK_W10:-none} hook=${HOOK_GW:-none} keep=${KEEP_ME:-none}"'
with mock.patch.dict(os.environ, {"TOK_OR": "s1", "TOK_W10": "s2", "HOOK_GW": "s3", "KEEP_ME": "yes"}):
h = ex.start(Run("GW-9-1", tmp, "", script=script))
end = time.time() + 10
while ex.poll(h) != "finished" and time.time() < end:
time.sleep(0.05)
self.assertEqual(ex.collect(h).last_message, "or=none w10=none hook=none keep=yes")
class WindowsScriptTest(unittest.TestCase):
def setUp(self):
self.cfg = config.load(ROOT / "config" / "agentd.example.yaml")
self.t = RecordingWin(self.cfg, "win10")
self.ex = make_executor(self.cfg, "win10", "codex", self.t)
def test_codex_run_and_resume_commands(self):
run_dir = self.t.join(self.ex.run_root(), "GW-5-1")
fresh = self.ex.command(Run("GW-5-1", self.t.repo, "p", "gpt-6-astra", "high"), run_dir)
self.assertTrue(fresh.startswith("& 'C:\\Users\\Administrator\\AppData\\Local\\Programs\\OpenAI\\Codex\\bin\\codex.exe' exec --json"))
self.assertIn("-C '%s' -s workspace-write" % self.t.repo, fresh)
self.assertIn("-o '%s\\last.md'" % run_dir, fresh)
resumed = self.ex.command(Run("GW-5-2", self.t.repo, "p", "gpt-6-astra", "high", thread_id="th-9"), run_dir)
self.assertIn(" exec resume th-9 --json -m gpt-6-astra", resumed)
self.assertNotIn(" -C ", resumed) # `codex exec resume` rejects -C/-s; the runner already cd's into the repo
self.assertNotIn(" -s ", resumed)
tiered = self.ex.command(Run("GW-5-3", self.t.repo, "p", "gpt-6.1-sol", "medium", tier="fast"), run_dir)
self.assertIn("-c 'service_tier=\"fast\"'", tiered)
def test_run_dirs_are_unique_per_run(self):
a = self.ex.start(Run("GW-5-1", self.t.repo, "p", "m", "e"))
b = self.ex.start(Run("GW-5-2", self.t.repo, "p", "m", "e"))
self.assertNotEqual(a["run_dir"], b["run_dir"])
self.assertEqual([x[0] for x in self.t.launched], ["agentd-GW-5-1", "agentd-GW-5-2"])
self.assertTrue(a["run_dir"].endswith("\\runtime\\agentd\\GW-5-1"))
def test_runner_quotes_paths_with_spaces_and_apostrophes(self):
_, script = self.t.runner(r"C:\a b\O'Neil\run", r"C:\my repo\O'Neil", "& 'C:\\x\\codex.exe' exec -", "events.jsonl")
self.assertIn(r"Set-Location -LiteralPath 'C:\my repo\O''Neil' -ErrorAction Stop", script)
self.assertIn(r"'C:\a b\O''Neil\run\prompt.md'", script)
self.assertIn(r"'C:\a b\O''Neil\run\exit.txt' -Value ('exit=97", script) # cd failure still ends the run
self.assertIn(r"Add-Content -Path 'C:\a b\O''Neil\run\events.jsonl'", script)
def test_launch_script_quoting(self):
s = self.t.launch_script("agentd-GW-1-1", r"C:\My Docs\O'Neil\run.ps1")
self.assertIn(r"-File \"C:\My Docs\O''Neil\run.ps1\"'", s)
self.assertIn("/TN 'agentd-GW-1-1'", s)
def test_relay_env_has_no_plane_tokens(self):
seen = {}
def fake_run(args, **kw):
seen.update(kw["env"])
return mock.Mock(returncode=0, stdout="X=ok", stderr="")
with mock.patch.dict(os.environ, {"PLANE_WINDOW10_API_TOKEN": "s"}), \
mock.patch("agentd.transports.warpgate_ssh.subprocess.run", fake_run):
WarpgateSshTransport(self.cfg, "win10").ps("'X=ok'")
self.assertNotIn("PLANE_WINDOW10_API_TOKEN", seen)
self.assertIn("WIN10_TIMEOUT", seen)
class StoreTest(unittest.TestCase):
def test_save_is_atomic_and_heartbeat_is_complete_json(self):
with tempfile.TemporaryDirectory() as tmp:
st = Store(tmp, echo=False)
st.save({"projects": {"A": {"issues": {}}}})
with mock.patch("agentd.store.os.replace", side_effect=OSError("disk full")):
with self.assertRaises(OSError):
st.save({"projects": {"B": {}}})
self.assertIn("A", st.load()["projects"]) # old state survives a failed write
st.heartbeat({"errors": [], "inflight": []})
hb = json.loads((Path(tmp) / "heartbeat.json").read_text())
self.assertEqual(hb["errors"], [])
self.assertIn("ts", hb)
if __name__ == "__main__":
unittest.main()