Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion arbiter/fabricator/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -2666,10 +2666,13 @@ def store_agent_config_registry_bound(
agent_id=agent_use_id, agent_name=agent_use_id,
registration_errors=registration_errors,
org_id=org_id,
# Always write registryApprovalStatus on COMPLETED jobs so the
# intake status-check never falls back to a dangerous default.
# Priority: pending_approval > draft > approved.
registry_approval_status=(
"pending_approval"
if run_state is not None and run_state.pending_approval
else None
else "approved"
),
)

Expand Down
2 changes: 1 addition & 1 deletion service/agent_intake_single/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
bedrock-agentcore>=1.18.1
strands-agents[otel]>=1.50.1
fastapi>=0.140.0
boto3>=1.43.56
boto3==1.43.116
python-dotenv>=1.2.2
requests>=2.34.2
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Container-level smoke test: botocore ships the agent-registry-control service model.

This test MUST be run with the pinned dependencies from requirements.txt
(e.g. inside the container image or a venv created from that file). It will
fail in any environment whose botocore predates the agent-registry-control
service model — that is intentional: a failing build proves the image would
raise UnknownServiceError at runtime.
"""

import botocore
from botocore.session import get_session


def test_agent_registry_control_is_available():
"""botocore must include the agent-registry-control service model."""
session = get_session()
available = session.get_available_services()
assert "agent-registry-control" in available, (
f"botocore {botocore.__version__} does not include "
f"'agent-registry-control' — pin boto3/botocore to a version "
f"that ships this service model (>= 1.43.116 known good)"
)
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,13 @@ def test_pending_approval_agent_state_reads_awaiting(
def test_approved_agent_state_reads_built_and_approved(
self, jobs_table, marker_store,
):
items = [_job("AgentA", "COMPLETED")] # no registryApprovalStatus = auto-approved
items = [_job("AgentA", "COMPLETED")] # no registryApprovalStatus = unknown
result = _run_status(jobs_table, items, marker_store)

states = {a["name"]: a["state"] for a in result["agents"]}
assert states["AgentA"] == "built and approved"
# Without an explicit registryApprovalStatus, the fallback is
# "could not be confirmed" — never "approved" by default.
assert states["AgentA"] == "built; approval status could not be confirmed"

def test_mixed_approved_and_pending_partial_like(
self, jobs_table, marker_store,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,9 @@ def test_registry_unset_falls_back_to_snapshot(

result = _run_status(jobs_table, items, marker_store)

# No REGISTRY_ID -> assume auto-approved (legacy behavior)
# No REGISTRY_ID -> no live lookup, no snapshot -> "could not be confirmed"
states = {a["name"]: a["state"] for a in result["agents"]}
assert states["AgentA"] == "built and approved"
assert states["AgentA"] == "built; approval status could not be confirmed"


# ===========================================================================
Expand Down Expand Up @@ -459,9 +459,9 @@ def test_only_first_five_agents_resolved(
states = {a["name"]: a["state"] for a in result["agents"]}
for n in names[:5]:
assert states[n] == "built and approved"
# Last 2 get snapshot fallback (no registryApprovalStatus = auto-approved)
# Last 2 get snapshot fallback (no registryApprovalStatus = "could not be confirmed")
for n in names[5:]:
assert states[n] == "built and approved"
assert states[n] == "built; approval status could not be confirmed"


# ===========================================================================
Expand Down
15 changes: 11 additions & 4 deletions service/agent_intake_single/tools/postfab.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,13 @@ def _resolve_registry_status(agent_name: str, org_id: str) -> str | None:
return summary.get("status")
return None
except Exception as e:
logger.warning(
"registry status lookup failed agent=%s: %s",
agent_name, type(e).__name__,
# Log at ERROR (not warning) so CloudWatch metric filters can alert
# on registry-client unavailability — the fallback path must never
# silently default to 'approved'.
logger.error(
"registry_status_lookup_failed agent=%s error_type=%s: %s "
"(approval status will show 'could not be confirmed')",
agent_name, type(e).__name__, e,
)
return None

Expand Down Expand Up @@ -205,7 +209,10 @@ def _plain_state(item: dict, live_status: str | None = None) -> str:
approval = item.get("registryApprovalStatus")
if approval == "pending_approval":
return _APPROVAL_PLAIN["pending_approval"]
return _APPROVAL_PLAIN.get(approval, "built and approved")
if approval == "approved":
return _APPROVAL_PLAIN["approved"]
# Unknown or absent approval status — never default to "approved".
return "built; approval status could not be confirmed"
return _STATUS_PLAIN.get(status, "in an unknown state")


Expand Down
Loading