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
18 changes: 14 additions & 4 deletions infisical_sdk/api_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,18 +567,23 @@ class AgentVaultSessionAccessBundle(BaseModel):

@dataclass
class AgentVaultInlineService(BaseModel):
"""A service sent with an Agent Vault session, without its token, password or values. Its nested settings, such as credential, are left as the API returns them."""
"""A service sent with an Agent Vault session, without its token, password or values. type is http, mcp, postgres, mysql or ssh, and the API returns only that type's fields: hostPattern, allowedMethods, allowedPathPrefixes, customHeaders and substitutions for http; serverUrl, transport, hostPattern and customHeaders for mcp; host, port, database and tls for postgres and mysql; host and port for ssh. Its nested settings, such as credential and tls, are left as the API returns them."""
id: str
name: str
type: str
hostPattern: str
hostPattern: Optional[str] = None
serverUrl: Optional[str] = None
transport: Optional[str] = None
allowedMethods: Optional[List[str]] = None
allowedPathPrefixes: Optional[List[str]] = None
credential: Optional[Dict[str, Any]] = None
customHeaders: Optional[List[Dict[str, Any]]] = None
substitutions: Optional[List[Dict[str, Any]]] = None
description: Optional[str] = None
host: Optional[str] = None
port: Optional[int] = None
database: Optional[str] = None
tls: Optional[Dict[str, Any]] = None

@dataclass
class AgentVaultSession(BaseModel):
Expand Down Expand Up @@ -682,12 +687,12 @@ class AgentVaultAccessBundleRef(BaseModel):

@dataclass
class AgentVaultService(BaseModel):
"""A service in an Agent Vault access bundle. Its nested settings, such as credential, are left as the API returns them."""
"""A service in an Agent Vault access bundle. type is http, mcp, postgres, mysql or ssh, and the API returns only that type's fields: hostPattern, allowedMethods, allowedPathPrefixes, customHeaders and substitutions for http; serverUrl, transport, hostPattern, allowedTools and customHeaders for mcp; host, port, database and tls for postgres and mysql; host and port for ssh. Its nested settings, such as credential and tls ({"enabled", "verify", "ca"}), are left as the API returns them."""
id: str
accessBundleId: str
name: str
type: str
hostPattern: str
hostPattern: Optional[str] = None
serverUrl: Optional[str] = None
transport: Optional[str] = None
allowedMethods: Optional[List[str]] = None
Expand All @@ -700,6 +705,11 @@ class AgentVaultService(BaseModel):
createdAt: Optional[str] = None
updatedAt: Optional[str] = None
allowedTools: Optional[List[str]] = None
description: Optional[str] = None
host: Optional[str] = None
port: Optional[int] = None
database: Optional[str] = None
tls: Optional[Dict[str, Any]] = None

