Sync builder workspaces from managed repo
All checks were successful
build / build (push) Successful in 2s
All checks were successful
build / build (push) Successful in 2s
This commit is contained in:
@@ -7,6 +7,8 @@ import unittest
|
||||
from agent_builder.tools import (
|
||||
_BUILDER_STATE_FILE,
|
||||
_deployment_drift_error,
|
||||
_files_from_tarball,
|
||||
_replace_workspace_files,
|
||||
_render_a2a_init_template,
|
||||
_tarball_workspace_dir,
|
||||
)
|
||||
@@ -40,18 +42,17 @@ class TemplateInitTests(unittest.TestCase):
|
||||
|
||||
self.assertIn("A2AAgent", files["agent.py"])
|
||||
|
||||
def test_deployment_drift_error_blocks_stale_workspace(self) -> None:
|
||||
def test_deployment_drift_error_blocks_untracked_existing_workspace(self) -> None:
|
||||
latest = {"deploy_id": "dpl_1", "head_sha": "abc1234"}
|
||||
|
||||
err = _deployment_drift_error("demo-agent", latest, {}, force=False)
|
||||
|
||||
self.assertIsNotNone(err)
|
||||
assert err is not None
|
||||
self.assertEqual(err["error"], "workspace_drift")
|
||||
self.assertEqual(err["error"], "workspace_untracked")
|
||||
self.assertEqual(err["current_head_sha"], "abc1234")
|
||||
self.assertIsNone(err["workspace_base_head_sha"])
|
||||
|
||||
def test_deployment_drift_error_allows_matching_or_forced_workspace(self) -> None:
|
||||
def test_deployment_drift_error_allows_tracked_or_forced_workspace(self) -> None:
|
||||
latest = {"deploy_id": "dpl_1", "head_sha": "abc1234"}
|
||||
|
||||
self.assertIsNone(
|
||||
@@ -62,6 +63,14 @@ class TemplateInitTests(unittest.TestCase):
|
||||
force=False,
|
||||
)
|
||||
)
|
||||
self.assertIsNone(
|
||||
_deployment_drift_error(
|
||||
"demo-agent",
|
||||
latest,
|
||||
{"repo_head_sha": "repohead999"},
|
||||
force=False,
|
||||
)
|
||||
)
|
||||
self.assertIsNone(
|
||||
_deployment_drift_error(
|
||||
"demo-agent",
|
||||
@@ -83,6 +92,38 @@ class TemplateInitTests(unittest.TestCase):
|
||||
with tarfile.open(fileobj=io.BytesIO(bundle), mode="r:gz") as tf:
|
||||
self.assertEqual(tf.getnames(), ["agent.py"])
|
||||
|
||||
def test_files_from_tarball_rejects_unsafe_paths(self) -> None:
|
||||
bundle = _tarball({"../agent.py": "bad"})
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
_files_from_tarball(bundle)
|
||||
|
||||
def test_replace_workspace_files_deletes_stale_objects(self) -> None:
|
||||
prefix = "agents/demo-agent/"
|
||||
s3 = _FakeS3({
|
||||
prefix + "old.py": b"old",
|
||||
prefix + _BUILDER_STATE_FILE: b"{}",
|
||||
})
|
||||
|
||||
written = _replace_workspace_files(
|
||||
s3,
|
||||
"bucket",
|
||||
prefix,
|
||||
{"agent.py": b"print('ok')\n", "a2a.yaml": b"name: demo-agent\n"},
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
sorted(s3.objects),
|
||||
[prefix + "a2a.yaml", prefix + "agent.py"],
|
||||
)
|
||||
self.assertEqual(
|
||||
written,
|
||||
[
|
||||
{"path": "a2a.yaml", "size": len(b"name: demo-agent\n")},
|
||||
{"path": "agent.py", "size": len(b"print('ok')\n")},
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def _tarball(files: dict[str, str]) -> bytes:
|
||||
buf = io.BytesIO()
|
||||
@@ -106,6 +147,20 @@ class _FakeS3:
|
||||
def get_object(self, *, Bucket: str, Key: str) -> dict[str, io.BytesIO]:
|
||||
return {"Body": io.BytesIO(self.objects[Key])}
|
||||
|
||||
def put_object(
|
||||
self,
|
||||
*,
|
||||
Bucket: str,
|
||||
Key: str,
|
||||
Body: bytes,
|
||||
ContentType: str,
|
||||
) -> None:
|
||||
self.objects[Key] = bytes(Body)
|
||||
|
||||
def delete_objects(self, *, Bucket: str, Delete: dict[str, object]) -> None:
|
||||
for obj in Delete["Objects"]: # type: ignore[index]
|
||||
self.objects.pop(obj["Key"], None)
|
||||
|
||||
|
||||
class _FakePaginator:
|
||||
def __init__(self, objects: dict[str, bytes]) -> None:
|
||||
|
||||
Reference in New Issue
Block a user