Skip to content

Commit b6e6abd

Browse files
committed
fix: resolve remaining a2a ci failures
Signed-off-by: lucarlig <luca.carlig@ibm.com>
1 parent 4e4044a commit b6e6abd

File tree

8 files changed

+49
-78
lines changed

8 files changed

+49
-78
lines changed

Containerfile.lite

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ RUN if [ "$ENABLE_RUST" = "true" ]; then \
135135
# Build the experimental Rust A2A runtime binary (only if ENABLE_RUST=true)
136136
RUN if [ "$ENABLE_RUST" = "true" ]; then \
137137
cargo build --release -p contextforge_a2a_runtime && \
138-
cp /build/target/release/contextforge_a2a_runtime /build/target/release/contextforge-a2a-runtime && \
139138
echo "✅ Rust A2A runtime built successfully"; \
140139
else \
141140
echo "⏭️ Skipping Rust A2A runtime build"; \

mcpgateway/main.py

Lines changed: 9 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
from mcpgateway.common.models import ListResourceTemplatesResult, LogLevel, Root
8282
from mcpgateway.common.validators import SecurityValidator
8383
from mcpgateway.config import settings
84-
from mcpgateway.db import refresh_slugs_on_startup, SessionLocal
84+
from mcpgateway.db import A2AAgent as DbA2AAgent, A2APushNotificationConfig, A2ATask as DbA2ATask, refresh_slugs_on_startup, SessionLocal
8585
from mcpgateway.db import Tool as DbTool
8686
from mcpgateway.handlers.sampling import SamplingHandler
8787
from mcpgateway.middleware.compression import SSEAwareCompressMiddleware
@@ -111,6 +111,7 @@
111111
from mcpgateway.schemas import (
112112
A2AAgentCreate,
113113
A2AAgentRead,
114+
A2APushNotificationConfigCreate,
114115
A2AAgentUpdate,
115116
CursorPaginatedA2AAgentsResponse,
116117
CursorPaginatedGatewaysResponse,
@@ -143,6 +144,7 @@
143144
ToolUpdate,
144145
)
145146
from mcpgateway.services.a2a_service import A2AAgentError, A2AAgentNameConflictError, A2AAgentNotFoundError, A2AAgentService
147+
from mcpgateway.services.a2a_server_service import A2AServerService
146148
from mcpgateway.services.cancellation_service import cancellation_service
147149
from mcpgateway.services.completion_service import CompletionService
148150
from mcpgateway.services.content_security import ContentSizeError, ContentTypeError
@@ -8962,19 +8964,12 @@ async def handle_internal_a2a_agent_resolve(request: Request, agent_name: str):
89628964

89638965
db = SessionLocal()
89648966
try:
8965-
# First-Party
8966-
from mcpgateway.db import A2AAgent as DbA2AAgent # pylint: disable=import-outside-toplevel
8967-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
8968-
89698967
user_email, token_teams = _get_internal_a2a_scope_context(request)
89708968
service = A2AAgentService()
8971-
agent = db.query(DbA2AAgent).filter(DbA2AAgent.name == agent_name, DbA2AAgent.enabled == True).first() # noqa: E712
8969+
agent = db.query(DbA2AAgent).filter(DbA2AAgent.name == agent_name, DbA2AAgent.enabled.is_(True)).first()
89728970
if not agent:
8973-
# First-Party
8974-
from mcpgateway.services.a2a_server_service import A2AServerService # pylint: disable=import-outside-toplevel
8975-
8976-
server_service = A2AServerService()
8977-
server_agent = server_service.resolve_server_agent(db, agent_name, user_email=user_email, token_teams=token_teams)
8971+
a2a_server_service = A2AServerService()
8972+
server_agent = a2a_server_service.resolve_server_agent(db, agent_name, user_email=user_email, token_teams=token_teams)
89788973
if server_agent:
89798974
return ORJSONResponse(status_code=200, content=server_agent)
89808975
return ORJSONResponse(status_code=404, content={"error": f"agent '{agent_name}' not found"})
@@ -9023,27 +9018,18 @@ async def handle_internal_a2a_agent_card(request: Request, agent_name: str):
90239018

