Skip to content

Commit 9c728c0

Browse files
committed
fix: Add missing oauth_config and passthrough_headers columns to a2a_agents
PR #1270 added oauth_config and passthrough_headers to the A2AAgent model but forgot to include the database migration. This caused SQLAlchemy errors when querying a2a_agents from older databases. This migration: - Adds oauth_config column (JSON, nullable) - Adds passthrough_headers column (JSON, nullable) - Creates idx_a2a_agents_team_visibility index for query performance - Creates idx_a2a_agents_owner_visibility index for query performance The indexes match the pattern used for other resource tables (tools, servers, gateways, etc.) and are critical for multitenancy/RBAC query performance. Fixes SQLAlchemy OperationalError: no such column: a2a_agents.oauth_config Signed-off-by: Mihai Criveti <[email protected]>
1 parent 7487687 commit 9c728c0

File tree

1 file changed

+121
-0
lines changed

1 file changed

+121
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# -*- coding: utf-8 -*-
2+
"""Location: ./mcpgateway/alembic/versions/h2b3c4d5e6f7_add_oauth_config_to_a2a_agents.py
3+
Copyright 2025
4+
SPDX-License-Identifier: Apache-2.0
5+
Authors: Mihai Criveti
6+
7+
add oauth config and passthrough headers to a2a agents
8+
9+
Revision ID: h2b3c4d5e6f7
10+
Revises: 3c89a45f32e5
11+
Create Date: 2025-10-30 22:00:00.000000
12+
"""
13+
14+
# Standard
15+
from typing import Sequence, Union
16+
17+
# Third-Party
18+
from alembic import op
19+
import sqlalchemy as sa
20+
21+
# revision identifiers, used by Alembic.
22+
revision: str = "h2b3c4d5e6f7"
23+
down_revision: Union[str, Sequence[str], None] = "3c89a45f32e5"
24+
branch_labels: Union[str, Sequence[str], None] = None
25+
depends_on: Union[str, Sequence[str], None] = None
26+
27+
28+
def upgrade() -> None:
29+
"""Add oauth_config and passthrough_headers columns to a2a_agents table."""
30+
# Check if we're dealing with a fresh database
31+
inspector = sa.inspect(op.get_bind())
32+
tables = inspector.get_table_names()
33+
34+
if "a2a_agents" not in tables:
35+
print("a2a_agents table not found. Skipping migration.")
36+
return
37+
38+
# Check which columns already exist
39+
columns = [col["name"] for col in inspector.get_columns("a2a_agents")]
40+
41+
columns_to_add = []
42+
if "oauth_config" not in columns:
43+
columns_to_add.append(("oauth_config", sa.Column("oauth_config", sa.JSON(), nullable=True, comment="OAuth 2.0 configuration including grant_type, client_id, encrypted client_secret, URLs, and scopes")))
44+
45+
if "passthrough_headers" not in columns:
46+
columns_to_add.append(("passthrough_headers", sa.Column("passthrough_headers", sa.JSON(), nullable=True, comment="List of headers allowed to be passed through to the agent")))
47+
48+
# Add columns using batch mode for SQLite compatibility
49+
if columns_to_add:
50+
try:
51+
with op.batch_alter_table("a2a_agents", schema=None) as batch_op:
52+
for col_name, col_def in columns_to_add:
53+
batch_op.add_column(col_def)
54+
print(f"Successfully added {col_name} column to a2a_agents table.")
55+
except Exception as e:
56+
print(f"Warning: Could not add columns to a2a_agents: {e}")
57+
else:
58+
print("All columns already exist in a2a_agents.")
59+
60+
# Add missing team/visibility indexes for consistent performance with other resource tables
61+
# These indexes are critical for multitenancy queries that filter by owner_email, team_id, and visibility
62+
existing_indexes = [idx["name"] for idx in inspector.get_indexes("a2a_agents")]
63+
64+
indexes_to_create = [
65+
("idx_a2a_agents_team_visibility", ["team_id", "visibility"]),
66+
("idx_a2a_agents_owner_visibility", ["owner_email", "visibility"]),
67+
]
68+
69+
for index_name, columns in indexes_to_create:
70+
if index_name not in existing_indexes:
71+
try:
72+
op.create_index(index_name, "a2a_agents", columns)
73+
print(f"Successfully created index {index_name} on a2a_agents table.")
74+
except Exception as e:
75+
print(f"Warning: Could not create index {index_name}: {e}")
76+
77+
78+
def downgrade() -> None:
79+
"""Remove oauth_config and passthrough_headers columns from a2a_agents table."""
80+
# Check if we're dealing with a fresh database
81+
inspector = sa.inspect(op.get_bind())
82+
tables = inspector.get_table_names()
83+
84+
if "a2a_agents" not in tables:
85+
print("a2a_agents table not found. Skipping migration.")
86+
return
87+
88+
# Drop indexes first (if they exist)
89+
existing_indexes = [idx["name"] for idx in inspector.get_indexes("a2a_agents")]
90+
91+
indexes_to_drop = ["idx_a2a_agents_owner_visibility", "idx_a2a_agents_team_visibility"]
92+
93+
for index_name in indexes_to_drop:
94+
if index_name in existing_indexes:
95+
try:
96+
op.drop_index(index_name, "a2a_agents")
97+
print(f"Successfully dropped index {index_name} from a2a_agents table.")
98+
except Exception as e:
99+
print(f"Warning: Could not drop index {index_name}: {e}")
100+
101+
# Check which columns exist before trying to drop them
102+
columns = [col["name"] for col in inspector.get_columns("a2a_agents")]
103+
104+
columns_to_drop = []
105+
if "passthrough_headers" in columns:
106+
columns_to_drop.append("passthrough_headers")
107+
if "oauth_config" in columns:
108+
columns_to_drop.append("oauth_config")
109+
110+
if not columns_to_drop:
111+
print("No columns to remove from a2a_agents. Skipping migration.")
112+
return
113+
114+
# Remove columns using batch mode for SQLite compatibility
115+
try:
116+
with op.batch_alter_table("a2a_agents", schema=None) as batch_op:
117+
for col_name in columns_to_drop:
118+
batch_op.drop_column(col_name)
119+
print(f"Successfully removed {col_name} column from a2a_agents table.")
120+
except Exception as e:
121+
print(f"Warning: Could not drop columns from a2a_agents: {e}")

0 commit comments

Comments
 (0)