Skip to content

Commit 9c81640

Browse files
committed
fix: resolve cryptography optional import crash and docs inventory race condition
- Make cryptography package import optional in mcp_trust.py to prevent crash on environments without it. - Resolve mypy redefinition and unused type ignore warnings in telemetry and trust modules. - Swap the dashboard generation and inventory writing order in refresh_competitive_docs.py to ensure correct docs-inventory hash capturing. - Eliminate SelectableGroups dict deprecation warnings in plugin_system.py. Constraint: Keep cryptography dependency strictly optional and do not redefine imported symbols statically to satisfy type checks. Tested: Verified full mypy typecheck, ruff format/check, bandit security, and all acceptance docs checks pass cleanly in a synchronized uv dev environment. Confidence: high
1 parent 8e0ed99 commit 9c81640

5 files changed

Lines changed: 31 additions & 16 deletions

File tree

scripts/refresh_competitive_docs.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ def refresh_competitive_docs(
7676
print(f'wrote {dashboard_output}')
7777

7878
validate_docs = _load_module('validate_docs_consistency.py')
79-
inventory_module = _load_module('generate_docs_inventory.py')
80-
inventory_module.write_docs_inventory()
8179
aging_module = _load_module('report_docs_aging.py')
8280
aging_module.write_docs_aging_dashboard()
81+
inventory_module = _load_module('generate_docs_inventory.py')
82+
inventory_module.write_docs_inventory()
83+
8384
errors.extend(
8485
validate_docs.validate_docs_consistency(
8586
readme_path=_REPO_ROOT / 'README.md',

teaagent/env_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Any
1515

1616
# Use tomllib from stdlib for Python 3.11+, fall back to tomli
17+
tomllib: Any
1718
if sys.version_info >= (3, 11):
1819
import tomllib
1920

teaagent/mcp_trust.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@
22

33
from __future__ import annotations
44

5+
import contextlib
56
import json
67
import os
78
import time
89
from dataclasses import dataclass, field
910
from pathlib import Path
1011
from typing import Any, Optional
1112

12-
from cryptography.fernet import Fernet, InvalidToken
13-
1413
from teaagent.audit import AuditLogger
1514
from teaagent.hooks import HookError, HookRegistry
1615
from teaagent.tools import ToolRegistry
1716

17+
Fernet: Any = None
18+
with contextlib.suppress(ImportError):
19+
from cryptography import fernet
20+
21+
Fernet = fernet.Fernet
22+
1823

1924
@dataclass
2025
class MCPServerTrust:
@@ -96,8 +101,14 @@ def trust_policy_path(root: str | Path) -> Path:
96101
return Path(root).resolve() / '.teaagent' / 'mcp-trust.json'
97102

98103

99-
def _get_trust_policy_fernet() -> Fernet:
104+
def _get_trust_policy_fernet() -> Any:
100105
"""Get Fernet instance for MCP trust policy encryption with validation."""
106+
if Fernet is None:
107+
raise ValueError(
108+
"MCP trust policy encryption requires the 'cryptography' package. "
109+
"Install it using: pip install 'teaagent[crypto]'"
110+
)
111+
101112
if 'TEAAGENT_MCP_TRUST_KEY' not in os.environ:
102113
raise ValueError(
103114
'TEAAGENT_MCP_TRUST_KEY environment variable is required for MCP trust policy encryption. '
@@ -143,8 +154,12 @@ def load_mcp_trust_policy(root: str | Path) -> MCPTrustPolicy:
143154
try:
144155
raw_text = path.read_text(encoding='utf-8')
145156
payload = _deserialize_policy(raw_text)
146-
except (OSError, json.JSONDecodeError, InvalidToken, KeyError, ValueError):
157+
except (OSError, json.JSONDecodeError, KeyError, ValueError):
147158
return MCPTrustPolicy()
159+
except Exception as exc:
160+
if exc.__class__.__name__ == 'InvalidToken':
161+
return MCPTrustPolicy()
162+
raise
148163
return MCPTrustPolicy.from_dict(payload)
149164

150165

teaagent/plugin_system.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ def register(registry: ToolRegistry) -> None: ...
4545
import importlib.util
4646
import json
4747
import logging
48-
import sys
4948
from dataclasses import dataclass, field
5049
from enum import Enum
5150
from pathlib import Path
@@ -81,10 +80,8 @@ def _entry_points(group: str) -> list[Any]:
8180
"""Thin wrapper so tests can patch without touching importlib.metadata."""
8281
try:
8382
eps = importlib.metadata.entry_points()
84-
if sys.version_info >= (3, 12):
85-
return list(eps.select(group=group))
86-
return list(eps.get(group, []))
87-
except (ImportError, ValueError) as exc:
83+
return list(eps.select(group=group))
84+
except (ImportError, AttributeError, ValueError) as exc:
8885
logger.warning('Failed to load entry points: %s', exc)
8986
return []
9087

teaagent/telemetry/_transport.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
from __future__ import annotations
22

3+
import contextlib
34
import json
45
from typing import Any
56

6-
_otel_trace: Any
7-
try:
8-
from opentelemetry import trace as _otel_trace
9-
except ImportError: # pragma: no cover
10-
_otel_trace = None
7+
_otel_trace: Any = None
8+
with contextlib.suppress(ImportError):
9+
from opentelemetry import trace
10+
11+
_otel_trace = trace
1112

1213

1314
class TracingHTTPTransport:

0 commit comments

Comments
 (0)