跳转至

平台周报与月报

报告中心位于 /reports,仅管理员可访问。扫描器不需要升级。

启用

  1. 服务启动会在初始化事务中执行内嵌的 migrate_reports.sql,兼容已有数据库。所有新计划默认关闭,原有 reportWeekly=true 不会自动启用计划。
  2. 在运行时配置中将分析快照模式设为 shadow(保留现有分析读取路径)或 snapshot,检查历史回填进度。默认 realtime 不运行统计快照 worker。
  3. 可以先手动生成上一个完整周期,检查报告内容。手动生成与修订版只归档;同一周期重复手动生成返回初始版本。
  4. 配置 SMTP 和管理员邮箱,在报告中心选择收件人、时间并保存启用计划。保存计划会同步旧邮件通知开关;在邮件设置中关闭对应通知开关会暂停自动处理和投递。
  5. 新启用/重新启用的计划从当前周期结束后开始,不发送启用前的历史。收件人留空表示所有有有效邮箱、未锁定/禁用/删除的管理员。每周一或每月 1 日按上海时间发送。

指标

  • 周期采用 Asia/Shanghai,所有查询使用 [start,end);周一为周起点,月报使用自然月。
  • 新建任务按创建时间统计;终态任务按完成时间统计。成功率为成功 /(成功 + 失败 + 部分完成),取消单列,无分母显示 --。
  • 扫描产出来自本期成功完成的 IP 扫描执行,包括跨周期执行的全部观察结果。IP 跨执行去重,端口/服务计数跨执行累加,不代表资产存量或新增资产。
  • 成功执行平均耗时、P50、P95只包含有效起止时间。图表显示每日终态任务,扫描器表显示完成执行。
  • 月报不累加周报或每日去重 IP。日均去重 IP 指周期去重 IP 除以周期天数。上期为零不计算增长率,上期缺少保留历史或统计未齐时不显示环比。
  • 本版不包含 DNS 统计、资产消失判断、漏洞修复状态或扫描器在线率。历史清理之前没有额外事实留存时,不能恢复已删除数据;报告说明会注明“基于生成时保留的历史”。

归档与恢复

生成请求在 repeatable-read 事务中固定任务汇总、每日趋势、扫描器表现和成功执行集合。迟到执行不进入原报告;创建修订版时重新固定输入。成功执行统计必须完整且观测数量与固定输入一致,才能归档。

统计未齐进入 waiting_data,每分钟重试,24 小时后明确失败;输入执行被删除则失败。修复快照问题后可重试,重试重新开始 24 小时等待;输入变化需新建修订版。上期统计不足不阻塞本期归档,但关闭环比。

生成队列采用 SKIP LOCKED、5 分钟租约、UUID 领取令牌和条件回写。生成限时 50 秒,SQL 限时 30 秒;过期任务重新领取,数据库/计算错误最多重试 5 次。每实例每次处理一个报告。维护期间暂停生成和投递,自动计划每分钟扫描,最多补处理 8 个周期。

归档结果、统计口径版本、模板版本、渲染后邮件、固定趋势 PNG 和 SHA-256 保存在 PostgreSQL,不会随扫描历史删除。页面、CSV、打印和邮件使用归档结果。永久模板内容或输出校验错误不阻止统计归档,详情显示原因,修订后可再次生成邮件内容。模块未就绪、繁忙、超时、进程故障或执行任务异常则进入生成任务重试,不归档成已完成报告;渲染器恢复后可以继续生成和入队计划邮件,五次尝试耗尽后明确失败并允许手动重试。

邮件队列逐收件人处理,发送前重新验证用户角色、邮箱、计划、通知偏好和模板状态。使用稳定 Message-ID,SMTP 失败最多重试 5 次。SMTP 接受后、成功状态落库前崩溃仍可能重复发送;不提供 exactly-once 保证。手动发送明确选择收件人,不受自动计划开关限制;已有未完成投递时拒绝重复重发。

接口

  • GET /api/reports?page=1&page_size=20&period_type=weekly
  • GET /api/reports/{id}
  • POST /api/reports/generate:{"period_type":"weekly","date":"2026-09-21"};日期可省略。仅最近一年内已结束周期。
  • POST /api/reports/{id}/revisions
  • POST /api/reports/{id}/retry
  • GET /api/report-schedules
  • PUT /api/report-schedules/{weekly|monthly}:enabled,send_hour,send_minute,recipient_ids,expected_revision。计划更新使用乐观并发控制。
  • GET /api/reports/{id}/deliveries
  • POST /api/reports/{id}/deliveries:{"recipient_ids":[1]}。

所有接口要求登录管理员;写操作使用现有 CSRF 与限流。计划与投递变更写入审计。

验证

cargo fmt --check
cargo clippy --all-targets
cargo test
# 仅使用一次性数据库,每个用例创建、清理独立 schema:
REPORT_TEST_DATABASE_URL='host=/path/to/test/socket port=55439 user=test dbname=postgres' cargo test --lib reports:: -- --include-ignored

集成用例覆盖去重、跨期观察、半开区间、部分完成/取消口径、快照等待、迟到输入、修订、归档保留、重启领取、并发创建、自动调度和发送前权限重验。默认测试跳过需要临时 PostgreSQL 的用例;没有连接真实 SMTP。

完整邮件与远程趋势图片

