# 审计 — 调度执行周期可视化（2026-06-08）

**Changelog**: `docs/changelog/2026-06-08-schedule-cycle-picker.md`  
**设计**: `docs/design/specs/2026-06-08-schedule-cycle-picker-design.md`

## 审计范围

| 模块 | 文件 |
|------|------|
| 周期工具 | `frontend/src/utils/scheduleCycle.ts` |
| 选择器 | `frontend/src/components/schedules/ScheduleCyclePicker.vue` |
| 调度页 | `frontend/src/pages/SchedulesPage.vue` |
| 后端镜像 | `server/utils/schedule_cycle.py` |
| 单测 | `tests/test_schedule_cycle.py` |

## 安全

| 项 | 结论 |
|----|------|
| 无新 API | PASS — 仍提交 `cron_expr` 字符串 |
| Cron 注入 | PASS — 白名单类型 + 数值 clamp；custom 仅 5 字段字符集 |
| 鉴权 | PASS — 调度 CRUD 仍走既有 JWT |

## Step 3

| H | 规则 | 结论 |
|---|------|------|
| H1 | 不改 DB/runner | PASS |
| H2 | 宝塔周期对齐 | PASS — day/day-n/hour/hour-n/minute-n/week/month |
| H3 | 旧 Cron 可编辑 | PASS — parseCronToCycle + custom 回退 |
| H4 | 秒级诚实披露 | PASS — N≥60，折算分钟步进 + UI hint |
| H5 | 列表可读 | PASS — formatCycleLabel |

## Closure

| H | 判定 |
|---|------|
| H1–H5 | PASS |

## DoD

- [x] `pytest tests/test_schedule_cycle.py tests/test_schedule_next_run.py` — 21 passed
- [x] `cd frontend && npm run build` — OK
- [x] changelog + 设计文档
- [x] 生产热更新 + 容器内 bundle 含「执行周期」
- [ ] 用户浏览器终验

## 代码审计（2026-06-08 补审）

此前仅跑门控 + 写文档；以下为逐文件审读结论。

### PASS

| 项 | 说明 |
|----|------|
| 宝塔对齐 | `buildCronFromCycle` 与 aaPanel `GetCrondCycle` 一致 |
| Runner 兼容 | 仍写 5 字段 `cron_expr`，`schedule_runner` 无需改动 |
| 数值 clamp | 时/分/interval 前后端均有边界 |
| 旧数据 | 无法反解析 → `custom` 保留原 Cron |
| 安全 | 无新 API；custom 模式字符集校验；JWT 不变 |

### 发现问题（已修复 2026-06-08）

| 严重度 | 问题 | 处理 |
|--------|------|------|
| ~~中~~ | ~~「每 N 秒」无法 roundtrip~~ | **已移除** second-n；最短 1 分钟 minute-n |

### 审读文件

`scheduleCycle.ts` · `ScheduleCyclePicker.vue` · `SchedulesPage.vue` · `schedule_cycle.py` · `test_schedule_cycle.py` · `schedule_runner.py`（未改，兼容性确认）

## Gate 7 说明

本变更仅前端 + 工具/单测。HEAD 已提交 sort 修复交叉引用：`useServerPagination.ts`、`DashboardPage.vue`、`ServersPage.vue`、`servers.py`、`server_list_sort.py`、`server_repo.py`、`test_server_list_sort.py`、`web/app/index.html`（见 `docs/audit/2026-06-08-servers-live-sort-fix.md`）。
