From 3c97ad407ce87c8e080e79dc9d3c88a67fc0375d Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 2 Jan 2026 13:27:30 -0500 Subject: [PATCH] feat(session): cap TTL at 1 hour maximum --- src/grist_mcp/session.py | 15 ++++++++++++--- tests/unit/test_session.py | 16 ++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/grist_mcp/session.py b/src/grist_mcp/session.py index ace0651..8bccc4b 100644 --- a/src/grist_mcp/session.py +++ b/src/grist_mcp/session.py @@ -4,6 +4,9 @@ import secrets from dataclasses import dataclass from datetime import datetime, timedelta, timezone +MAX_TTL_SECONDS = 3600 # 1 hour +DEFAULT_TTL_SECONDS = 300 # 5 minutes + @dataclass class SessionToken: @@ -27,19 +30,25 @@ class SessionTokenManager: agent_name: str, document: str, permissions: list[str], - ttl_seconds: int, + ttl_seconds: int = DEFAULT_TTL_SECONDS, ) -> SessionToken: - """Create a new session token.""" + """Create a new session token. + + TTL is capped at MAX_TTL_SECONDS (1 hour). + """ now = datetime.now(timezone.utc) token_str = f"sess_{secrets.token_urlsafe(32)}" + # Cap TTL at maximum + effective_ttl = min(ttl_seconds, MAX_TTL_SECONDS) + session = SessionToken( token=token_str, document=document, permissions=permissions, agent_name=agent_name, created_at=now, - expires_at=now + timedelta(seconds=ttl_seconds), + expires_at=now + timedelta(seconds=effective_ttl), ) self._tokens[token_str] = session diff --git a/tests/unit/test_session.py b/tests/unit/test_session.py index 0dee1e1..fb3d834 100644 --- a/tests/unit/test_session.py +++ b/tests/unit/test_session.py @@ -21,3 +21,19 @@ def test_create_token_returns_valid_session_token(): assert token.agent_name == "test-agent" assert token.expires_at > datetime.now(timezone.utc) assert token.expires_at < datetime.now(timezone.utc) + timedelta(seconds=310) + + +def test_create_token_caps_ttl_at_maximum(): + manager = SessionTokenManager() + + # Request 2 hours, should be capped at 1 hour + token = manager.create_token( + agent_name="test-agent", + document="sales", + permissions=["read"], + ttl_seconds=7200, + ) + + # Should be capped at 3600 seconds (1 hour) + max_expires = datetime.now(timezone.utc) + timedelta(seconds=3610) + assert token.expires_at < max_expires