From 85a566469add5ccb62072cea50d9cd29357250f0 Mon Sep 17 00:00:00 2001 From: Raja Sekhar Rao Dheekonda Date: Tue, 27 Oct 2026 16:06:10 -0700 Subject: [PATCH] fix(ai-red-teaming): ATLAS objective aliases + saner auto-exec backstop - generate_atlas_attack: normalize objective aliases (id<-name/objective_id, goal<-description/objective/prompt) and give a per-object error naming the missing field, instead of rejecting near-miss schemas with a terse message. - _auto_execute_workflow: lower the default subprocess timeout 3600s -> 1200s as a backstop so a stalled run can't block the tool for a full hour. - bump version 1.20.1 -> 1.20.2 for manifest sync. --- capabilities/ai-red-teaming/capability.yaml | 2 +- .../ai-red-teaming/scripts/attack_runner.py | 29 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/capabilities/ai-red-teaming/capability.yaml b/capabilities/ai-red-teaming/capability.yaml index 61f7dfd..d3063b2 100644 --- a/capabilities/ai-red-teaming/capability.yaml +++ b/capabilities/ai-red-teaming/capability.yaml @@ -1,6 +1,6 @@ schema: 1 name: ai-red-teaming -version: "1.20.1" +version: "1.20.2" description: > Probe the security and safety of AI applications, agents, and foundation models. Orchestrates adversarial attack workflows to discover vulnerabilities in LLMs, diff --git a/capabilities/ai-red-teaming/scripts/attack_runner.py b/capabilities/ai-red-teaming/scripts/attack_runner.py index 99b3bf2..a520eb6 100644 --- a/capabilities/ai-red-teaming/scripts/attack_runner.py +++ b/capabilities/ai-red-teaming/scripts/attack_runner.py @@ -117,7 +117,7 @@ def _resolve_platform_env() -> dict[str, str]: return env -def _auto_execute_workflow(filename: str, timeout: int = 3600) -> str: +def _auto_execute_workflow(filename: str, timeout: int = 1200) -> str: """Execute a workflow script and return output. Used for auto-execution after generate.""" filepath = WORKFLOWS_DIR / filename if not filepath.exists(): @@ -7054,16 +7054,27 @@ def generate_atlas_attack(params: dict) -> dict: return { "error": "objectives must be a non-empty list of {id, category, goal} dicts" } - for obj in objectives: - if ( - not isinstance(obj, dict) - or not obj.get("id") - or not obj.get("category") - or not obj.get("goal") - ): + normalized_objectives = [] + for idx, obj in enumerate(objectives): + if not isinstance(obj, dict): + return {"error": f"objective #{idx} must be a dict with 'id', 'category', 'goal'"} + # Accept common aliases so callers don't fail on a near-miss schema. + oid = obj.get("id") or obj.get("name") or obj.get("objective_id") + ocat = obj.get("category") or obj.get("cat") + ogoal = obj.get("goal") or obj.get("description") or obj.get("objective") or obj.get("prompt") + missing = [k for k, v in (("id", oid), ("category", ocat), ("goal", ogoal)) if not v] + if missing: return { - "error": "each objective requires non-empty 'id', 'category', and 'goal' fields" + "error": ( + f"objective #{idx} ({oid or '?'}) missing required field(s): " + f"{', '.join(missing)}. Accepted aliases: id<-name/objective_id, " + "goal<-description/objective/prompt." + ) } + merged = dict(obj) + merged["id"], merged["category"], merged["goal"] = oid, ocat, ogoal + normalized_objectives.append(merged) + objectives = normalized_objectives try: total_budget = int(total_budget) except (TypeError, ValueError):