90249019
db = SessionLocal()
90259020
try:
9026-
# First-Party
9027-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9028-
90299021
user_email, token_teams = _get_internal_a2a_scope_context(request)
90309022
service = A2AAgentService()
90319023

90329024
# Check agent visibility before building the card to avoid loading
90339025
# sensitive relationship data for agents the caller cannot see.
9034-
# First-Party
9035-
from mcpgateway.db import A2AAgent as DbA2AAgent # pylint: disable=import-outside-toplevel
9036-
9037-
agent = db.query(DbA2AAgent).filter(DbA2AAgent.name == agent_name, DbA2AAgent.enabled == True).first() # noqa: E712
9026+
agent = db.query(DbA2AAgent).filter(DbA2AAgent.name == agent_name, DbA2AAgent.enabled.is_(True)).first()
90389027
card = None
90399028
if agent is not None and service._check_agent_access(agent, user_email, token_teams): # pylint: disable=protected-access
90409029
card = service.get_agent_card(db, agent_name)
90419030
if card is None:
9042-
# First-Party
9043-
from mcpgateway.services.a2a_server_service import A2AServerService # pylint: disable=import-outside-toplevel
9044-
9045-
server_service = A2AServerService()
9046-
card = server_service.get_server_agent_card(db, agent_name, user_email=user_email, token_teams=token_teams)
9031+
a2a_server_service = A2AServerService()
9032+
card = a2a_server_service.get_server_agent_card(db, agent_name, user_email=user_email, token_teams=token_teams)
90479033
if card is None:
90489034
return ORJSONResponse(status_code=404, content={"error": f"agent '{agent_name}' not found"})
90499035
return ORJSONResponse(status_code=200, content=card)
@@ -9078,9 +9064,6 @@ async def handle_internal_a2a_tasks_get(request: Request):
90789064
if agent_id is not None and not isinstance(agent_id, str):
90799065
return ORJSONResponse(status_code=400, content={"error": "agent_id must be a string"})
90809066

9081-
# First-Party
9082-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9083-
90849067
user_email, token_teams = _get_internal_a2a_scope_context(request)
90859068
service = A2AAgentService()
90869069
task = service.get_task(db, task_id, agent_id=agent_id, user_email=user_email, token_teams=token_teams)
@@ -9120,9 +9103,6 @@ async def handle_internal_a2a_tasks_list(request: Request):
91209103
limit = min(int(body.get("limit", 100)), 1000)
91219104
offset = max(int(body.get("offset", 0)), 0)
91229105

9123-
# First-Party
9124-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9125-
91269106
user_email, token_teams = _get_internal_a2a_scope_context(request)
91279107
service = A2AAgentService()
91289108
tasks = service.list_tasks(db, agent_id=agent_id, state=state, limit=limit, offset=offset, user_email=user_email, token_teams=token_teams)
@@ -9158,9 +9138,6 @@ async def handle_internal_a2a_tasks_cancel(request: Request):
91589138
if agent_id is not None and not isinstance(agent_id, str):
91599139
return ORJSONResponse(status_code=400, content={"error": "agent_id must be a string"})
91609140

9161-
# First-Party
9162-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9163-
91649141
user_email, token_teams = _get_internal_a2a_scope_context(request)
91659142
service = A2AAgentService()
91669143
task = service.cancel_task(db, task_id, agent_id=agent_id, user_email=user_email, token_teams=token_teams)
@@ -9195,10 +9172,6 @@ async def handle_internal_a2a_push_create(request: Request):
91959172
return ORJSONResponse(status_code=400, content={"error": "a2a_agent_id, task_id, and webhook_url are required"})
91969173

