Skip to content

Commit 44e7e8a

Browse files
authored
Merge pull request #11 from scaleapi/anishxyz/authn
[Auth] Authorized Registration
2 parents 3e5a25f + 895408f commit 44e7e8a

File tree

9 files changed

+831
-778
lines changed

9 files changed

+831
-778
lines changed

src/agentex/lib/cli/handlers/deploy_handlers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
from pydantic import BaseModel, Field
99
from rich.console import Console
1010

11+
from agentex.lib.cli.utils.auth_utils import _encode_principal_context
1112
from agentex.lib.cli.utils.exceptions import DeploymentError, HelmError
1213
from agentex.lib.cli.utils.kubectl_utils import check_and_switch_cluster_context
14+
from agentex.lib.environment_variables import EnvVarKeys
1315
from agentex.lib.sdk.config.agent_config import AgentConfig
1416
from agentex.lib.sdk.config.agent_manifest import AgentManifest
1517
from agentex.lib.sdk.config.deployment_config import ClusterConfig
@@ -168,6 +170,10 @@ def merge_deployment_configs(
168170
if TEMPORAL_WORKER_KEY in helm_values:
169171
helm_values[TEMPORAL_WORKER_KEY]["env"] = agent_config.env
170172

173+
encoded_principal = _encode_principal_context(manifest)
174+
if encoded_principal:
175+
helm_values["env"][EnvVarKeys.AUTH_PRINCIPAL_B64] = encoded_principal
176+
171177
if manifest.deployment and manifest.deployment.imagePullSecrets:
172178
pull_secrets = [
173179
pull_secret.to_dict()

src/agentex/lib/cli/handlers/run_handlers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
from rich.console import Console
77
from rich.panel import Panel
88

9+
from agentex.lib.cli.utils.auth_utils import _encode_principal_context
910
from agentex.lib.cli.handlers.cleanup_handlers import (
1011
cleanup_agent_workflows,
1112
should_cleanup_on_restart
1213
)
14+
from agentex.lib.environment_variables import EnvVarKeys
1315
from agentex.lib.sdk.config.agent_manifest import AgentManifest
1416
from agentex.lib.utils.logging import make_logger
1517

@@ -427,6 +429,11 @@ def create_agent_environment(manifest: AgentManifest) -> dict[str, str]:
427429
"ACP_PORT": str(manifest.local_development.agent.port),
428430
}
429431

432+
# Add authorization principal if set
433+
encoded_principal = _encode_principal_context(manifest)
434+
if encoded_principal:
435+
env_vars[EnvVarKeys.AUTH_PRINCIPAL_B64] = encoded_principal
436+
430437
# Add description if available
431438
if manifest.agent.description:
432439
env_vars["AGENT_DESCRIPTION"] = manifest.agent.description

src/agentex/lib/cli/utils/__init__.py

Whitespace-only changes.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import base64
2+
import json
3+
4+
from agentex.lib.sdk.config.agent_manifest import AgentManifest
5+
6+
7+
# Base 64 encode principal dictionary
8+
def _encode_principal_context(manifest: AgentManifest):
9+
if manifest.auth is None:
10+
return None
11+
12+
principal = manifest.auth.principal
13+
if principal is None:
14+
return None
15+
16+
json_str = json.dumps(principal, separators=(',', ':'))
17+
encoded_bytes = base64.b64encode(json_str.encode('utf-8'))
18+
return encoded_bytes.decode('utf-8')

src/agentex/lib/environment_variables.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ class EnvVarKeys(str, Enum):
2424
ACP_URL = "ACP_URL"
2525
ACP_PORT = "ACP_PORT"
2626
ACP_TYPE = "ACP_TYPE"
27-
# Workflow Configuraiton
27+
# Workflow Configuration
2828
WORKFLOW_NAME = "WORKFLOW_NAME"
2929
WORKFLOW_TASK_QUEUE = "WORKFLOW_TASK_QUEUE"
30+
# Auth Configuration
31+
AUTH_PRINCIPAL_B64 = "AUTH_PRINCIPAL_B64"
3032

3133

3234
class Environment(str, Enum):
@@ -54,6 +56,7 @@ class EnvironmentVariables(BaseModel):
5456
# Workflow Configuration
5557
WORKFLOW_TASK_QUEUE: str | None = None
5658
WORKFLOW_NAME: str | None = None
59+
AUTH_PRINCIPAL_B64: str | None = None
5760

5861
@classmethod
5962
def refresh(cls) -> EnvironmentVariables | None:

src/agentex/lib/sdk/config/agent_manifest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from agentex.lib.sdk.config.agent_config import AgentConfig
1717
from agentex.lib.sdk.config.build_config import BuildConfig
18-
from agentex.lib.sdk.config.deployment_config import DeploymentConfig
18+
from agentex.lib.sdk.config.deployment_config import DeploymentConfig, AuthenticationConfig
1919
from agentex.lib.sdk.config.local_development_config import LocalDevelopmentConfig
2020
from agentex.lib.utils.logging import make_logger
2121
from agentex.lib.utils.model_utils import BaseModel
@@ -36,6 +36,7 @@ class AgentManifest(BaseModel):
3636
deployment: DeploymentConfig | None = Field(
3737
default=None, description="Deployment configuration for the agent"
3838
)
39+
auth: AuthenticationConfig | None = Field(default=None, description="Authentication configuration")
3940

4041
def context_manager(self, build_context_root: Path) -> BuildContextManager:
4142
"""

src/agentex/lib/sdk/config/deployment_config.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Any
1+
from typing import Any, Dict
22

33
from pydantic import Field
44

@@ -90,6 +90,10 @@ class ClusterConfig(BaseModel):
9090
)
9191

9292

93+
class AuthenticationConfig(BaseModel):
94+
principal: Dict[str, Any] = Field(description="Principal used for authorization on registration")
95+
96+
9397
class InjectedImagePullSecretValues(BaseModel):
9498
"""Values for image pull secrets"""
9599

src/agentex/lib/sdk/fastacp/base/base_acp_server.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import asyncio
2+
import base64
23
import inspect
4+
import json
35
from collections.abc import AsyncGenerator, Awaitable, Callable
46
from contextlib import asynccontextmanager
57
from typing import Any
@@ -341,6 +343,16 @@ def run(self, host: str = "0.0.0.0", port: int = 8000, **kwargs):
341343
"""Start the Uvicorn server for async handlers."""
342344
uvicorn.run(self, host=host, port=port, **kwargs)
343345

346+
def _get_auth_principal(self, env_vars: EnvironmentVariables):
347+
if not env_vars.AUTH_PRINCIPAL_B64:
348+
return None
349+
350+
try:
351+
decoded_str = base64.b64decode(env_vars.AUTH_PRINCIPAL_B64).decode('utf-8')
352+
return json.loads(decoded_str)
353+
except Exception:
354+
return None
355+
344356
async def _register_agent(self, env_vars: EnvironmentVariables):
345357
"""Register this agent with the Agentex server"""
346358
# Build the agent's own URL
@@ -350,12 +362,14 @@ async def _register_agent(self, env_vars: EnvironmentVariables):
350362
env_vars.AGENT_DESCRIPTION
351363
or f"Generic description for agent: {env_vars.AGENT_NAME}"
352364
)
365+
353366
# Prepare registration data
354367
registration_data = {
355368
"name": env_vars.AGENT_NAME,
356369
"description": description,
357370
"acp_url": full_acp_url,
358371
"acp_type": env_vars.ACP_TYPE,
372+
"principal_context": self._get_auth_principal(env_vars)
359373
}
360374

361375
if env_vars.AGENT_ID:

0 commit comments

Comments
 (0)