Skip to content

Commit 1a0e8ce

Browse files
committed
test(e2e): guard credential-delivery tests on server runtimeMetadata support
Released agentspan servers (through v0.4.2) do not implement the TaskDef.runtimeMetadata credential-delivery contract (conductor-oss PR #1255) — they drop the field — so worker credential injection cannot work there, and the credential-delivery e2e tests would fail for a server-version reason unrelated to the SDK. Add a server-capability probe (does a registered TaskDef.runtimeMetadata persist?) and a `requires_runtime_metadata` fixture that skips the credential-delivery tests when unsupported. Applied to suite26 TestWorkerCredentials, suite2 test_credential_lifecycle, suite3 test_cli_credential_lifecycle. The CLI spawn-safety test is left unguarded (server-independent). Verified both ways: against the dev server (supports it) the tests RUN and pass; against v0.4.2 (does not) they SKIP with a TODO to bump AGENTSPAN_VERSION once a release ships runtimeMetadata.
1 parent 27b7a46 commit 1a0e8ce

4 files changed

Lines changed: 63 additions & 0 deletions

File tree

e2e/conftest.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,63 @@ def get_task_by_name(execution_id: str, task_ref_prefix: str) -> list:
151151
for t in wf.get("tasks", [])
152152
if task_ref_prefix in t.get("referenceTaskName", "")
153153
]
154+
155+
156+
# ── Server capability: TaskDef.runtimeMetadata (conductor-oss PR #1255) ──
157+
#
158+
# Worker credential delivery relies on the server persisting a worker's declared
159+
# TaskDef.runtimeMetadata and delivering the resolved values on Task.runtimeMetadata
160+
# at poll time. Released servers (through v0.4.2) do NOT implement this yet — they
161+
# drop the field — so the credential-delivery e2e tests would fail there for a
162+
# reason unrelated to the SDK. Probe the running server once and skip those tests
163+
# when unsupported.
164+
#
165+
# TODO: once agentspan cuts a release that implements runtimeMetadata, bump
166+
# AGENTSPAN_VERSION in .github/workflows/agent-e2e.yml — this guard then lets the
167+
# credential tests run automatically (no test change needed).
168+
169+
_RUNTIME_METADATA_SUPPORT = None
170+
171+
172+
def _probe_runtime_metadata_support() -> bool:
173+
import uuid
174+
175+
name = f"_rtmd_cap_probe_{uuid.uuid4().hex[:8]}"
176+
try:
177+
r = requests.post(
178+
f"{BASE_URL}/api/metadata/taskdefs",
179+
json=[{"name": name, "runtimeMetadata": ["PROBE"],
180+
"retryCount": 0, "timeoutSeconds": 0}],
181+
timeout=8,
182+
)
183+
if r.status_code not in (200, 204):
184+
return False
185+
g = requests.get(f"{BASE_URL}/api/metadata/taskdefs/{name}", timeout=8)
186+
return g.status_code == 200 and g.json().get("runtimeMetadata") == ["PROBE"]
187+
except Exception:
188+
return False
189+
finally:
190+
try:
191+
requests.delete(f"{BASE_URL}/api/metadata/taskdefs/{name}", timeout=5)
192+
except Exception:
193+
pass
194+
195+
196+
def _server_supports_runtime_metadata() -> bool:
197+
global _RUNTIME_METADATA_SUPPORT
198+
if _RUNTIME_METADATA_SUPPORT is None:
199+
_RUNTIME_METADATA_SUPPORT = _probe_runtime_metadata_support()
200+
return _RUNTIME_METADATA_SUPPORT
201+
202+
203+
@pytest.fixture
204+
def requires_runtime_metadata():
205+
"""Skip a test unless the server implements the TaskDef.runtimeMetadata
206+
credential-delivery contract (conductor-oss PR #1255)."""
207+
if not _server_supports_runtime_metadata():
208+
pytest.skip(
209+
"server does not persist/deliver TaskDef.runtimeMetadata "
210+
"(conductor-oss PR #1255) — worker credential injection requires it. "
211+
"TODO: bump AGENTSPAN_VERSION in .github/workflows/agent-e2e.yml once a "
212+
"release ships runtimeMetadata support."
213+
)

e2e/test_suite26_worker_credentials.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ def _get_taskdef(name: str) -> dict | None:
126126

127127

128128
@pytest.mark.timeout(300)
129+
@pytest.mark.usefixtures("requires_runtime_metadata")
129130
class TestWorkerCredentials:
130131
def test_credential_injected_via_runtime_metadata(self, runtime, model):
131132
"""The tool receives the server-resolved secret (Task.runtimeMetadata)."""

e2e/test_suite2_tool_calling.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ def _get_output_text(result) -> str:
295295
class TestSuite2ToolCalling:
296296
"""Credential lifecycle: missing -> env ignored -> add -> update."""
297297

298+
@pytest.mark.usefixtures("requires_runtime_metadata")
298299
def test_credential_lifecycle(self, runtime, cli_credentials, model):
299300
"""Full credential lifecycle test — sequential steps with cleanup."""
300301
try:

e2e/test_suite3_cli_tools.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ def _assert_run_completed(result, step_name: str):
240240
class TestSuite3CliTools:
241241
"""CLI tools: credential lifecycle + command whitelist."""
242242

243+
@pytest.mark.usefixtures("requires_runtime_metadata")
243244
def test_cli_credential_lifecycle(self, runtime, cli_credentials, model):
244245
"""Full CLI credential lifecycle — sequential steps with cleanup."""
245246
real_token = os.environ.get("GITHUB_TOKEN")

0 commit comments

Comments
 (0)