"""Scheduled jobs for the bounty domain.""" from __future__ import annotations import logging from typing import Any from sqlalchemy.ext.asyncio import AsyncSession from app.scheduled_jobs.registry import register_scheduled_job logger = logging.getLogger(__name__) @register_scheduled_job( key="bounty.mail_intake_poll", display_name="白帽子来信轮询(security@)", description=( "每 15 分钟轮询 security@ 收件箱,把新的白帽子来信落到「待确认收件」" "队列,由人一键接受或忽略;同一 thread 的后续来信挂到已有报告上。" "刻意不自动建报告 —— security@ 里还有厂商推销、内部信和自动扫描," "而 HRIS 同步那次谓词太松,把 26 个系统账号当成新人开了号。" "需要 Workspace 给服务账号加 gmail.readonly,未授权前保持停用。" ), ) async def run_mail_intake_poll( db: AsyncSession, config: dict[str, Any], ) -> dict[str, Any]: from app.domains.bounty import mail_intake summary = await mail_intake.poll(db, config=config) await db.commit() # Per ``feedback_handler_status_must_raise``: returning a soft-failure # dict lands ``runs.status='ok'``, so a poller that has been unable to # read the mailbox for a week would look healthy. The scope error is # raised by ``mail_intake.poll`` itself and propagates from here. logger.info( "bounty.mail_intake_poll: listed=%s queued=%s attached=%s", summary.get("listed"), summary.get("queued"), summary.get("attached_to_existing"), ) return summary