91979174
# Validate webhook URL through the schema to enforce SSRF protection.
9198-
# First-Party
9199-
from mcpgateway.schemas import A2APushNotificationConfigCreate # pylint: disable=import-outside-toplevel
9200-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9201-
92029175
try:
92039176
validated = A2APushNotificationConfigCreate(**body)
92049177
except Exception as validation_err:
@@ -9239,9 +9212,6 @@ async def handle_internal_a2a_push_get(request: Request):
92399212
if not task_id:
92409213
return ORJSONResponse(status_code=400, content={"error": "task_id is required"})
92419214

9242-
# First-Party
9243-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9244-
92459215
user_email, token_teams = _get_internal_a2a_scope_context(request)
92469216
service = A2AAgentService()
92479217
cfg = service.get_push_config(db, task_id, agent_id=agent_id)
@@ -9277,9 +9247,6 @@ async def handle_internal_a2a_push_list(request: Request):
92779247
agent_id = body.get("agent_id")
92789248
task_id = body.get("task_id")
92799249

9280-
# First-Party
9281-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9282-
92839250
user_email, token_teams = _get_internal_a2a_scope_context(request)
92849251
service = A2AAgentService()
92859252
configs = service.list_push_configs(db, agent_id=agent_id, task_id=task_id)
@@ -9314,10 +9281,6 @@ async def handle_internal_a2a_push_delete(request: Request):
93149281
if not config_id:
93159282
return ORJSONResponse(status_code=400, content={"error": "config_id is required"})
93169283

9317-
# First-Party
9318-
from mcpgateway.db import A2APushNotificationConfig # pylint: disable=import-outside-toplevel
9319-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9320-
93219284
user_email, token_teams = _get_internal_a2a_scope_context(request)
93229285
service = A2AAgentService()
93239286
cfg = db.query(A2APushNotificationConfig).filter(A2APushNotificationConfig.id == config_id).first()
@@ -9355,10 +9318,6 @@ async def handle_internal_a2a_events_flush(request: Request):
93559318
if not events:
93569319
return ORJSONResponse(status_code=200, content={"count": 0})
93579320

9358-
# First-Party
9359-
from mcpgateway.db import A2ATask as DbA2ATask # pylint: disable=import-outside-toplevel
9360-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9361-
93629321
user_email, token_teams = _get_internal_a2a_scope_context(request)
93639322
service = A2AAgentService()
93649323

@@ -9403,10 +9362,6 @@ async def handle_internal_a2a_events_replay(request: Request):
94039362
if not task_id:
94049363
return ORJSONResponse(status_code=400, content={"error": "task_id required"})
94059364

9406-
# First-Party
9407-
from mcpgateway.db import A2ATask as DbA2ATask # pylint: disable=import-outside-toplevel
9408-
from mcpgateway.services.a2a_service import A2AAgentService # pylint: disable=import-outside-toplevel
9409-
94109365
user_email, token_teams = _get_internal_a2a_scope_context(request)
94119366
service = A2AAgentService()
94129367
task_row = db.query(DbA2ATask).filter(DbA2ATask.task_id == task_id).first()

