fix(awooop): use shared redis for approval gates
This commit is contained in:
@@ -44,7 +44,7 @@ from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
import structlog
|
||||
from sqlalchemy import select, text
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.db.awooop_models import (
|
||||
@@ -54,6 +54,7 @@ from src.db.awooop_models import (
|
||||
AwoooPMcpToolRegistry,
|
||||
AwoooPProject,
|
||||
)
|
||||
from src.core.redis_client import get_redis
|
||||
from src.plugins.mcp.interfaces import MCPToolResult
|
||||
from src.plugins.mcp.registry import get_provider_registry
|
||||
|
||||
@@ -359,14 +360,9 @@ class McpGateway:
|
||||
raise GateApprovalError("write/admin 操作需要 run_id(approval 追蹤用)")
|
||||
|
||||
try:
|
||||
import aioredis
|
||||
|
||||
from src.core.config import settings
|
||||
|
||||
redis = aioredis.from_url(settings.REDIS_URL)
|
||||
redis = get_redis()
|
||||
approval_key = f"mcp_approval:{ctx.project_id}:{ctx.agent_id}:{ctx.tool_name}:{ctx.run_id}"
|
||||
approved = await redis.get(approval_key)
|
||||
await redis.aclose()
|
||||
except Exception as exc:
|
||||
logger.warning(
|
||||
"mcp_gate5_redis_error",
|
||||
|
||||
@@ -46,6 +46,8 @@ from typing import Any
|
||||
|
||||
import structlog
|
||||
|
||||
from src.core.redis_client import get_redis
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -219,29 +221,23 @@ async def record_approval(
|
||||
exp = payload["exp"]
|
||||
|
||||
try:
|
||||
import aioredis
|
||||
from src.core.config import settings
|
||||
|
||||
redis = aioredis.from_url(settings.REDIS_URL)
|
||||
redis = get_redis()
|
||||
|
||||
# jti NX
|
||||
jti_key = f"{_JTI_KEY_PREFIX}{jti}"
|
||||
ttl_remaining = max(exp - int(time.time()), 1)
|
||||
ok = await redis.set(jti_key, "1", nx=True, ex=ttl_remaining)
|
||||
if not ok:
|
||||
await redis.aclose()
|
||||
raise TokenReplayError(f"jti={jti!r} 已使用")
|
||||
|
||||
# SADD approver
|
||||
sig_key = f"{_SIG_SET_PREFIX}{project_id}:{run_id}:{tool_name}"
|
||||
added = await redis.sadd(sig_key, approver_id)
|
||||
if added == 0:
|
||||
await redis.aclose()
|
||||
raise DuplicateApproverError(f"approver '{approver_id}' 已簽核")
|
||||
|
||||
await redis.expire(sig_key, _SIG_TTL_SECONDS)
|
||||
count = int(await redis.scard(sig_key))
|
||||
await redis.aclose()
|
||||
|
||||
logger.info(
|
||||
"awooop_approval_recorded",
|
||||
@@ -271,13 +267,9 @@ async def check_approval_quorum(
|
||||
檢查 quorum。Raises QuorumNotMetError if 不足。
|
||||
"""
|
||||
try:
|
||||
import aioredis
|
||||
from src.core.config import settings
|
||||
|
||||
redis = aioredis.from_url(settings.REDIS_URL)
|
||||
redis = get_redis()
|
||||
sig_key = f"{_SIG_SET_PREFIX}{project_id}:{run_id}:{tool_name}"
|
||||
count = int(await redis.scard(sig_key))
|
||||
await redis.aclose()
|
||||
|
||||
if count < required_count:
|
||||
raise QuorumNotMetError(f"簽核數不足({count}/{required_count})")
|
||||
|
||||
Reference in New Issue
Block a user