feat(audit): skip audit log for excluded health/root paths

健康检查与根路径(/health/live、/health/ready、/api/v1/health、
/、/health/storage)没有用户、没业务动作,每秒被 K8s/LB
探针刷一次只会灌进无意义噪音。命中排除集即跳过审计行;
诊断日志(method/path/status/ms 走 stderr)照常打,对容器
运维排错仍有用。

* settings.audit_excluded_paths: list[str] 默认覆盖 5 条
  基础设施路径,env AUDIT_EXCLUDED_PATHS 用逗号分隔
  (pydantic NoDecode + field_validator 兼容 str/list)
* main.py 模块级 _AUDIT_EXCLUDED = frozenset(...),
  access_log 的 success/exception 两条审计行各加守卫
  诊断无条件打
* 测试用 _AccessLogReplica 复刻 access_log 契约(不 import
  真实 main.py),新增 4 个 case:排除根路径、排除 /health/live、
  不排除路径照写审计、自定义排除集

顺带 schedule 模块:ExecutionResult 与 context 已迁到
schedule.domain.*(execution.py / orchestrator.py /
scheduler.py / worker.py),调用点跟进;schedule 自身
18 个测试在改前改后均通过。
This commit is contained in:
tao.chen
2026-09-02 10:10:41 +08:00
committed by tao.chen
parent 8dc2311536
commit 9f7b6ba18c
8 changed files with 162 additions and 45 deletions
+26 -2
View File
@@ -18,9 +18,10 @@ Rules for adding a new variable:
from __future__ import annotations
from functools import lru_cache
from typing import Annotated
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
class Settings(BaseSettings):
@@ -79,6 +80,29 @@ class Settings(BaseSettings):
default=30,
description="审计日志保留天数;过期文件启动时清理。设 0 关闭清理。",
)
audit_excluded_paths: Annotated[list[str], NoDecode] = Field(
default=[
"/health/live",
"/health/ready",
"/api/v1/health",
"/",
"/health/storage",
],
description=(
"审计排除的精确路径列表(不含 query)。命中即不写审计行。"
"诊断日志(method/path/status/ms)仍写 stderr。"
"环境变量 AUDIT_EXCLUDED_PATHS 用逗号分隔,例如"
" '/health/live,/api/v1/health'"
),
)
@field_validator("audit_excluded_paths", mode="before")
@classmethod
def _split_audit_paths(cls, v):
# env 进来是 "a,b,c";代码里直接传 list 也行
if isinstance(v, str):
return [s.strip() for s in v.split(",") if s.strip()]
return v
# ── runtime container endpoint ───────────────────────────────
runtime_api_url: str = Field(