mcpgateway/services/a2a_protocol.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,7 @@ def prepare_a2a_invocation(
366366
# If decoding fails (corrupted data, wrong key, invalid encoding, truncated input,
367367
# or invalid nonce/cipher parameters), use the raw value as the API key
368368
#
369-
# TODO: Is this a logic failure? Perhaps the gateway should
370-
# ensure all API Key style auths are encoded -- or vice versa
371-
#
369+
# Keep backward compatibility with older raw API key rows.
372370
headers.setdefault("Authorization", f"Bearer {auth_value}")
373371
else:
374372
decoded = decode_auth(auth_value)

mcpgateway/services/a2a_server_service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def get_server_agent_card(
107107
>>> service.get_server_agent_card(db, "no-such-server") is None
108108
True
109109
"""
110-
server_query = select(DbServer).where(DbServer.name == server_name, DbServer.enabled == True) # noqa: E712
110+
server_query = select(DbServer).where(DbServer.name == server_name, DbServer.enabled.is_(True))
111111
server = db.execute(server_query).scalar_one_or_none()
112112
if not server:
113113
return None
@@ -178,7 +178,7 @@ def resolve_server_agent(
178178
>>> service.resolve_server_agent(db, "no-such-server") is None
179179
True
180180
"""
181-
server_query = select(DbServer).where(DbServer.name == server_name, DbServer.enabled == True) # noqa: E712
181+
server_query = select(DbServer).where(DbServer.name == server_name, DbServer.enabled.is_(True))
182182
server = db.execute(server_query).scalar_one_or_none()
183183
if not server:
184184
return None
@@ -225,7 +225,7 @@ def select_downstream_agent(self, db: Session, server_id: str) -> Optional[str]:
225225
.join(server_a2a_association, server_a2a_association.c.a2a_agent_id == DbA2AAgent.id)
226226
.where(
227227
server_a2a_association.c.server_id == server_id,
228-
DbA2AAgent.enabled == True, # noqa: E712
228+
DbA2AAgent.enabled.is_(True),
229229
)
230230
.order_by(DbA2AAgent.name)
231231
.limit(1)
@@ -331,7 +331,7 @@ def _find_a2a_interface(self, db: Session, server_id: str) -> Optional[DbServerI
331331
select(DbServerInterface)
332332
.where(
333333
DbServerInterface.server_id == server_id,
334-
DbServerInterface.enabled == True, # noqa: E712
334+
DbServerInterface.enabled.is_(True),
335335
func.lower(DbServerInterface.protocol).like("a2a%"),
336336
)
337337
.order_by(DbServerInterface.created_at.desc())

mcpgateway/services/a2a_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ def _visible_agent_ids(
361361
if token_teams is None and user_email is None:
362362
return None
363363

364-
query = db.query(DbA2AAgent.id).filter(DbA2AAgent.enabled == True) # noqa: E712
364+
query = db.query(DbA2AAgent.id).filter(DbA2AAgent.enabled.is_(True))
365365

366366
# Build visibility predicate matching _check_agent_access rules.
367367
visibility_filters = [DbA2AAgent.visibility == "public"]
@@ -1055,7 +1055,7 @@ def get_agent_card(self, db: Session, agent_name: str) -> Optional[Dict[str, Any
10551055
>>> service.get_agent_card(db, "missing") is None
10561056
True
10571057
"""
1058-
query = select(DbA2AAgent).where(DbA2AAgent.name == agent_name, DbA2AAgent.enabled == True) # noqa: E712
1058+
query = select(DbA2AAgent).where(DbA2AAgent.name == agent_name, DbA2AAgent.enabled.is_(True))
10591059
agent = db.execute(query).scalar_one_or_none()
10601060
if not agent:
10611061
return None

tests/unit/mcpgateway/services/test_a2a_service.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3550,6 +3550,7 @@ def test_get_push_config_found(self, service, mock_db):
35503550
cfg = MagicMock()
35513551
mock_query = MagicMock()
35523552
mock_query.filter.return_value = mock_query
3553+
mock_query.order_by.return_value = mock_query
35533554
mock_query.first.return_value = cfg
35543555
mock_db.query.return_value = mock_query
35553556

@@ -3564,6 +3565,7 @@ def test_get_push_config_not_found(self, service, mock_db):
35643565
"""get_push_config returns None when no config exists for the task."""
35653566
mock_query = MagicMock()
35663567
mock_query.filter.return_value = mock_query
3568+
mock_query.order_by.return_value = mock_query
35673569
mock_query.first.return_value = None
35683570
mock_db.query.return_value = mock_query
35693571

@@ -3576,6 +3578,7 @@ def test_get_push_config_with_agent_id(self, service, mock_db):
35763578
cfg = MagicMock()
35773579
mock_query = MagicMock()
35783580
mock_query.filter.return_value = mock_query
3581+
mock_query.order_by.return_value = mock_query
35793582
mock_query.first.return_value = cfg
35803583
mock_db.query.return_value = mock_query
35813584

0 commit comments

Comments
 (0)