内置周报和月报邮件包含核心指标、任务完成情况、环比、每日趋势表、端口/服务 Top 10、扫描器执行表现、处理建议和统计口径。HTML 与纯文本均使用同一份归档 payload;邮件不包含具体 IP 列表、任务目标、连接凭据或投递记录。没有名称、仅有 扫描器标识的记录使用邮件标签代替标识。扫描器默认最多展示 20 个,超出时注明剩余数量。

在 运行策略 → 报告邮件 设置平台外部 HTTPS 地址并启用远程趋势图片。 地址可含部署前缀,但不能含用户名、密码、查询参数或 URL 片段。未设置地址或未 启用图片时仍可发送完整文字邮件。外部地址未设置时详情入口仅显示平台相对路径。 报告中心会显示图片未启用的提示。SMTP 设置及管理员收件人校验沿用原有流程。

report_mail 配置保存到运行时配置表;首次缺失时可由以下 TOML 初始化:

[report_mail]
public_base_url = "https://reports.example.invalid"
remote_images_enabled = false
image_lifetime_days = 365
scanner_row_limit = 20

有效期范围为 1~3650 天,扫描器展示上限为 1~100。所有实例在生成报告时读取 数据库中的权威配置,读取配置接口也刷新本实例快照。设置仅影响新生成报告, 旧报告保留其正文、链接和生成时的有效期策略。

如果已有自定义或发布模板,请在邮件模板编辑器中选择周报/月报,点击 载入默认模板,校验预览后保存并发布。此操作不会自动改写已有草稿或发布版本。 变量说明已包含环比、趋势、扫描器和完整性字段。预览与测试邮件只使用固定示例 统计;测试邮件中的示例图片使用配置的外部地址,不生成真实报告访问凭证。

趋势图片为白色背景的 1280 × 600 PNG,按 640px 宽度显示,颜色与 Web 的任务 状态一致。字体嵌入程序,服务器无需安装字体或浏览器。图片在报告生成时固定并 存入 report_mail_asset,与报告正文同事务提交;GET 请求不重算、不生成图片。 图片内容或绘制校验错误不会阻止统计归档,但禁用该版本邮件并记录 quality.mail_error。图表执行任务异常会进入生成任务重试,避免短暂计算故障造成邮件永久缺失。

图片通过 GET /mail/report-images/{token}/trend.png 加载,也支持 HEAD。 令牌为随机 256 位凭证,只能读取绑定的单张图片;数据表只保存令牌 SHA-256。 完整图片 URL 保存在归档邮件中,不经普通报告详情 API 返回。无效、撤销、过期或 不存在的图片统一返回 404。图片不需要会话或 CSRF;报告 API 的管理员权限不变。

图片默认自生成时起有效 365 天。主动重发时按该报告生成时的有效期设置延长 未撤销图片的访问期限,不修改正文、PNG、图表版本或统计校验和。图片响应带有 ETag、nosniff 和最长一小时的 private 缓存,过期/撤销检查早于 304 判定。

管理员可在报告详情撤销图片,也可调用 POST /api/reports/{id}/mail-image/revoke。此写操作要求管理员及 CSRF,记录审计, 取消尚未发送的 pending 邮件;已交给 SMTP 的邮件无法收回。撤销后重发会被拒绝, 需生成修订版。关闭远程图片设置只影响新报告,不撤销旧图片。已被邮箱缓存或 转发的图像无法收回。图片链接持有人可以下载图像,所以图像只包含每日任务数量。

反向代理必须将 /mail/report-images/ 转发给服务端,排在 SPA 回退和外部登录 重定向之前。若应用仅部署于内网,外部邮箱代理可能无法下载图像。邮箱也可能 禁止图片或后台预取;每日趋势表始终保留,图片请求不作为阅读回执。

应用请求日志、认证日志、限流日志及公共日志帮助函数均隐藏图片令牌。 反向代理同样必须脱敏,例如 Nginx 使用不含参数的 $uri 映射:

# 放在 http 块中;按实际部署前缀调整此匹配。
map $uri $report_safe_uri {
    default $uri;
    ~^/mail/report-images/ /mail/report-images/[redacted]/trend.png;
}
log_format report_safe '$remote_addr [$time_local] "$request_method $report_safe_uri $server_protocol" $status $body_bytes_sent';
# 对相应 server 使用 access_log /path/to/access.log report_safe;
# 不要使用包含完整 URL 的 $request,也不要为图片请求开启 URI 调试日志。

图片随完整数据库备份保留;删除扫描历史不会删图,删除报告会级联删除对应图片。 部署时应长期保留邮件中已经使用的外部域名及路径,修改地址不会重写旧邮件。 字体版权说明随 docs/licenses 一同分发。

验证覆盖周/月图像、空数据、完整邮件内容、匿名图片访问、HEAD/ETag、过期与撤销、 续期、扫描历史删除后的归档一致性、普通用户不能撤销图片及旧报告兼容。 集成测试只使用一次性 PostgreSQL;没有向真实收件人发送 SMTP 邮件。

模块化渲染

生产报表现在将统计/模板捕获、邮件渲染和归档提交分为三个阶段。图表与邮件渲染不持有统计事务或数据库连接,归档前重新验证任务 token、租约和报告版本。邮件渲染支持默认内置实现或独立进程,管理员可切换已安装制品;图表计算仍在服务端。

归档 quality.renderer 记录渲染制品、代际和本次输入 checksum。模块切换只影响后续渲染,不改写已有报告和邮件。启用方法与当前部署边界见报表渲染热更新。