Improve security

This commit is contained in:
2026-03-07 15:34:23 +00:00
parent add685a326
commit 611de57bf8
31 changed files with 3617 additions and 58 deletions

View File

@@ -26,6 +26,7 @@ from core.tasks.chat_defaults import ensure_default_source_for_chat, resolve_mes
from core.tasks.codex_approval import queue_codex_event_with_pre_approval
from core.tasks.providers import get_provider
from core.tasks.codex_support import resolve_external_chat_id
from core.security.command_policy import CommandSecurityContext, evaluate_command_policy
_TASK_HINT_RE = re.compile(r"\b(todo|task|action|need to|please)\b", re.IGNORECASE)
_COMPLETION_RE = re.compile(r"\b(done|completed|fixed)\s*#([A-Za-z0-9_-]+)\b", re.IGNORECASE)
@@ -699,6 +700,20 @@ def _is_task_command_candidate(text: str) -> bool:
return _has_task_prefix(body.lower(), ["task:", "todo:"])
def _is_explicit_task_command(text: str) -> bool:
body = str(text or "").strip()
if not body:
return False
return bool(
_LIST_TASKS_RE.match(body)
or _LIST_TASKS_CMD_RE.match(body)
or _TASK_SHOW_RE.match(body)
or _TASK_COMPLETE_CMD_RE.match(body)
or _UNDO_TASK_RE.match(body)
or _EPIC_CREATE_RE.match(body)
)
async def process_inbound_task_intelligence(message: Message) -> None:
if message is None:
return
@@ -707,6 +722,20 @@ async def process_inbound_task_intelligence(message: Message) -> None:
text = str(message.text or "").strip()
if not text:
return
security_context = CommandSecurityContext(
service=str(message.source_service or "").strip().lower(),
channel_identifier=str(message.source_chat_id or "").strip(),
message_meta=dict(message.message_meta or {}),
payload={},
)
if _is_explicit_task_command(text):
command_decision = await sync_to_async(evaluate_command_policy)(
user=message.user,
scope_key="tasks.commands",
context=security_context,
)
if not command_decision.allowed:
return
sources = await _resolve_source_mappings(message)
if not sources:
@@ -729,6 +758,14 @@ async def process_inbound_task_intelligence(message: Message) -> None:
if await _handle_epic_create_command(message, sources, text):
return
submit_decision = await sync_to_async(evaluate_command_policy)(
user=message.user,
scope_key="tasks.submit",
context=security_context,
)
if not submit_decision.allowed:
return
completion_allowed = any(bool(_effective_flags(source).get("completion_enabled")) for source in sources)
completion_rx = await _completion_regex(message) if completion_allowed else None
marker_match = (completion_rx.search(text) if completion_rx else None) or (_COMPLETION_RE.search(text) if completion_allowed else None)