mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
fix(plane): runner drops the fields ax's server sets before validating
On the live cluster ax hands AX_TASK_YAML with metadata.creationTimestamp and a status block; the strict authoring schema rejected it, readiness never turned green and every resume timed out. Other unknown fields still fail. up.sh retries the first resume while the golden snapshot builds. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8e6485e577
commit
2e7e0550b2
+1
-1
@@ -66,7 +66,7 @@ step "smoke task"
|
|||||||
ax delete task ousast-smoke >/dev/null 2>&1 || true
|
ax delete task ousast-smoke >/dev/null 2>&1 || true
|
||||||
envsubst < "$(dirname "$0")/smoke-task.yaml.tmpl" > "$SRC/smoke-task.yaml"
|
envsubst < "$(dirname "$0")/smoke-task.yaml.tmpl" > "$SRC/smoke-task.yaml"
|
||||||
ax apply -f "$SRC/smoke-task.yaml"
|
ax apply -f "$SRC/smoke-task.yaml"
|
||||||
ax resume task ousast-smoke || true
|
for i in 1 2 3 4 5 6; do ax resume task ousast-smoke && break; sleep 20; done # first resume may time out while the golden snapshot builds
|
||||||
ax get tasks
|
ax get tasks
|
||||||
|
|
||||||
step "footprint"
|
step "footprint"
|
||||||
|
|||||||
@@ -119,6 +119,21 @@ class DeliveryError(RuntimeError):
|
|||||||
|
|
||||||
# --- manifests ---------------------------------------------------------------------------------------------------
|
# --- manifests ---------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Fields ax's API server sets on what it hands the runner (ax.proto: ObjectMeta.creation_timestamp, Task.status).
|
||||||
|
# They are not authoring fields, so they are dropped before the strict schema sees the document; any other
|
||||||
|
# unknown field still fails.
|
||||||
|
_SERVER_META = ("creationTimestamp", "creation_timestamp")
|
||||||
|
|
||||||
|
|
||||||
|
def _without_server_fields(document: object) -> object:
|
||||||
|
if not isinstance(document, dict):
|
||||||
|
return document
|
||||||
|
cleaned = {k: v for k, v in document.items() if k != "status"}
|
||||||
|
meta = cleaned.get("metadata")
|
||||||
|
if isinstance(meta, dict):
|
||||||
|
cleaned["metadata"] = {k: v for k, v in meta.items() if k not in _SERVER_META}
|
||||||
|
return cleaned
|
||||||
|
|
||||||
|
|
||||||
def load_task(text: str) -> Task:
|
def load_task(text: str) -> Task:
|
||||||
"""Parse ``AX_TASK_YAML``; raise :class:`RunnerError` unless it is exactly one Task."""
|
"""Parse ``AX_TASK_YAML``; raise :class:`RunnerError` unless it is exactly one Task."""
|
||||||
@@ -129,7 +144,7 @@ def load_task(text: str) -> Task:
|
|||||||
if len(documents) != 1:
|
if len(documents) != 1:
|
||||||
raise RunnerError(f"AX_TASK_YAML must hold exactly one Task document, found {len(documents)}")
|
raise RunnerError(f"AX_TASK_YAML must hold exactly one Task document, found {len(documents)}")
|
||||||
try:
|
try:
|
||||||
manifest = parse_manifest(documents[0], source="AX_TASK_YAML")
|
manifest = parse_manifest(_without_server_fields(documents[0]), source="AX_TASK_YAML")
|
||||||
except ManifestError as exc:
|
except ManifestError as exc:
|
||||||
raise RunnerError(str(exc)) from exc
|
raise RunnerError(str(exc)) from exc
|
||||||
if not isinstance(manifest, Task):
|
if not isinstance(manifest, Task):
|
||||||
@@ -146,7 +161,7 @@ def load_workspaces(text: str) -> dict[str, Workspace]:
|
|||||||
workspaces: dict[str, Workspace] = {}
|
workspaces: dict[str, Workspace] = {}
|
||||||
for index, document in enumerate(documents):
|
for index, document in enumerate(documents):
|
||||||
try:
|
try:
|
||||||
manifest = parse_manifest(document, source=f"AX_WORKSPACES_YAML[{index}]")
|
manifest = parse_manifest(_without_server_fields(document), source=f"AX_WORKSPACES_YAML[{index}]")
|
||||||
except ManifestError as exc:
|
except ManifestError as exc:
|
||||||
raise RunnerError(str(exc)) from exc
|
raise RunnerError(str(exc)) from exc
|
||||||
if not isinstance(manifest, Workspace):
|
if not isinstance(manifest, Workspace):
|
||||||
|
|||||||
@@ -590,3 +590,22 @@ def test_git_commits_annotation_round_trips_to_the_checkout(
|
|||||||
checkout = workspace / "code"
|
checkout = workspace / "code"
|
||||||
assert git("rev-parse", "HEAD", cwd=checkout) == pin, "the pinned commit, not the branch tip"
|
assert git("rev-parse", "HEAD", cwd=checkout) == pin, "the pinned commit, not the branch tip"
|
||||||
assert (checkout / "hello.py").read_text() == "print('v1')\n"
|
assert (checkout / "hello.py").read_text() == "print('v1')\n"
|
||||||
|
|
||||||
|
|
||||||
|
def test_the_runner_accepts_what_ax_hands_it() -> None:
|
||||||
|
"""ax's server adds metadata.creationTimestamp and status (live cluster, 2026-09-29); other fields stay strict."""
|
||||||
|
from openultrasast.plane.runner import RunnerError, load_task, load_workspaces
|
||||||
|
|
||||||
|
task = load_task(
|
||||||
|
"apiVersion: ax.io/v1alpha1\nkind: Task\nmetadata:\n name: t\n atespace: default\n"
|
||||||
|
" creationTimestamp: '2026-09-29T17:11:58Z'\nspec:\n command: [repo-facts]\n"
|
||||||
|
"status:\n phase: Running\n id: task-t-1\n"
|
||||||
|
)
|
||||||
|
assert task.metadata.name == "t"
|
||||||
|
spaces = load_workspaces(
|
||||||
|
"apiVersion: ax.io/v1alpha1\nkind: Workspace\nmetadata:\n name: w\n"
|
||||||
|
" creationTimestamp: '2026-09-29T17:11:58Z'\nspec:\n files:\n - path: a.py\n content: x\n"
|
||||||
|
)
|
||||||
|
assert list(spaces) == ["w"]
|
||||||
|
with pytest.raises(RunnerError, match="uid"):
|
||||||
|
load_task("apiVersion: ax.io/v1alpha1\nkind: Task\nmetadata:\n name: t\n uid: x\nspec: {}\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user