@dataclass
class AgentVaultAccessBundle(BaseModel):
Expand Down
2 changes: 1 addition & 1 deletion infisical_sdk/resources/agent_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ def create(
label: A short description of what the session is for, such as "nightly deploy". Up to 128 characters, without line breaks, tabs, or invisible characters.
on_behalf_of_user_email: The email address of the user to start the session on behalf of. Can't be combined with on_behalf_of_user_id.
on_behalf_of_user_id: The ID of the user to start the session on behalf of. Can't be combined with on_behalf_of_user_email.
services: Services the session carries itself, instead of or beside its access bundle's: up to 20 dicts with the API's field names, such as {"type": "http", "hostPattern": "api.github.com", "credential": {"type": "bearer", "value": token}}. Only Agent Vault admins can send them. Each has the same fields as a service in an access bundle, except that its name is optional, its values can't use variables, it can't use OAuth or member-provided values, and an MCP server can't be limited to some of its tools. To limit an MCP server's tools, add it to an access bundle instead.
services: Services the session carries itself, instead of or beside its access bundle's: up to 20 dicts with the API's field names, such as {"type": "http", "hostPattern": "api.github.com", "credential": {"type": "bearer", "value": token}}. Only Agent Vault admins can send them. Each has the same fields as a service in an access bundle, except that its name is optional for HTTP and MCP services (database and SSH services need one), its values can't use variables, it can't use OAuth or member-provided values, and an MCP server can't be limited to some of its tools. To limit an MCP server's tools, add it to an access bundle instead.
project_id: The ID of the Agent Vault project to create the session in.

Returns:
Expand Down
34 changes: 32 additions & 2 deletions tests/test_agent_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,44 @@ def test_access_bundles_get_reads_the_tools_an_mcp_service_allows(api, agent_vau
service = {
"id": SERVICE_ID, "accessBundleId": BUNDLE["id"], "name": "linear", "type": "mcp",
"serverUrl": "https://mcp.linear.app/mcp", "transport": "streamable-http", "hostPattern": "mcp.linear.app",
"allowedMethods": None, "allowedPathPrefixes": None, "allowedTools": ["list_issues"],
"credential": {"type": "bearer", "memberProvidedFields": []}, "customHeaders": [], "substitutions": [],
"allowedTools": ["list_issues"],
"credential": {"type": "bearer", "memberProvidedFields": []}, "customHeaders": [],
"createdAt": BUNDLE["createdAt"], "updatedAt": BUNDLE["updatedAt"],
}
api.session.get.return_value = json_response({"accessBundle": dict(BUNDLE, services=[service])})
assert agent_vault.access_bundles.get(BUNDLE["id"]).services[0].allowedTools == ["list_issues"]


def test_access_bundles_get_reads_database_and_ssh_services_without_http_fields(api, agent_vault, json_response):
shared = {
"accessBundleId": BUNDLE["id"], "description": None, "variableReferences": [], "createdAt": BUNDLE["createdAt"], "updatedAt": BUNDLE["updatedAt"],
}
postgres = dict(shared, id=SERVICE_ID, name="orders-db", type="postgres", host="db.internal", port=5432,
database="orders", tls={"enabled": True, "verify": True, "ca": None},
credential={"type": "basic", "memberProvidedFields": []})
ssh = dict(shared, id="7d1e3f5a-9b2c-4d6e-8f0a-1b3c5d7e9f2a", name="bastion", type="ssh",
host="bastion.internal", port=22, credential={"type": "ssh-key", "hasCertificate": False})
api.session.get.return_value = json_response({"accessBundle": dict(BUNDLE, services=[postgres, ssh])})
database, server = agent_vault.access_bundles.get(BUNDLE["id"]).services
assert (database.host, database.port, database.database) == ("db.internal", 5432, "orders")
assert database.tls == {"enabled": True, "verify": True, "ca": None}
assert database.hostPattern is None
assert (server.host, server.port, server.tls) == ("bastion.internal", 22, None)


def test_sessions_read_an_inline_database_service(api, agent_vault, json_response):
inline = {
"id": INLINE_SERVICE["id"], "name": "orders-db", "description": "Orders replica", "type": "mysql", "host": "db.internal", "port": 3306,
"database": "orders", "tls": {"enabled": False, "verify": False, "ca": None},
"credential": {"type": "basic"},
}
api.session.get.return_value = json_response({"session": dict(SESSION, services=[inline])})
service = agent_vault.sessions.get(SESSION["id"]).services[0]
assert service == AgentVaultInlineService(**inline)
assert service.hostPattern is None and service.customHeaders is None
assert service.description == "Orders replica"


def test_access_bundles_list_grantees_reads_a_pending_organization_membership(api, agent_vault, json_response):
grantee = dict({key: ON_BEHALF_OF[key] for key in ("type", "id", "username", "email", "firstName", "lastName")},
isOrgMembershipPending=True, grantedAt="2026-10-27T00:00:00.000Z")
Expand Down
Loading