Conversation
- 按 main 与 dev 通道输出对应的暂存完成提示 - 兼容预发布版本的位置参数入口并继续拒绝稳定版绕过门禁 - 同步三仓发布规范口径与远程发布文档 - 增加发布入口兼容性和提示语回归测试
- 修正宝塔自定义模块名下的热更新缓存清理,避免新旧文件混载 - 为升级检测与部署 API 补充常见 Linux 系统 CA 信任库 - 固定设置页动态状态布局并避免重复渲染闪动 - 刷新后一次性校验目标版本,异常时提示重启宝塔面板 - 补充回归测试并同步升级使用说明
- 使用 x509 -text 兼容 OpenSSL 1.0.2k 的证书信息解析 - 记录受限且脱敏的解析失败原因、OpenSSL 路径与日期 locale - CI 编译固定校验的 OpenSSL 1.0.2k 并运行真实证书回归测试 - 补充部署、续签和诊断接线测试
- 面板识别 CAPPED/EXPIRED/policy 阻断等终态并给出「已停更」标签、统计与详情,新增 reset_issue_state 恢复入口 - Web 配置损坏改为部署前环境闸门:不计入部署尝试计数、上报 failure 回调、本轮记为失败,配置修复后自动恢复并清除阻断标记 - 手动部署与批量部署同样前置环境闸门,直接返回配置错误原因而非逐站点失败 - reload 失败判定改结构化正则,避免 error_log 等正常输出误判;配置校验失败才回滚,纯重载失败保留已写入证书 - 部署互斥锁提示语区分部署与续签并增加抢锁重试,前端添加流程改串行,部分失败也刷新列表 - 续签汇总输出成功/等待/失败计数,结果表转义任意诊断文本 - cron 脚本在面板解释器路径失效时回退 python3,pending key 清理覆盖悬空符号链接 - 发布脚本正常路径不再重复全节点验收,快路径保持自行验收
- 新增 probe_panel_runtime():整轮开始前一次性探测 public/panelSite 可导入性, 不可用即整轮中止并给出指向解释器回退的根因提示 - 运行环境不可用不发任何 per-order 回调:这是进程级故障,逐证书上报既定位不到 根因,也不属于 spec §2.8 的部署结果上报范围 - check_web_config() 调用包 try:抛异常与返回错误同样走阻断路径,此前裸调用会让 异常穿透到通用 except,回调发不出、原因不落盘、计数停在 0 而永不触顶 - 环境阻断回调改为变化触发:服务端 reminder 是电平驱动,一行即可让订单留在失败 视图,逐日重发零信息增量却会淹没管理端列表且不被清理 - renew_status.json 增加 aborted_reason,区分"整轮中止"与"跑完但无需续签"—— 两者都返回空列表,此前统一报成"无需续签" - 引擎新增 last_abort_reason,run_renew/run_renew_cron 据此分开报告 - 前端新增续签健康横幅:last_run 距今超 48h 或本轮中止即在证书页告警,仅在有已 启用证书时判定,避免全新安装误报
- 旧文件合并的删除判据收紧为「内容确实并入 AND 本次写入成功」,其余一律改名 .orphan 保留:此前 merged_files.append 在合并判断之外,「目标已有数据故未合并」 与「旧文件本身损坏」都会连同数据一起删除,且全程零异常 - 写入失败改捕获 Exception:json.dump 对不可序列化对象抛 TypeError,穿透出去会让 ConfigManager 构造失败、插件整体不可用 - 主配置损坏后进入只读降级:_write_json 与 _update_json 双侧门禁。真正的覆盖点是 _update_json 的「解析失败→备份→回落默认值→照常写回」,仅拦 _ensure_config 挡不住 cron 的任意一次 update_metadata - 降级仅由主配置触发,遗留文件损坏走 .orphan 无损跳过,避免插件永久只读 - .bak 已存在时不覆盖,第二次损坏不再毁掉第一份可恢复副本 - 续签引擎在降级态整轮中止:否则 get_certs 恒空、照常写出全 0 的新鲜状态, 与「确实无需续签」不可区分 - get_config 透出 config_degraded,前端在证书列表为空时优先告警而非显示「暂无证书」
- 新增 resolve_python():注册前用 subprocess 验证候选解释器能 import public, 只在面板 pyenv 与当前解释器间选择,绝不回落系统 python3。此前 _build_script 无 条件烧入 sys.executable,在系统 python3 下注册会写出每天必然失败的脚本,而脚本内 [ -x ] 存在性检查恰好通过、回退分支永不触发,是永久性静默失效 - setup 拆出 refresh:安装/升级保留现有执行时间只重写脚本正文,对齐 spec §7.4 幂等性;此前 remove + 重新随机化会让升级频繁的用户执行时间每次乱跳 - 改为先建后删:crontab 模块探测与 AddCrontab 结果确认都在删除动作之前, 杜绝「旧的删了新的没建成」的空窗 - install.sh 注册/刷新计划任务,updater 升级后同样刷新:cron 脚本正文存在宝塔 crontab 库、不在 PLUGIN_DIR 内,不在这两处刷新则修正永远到不了存量安装 - get_status 区分「确认不存在」「已暂停」「查询失败」,add_cert 仅在确认不存在时 创建:此前一次瞬时 DB 锁定就会经 remove+重建弄丢用户正常的任务 - deploy/install.sh 面板解释器优先,且不再用 2>/dev/null 吞掉注册失败 - cron 脚本打印续签结果:run_renew_cron 吞异常返回 _err 且返回值被丢弃, 此前 cron.log 恒为空、宝塔任务日志永远显示成功 - 前端渲染计划任务三态并在证书页告警计划任务缺失/暂停 真实宝塔容器验收:系统 python3 自检被拒、烧入路径为面板 pyenv、连续三次安装保持 19:46 不变且仅一条任务、crontab DB 损坏时放弃操作且原任务原封未动
F8 部分站点失败改判为失败,并把 metadata 写入拆成三组: - 组一(无条件):逐站点结果 site_deploy_status。面板此前用证书级 last_deploy_at 渲染每一个站点行,部分失败时失败站点也显示「已部署」,而它还挂着旧证书 - 组二(任一成功):计数清零,与编排层 counts_cleared=any 镜像。不收紧到全部成功—— 一张证书绑三个站点其中一个永久坏时,计数只增不减会在十轮后把整张证书推入 CAPPED, 两个健康站点跟着一起停更 - 组三(全部成功):到期时间与序列号。部分失败时保留旧值,needs_renewal 因此继续为真、 次日重试;此前无条件前推会让失败站点等到新证书临期(90 天证书约 76 天)才再试一次 判据均基于同一份完整 results,与 _deploy_callback_decision 天然同源 其余: - _check_deploy_results 部分失败改抛错,恢复内部一致性:回调本就报 failure, 只有本地汇总报 success - 阶段一逐证书异常隔离:APIClient 构造对 SSRF/token 非法主动 raise,此前一张证书 失败会让整批后续证书连一次 API 调用都没有,且 renew_status 保留上一轮成功记录 - pull 模式已签发但无绑定站点:复用 last_deploy_block_reason 记录并按变化触发上报 - 抢锁重试窗口按调用方参数化(cron 120s / 面板 6s),锁文件改 O_NOFOLLOW, 抢锁失败写独立小文件而非读改写 renew_status - 解绑时同步剔除 site_deploy_status 键,避免历史站点永久堆积 - 两处硬编码重置列表提取为 DEPLOY_SUCCESS_RESET_KEYS / MANUAL_RESET_KEYS - 前端:逐站点部署状态、缺 API 配置红标与统计、已签发但未绑定的警告色
- F9 证书更替检测:全部站点成功时比对 cert_serial,连续两轮相同才升级为 failure。 只在编排层判定(手动重复部署、粘贴私钥后重部署都是同一张证书,属正常操作); 两端序列号都非空才比较(解析失败返回空串,老 OpenSSL 上会让每次部署都误报); 到期时间未前移仅作序列号缺失时的降级判据——CA 重签常保留原有效期, 新序列号 + 相同 notAfter 是正常结果,而 local 走的恰恰是重签路径 - F13 验证文件重放判据改为「上次是否真的放上去了」:要求列表非空 + 覆盖全部绑定站点 + 文件仍在盘上。此前只比对 file_info,首轮放置失败后每轮都被短路, 文件一次都写不进去而订单永远卡在 processing - F14 auto_reissue 结果落盘:api_client 内部已吞异常返回 None,再吞一次就无迹可寻。 未确认成功时面板告警——pull 模式下它没设成功等于服务端永不重签 - F15 批次选择公平化:processing 组限额一半 + 组内按 last_attempt_at 轮转, 保证超额时 ceil(N/100) 轮内全部触达。单纯按紧急度排序无效——processing 证书 正因临期才提交 CSR,剩余有效期必然更短,排序只会让它们更稳地占住配额 - F16 EXPIRED 自愈:判定插在终态 continue 之前(写在其后永远执行不到), 守卫为剩余有效期可解析且高于安全余量,只清状态不动计数; 站点缺失计数补时钟护栏——跨十二小时确认这道防线依赖时钟单调,一次前跳即可跳过 - F17 pull 订单状态用展示专用字段 last_order_status,不碰 last_issue_state (后者带门禁语义,写入 cancelled 会让证书被永久跳过,违反「后续轮次仍可查询自愈」); 前端按真正的停机集分档,renewed/reissued/cancelling 不算故障 - F18 跳过原因进 renew_status,not_due 不入册,明细上限 50 条 - 三个新 metadata 字段同步进两处重置集合 - 文档同步:删除三仓都不存在的「CSR 超时」描述,更新 cron 与部署判定的实现要点
- §2.2 错误分类契约:错误响应恒 HTTP 200 + code=0,分类只经 errors.error_code; 拆为「整批共通」(限流/token/账号/IP)与「单条目」两表,后者新增 order_in_progress、 validation_method_unsupported、auto_renew_disabled、insufficient_balance; errors 的三种形态明确只有带 error_code 的那种参与分类 - retry_after 语义改为「睡满即可重试的保守秒数」(61..120),不再是「当前窗口剩余秒数」: 服务端按滑动窗口加权判定,只睡到下一窗口起点时刚超限的那个窗口权重为 1、全额计入, 必然仍被拒,那次徒劳重试还会把计数器垫高 - §2.3 查询收窄:order 必填且只接受订单 ID,彻底无分页(不返回也不接受 total/page/ page_size),批量未命中静默跳过;新增 §2.3.1 field 拉取模式,本规范客户端不走该路径 - §2.4 新增订单状态显式分类表,禁止「其余即终态」兜底:unpaid/cancelling 是可自愈中间态 且不得主动 POST(会触发服务端扣费),renewed/reissued 为链数据异常,未知取值保守当等待 - §1.5 新增 no_progress_since / block_report_count / last_order_status;last_issue_state 语义收窄为「有无在途订单」并新增 active 取值,触顶阶段字段定名 capped_phase - §3.2 无进展时限、§3.8 证书未更替检测与计数所有权(不得放入部署成功清零列表)、 §11 新增批量查询上限与非关键上报熔断阈值 - 修正 §4.1 setup 参数表:order 仍标「可选…不传时查询全部」,与新 §2.3 直接矛盾, 改为必填(本仓领先项,已回同 sslctl / sslctlw 副本)
- compose 构建上下文从 ../../sslctl/docker/test/mock-api 改为仓内 ./mock-api,消除跨仓
引用;此后两仓各自维护副本,行为契约同以 deploy-spec 为准
- 查询响应去分页:只回 {data, renew_before_days},删掉 total/page/page_size。刻意不再
输出服务端自报计数——客户端读不到它,就长不出翻页循环
- order 必填且形态须匹配 ^\d+(,\d+)*$,缺参/空串/域名/ID+域名混合一律 code=0 +
invalid_order;批量未命中静默跳过、全未命中回空数组,单 ID 未命中才 order_not_found
- 删除 filterOrdersByQuery(按域名做 SAN 子串匹配,会把 notexample.com 这类跨域证书混进
结果),响应构造收敛到唯一的 orderToResponse,此前散在 handler 里的四个分支合并
- 新增确定性失败注入场景 rate_limited(retry_after=100,符合新语义的 61..120)/
token_invalid / token_disabled / account_disabled / ip_not_allowed,以及 lying-total
(谎报 total 且返回满页),用于锁死「客户端单次取完、不按自报计数翻页」
- 新增 make mock-api-test(临时 module 跑,无 Go 工具链自动跳过)与目录 README;
镜像只 COPY main.go,测试不进镜像
- APIError 携带 error_code / retry_after,并给出 auth_blocked(限流/token/账号/IP)与 order_rejected(订单级)两个判据。分类一律正面列举、不写成「不属于某组即另一组」: 后者会把将来新增的取值都当成凭据问题,服务端加一个无害的码就能连带停掉整轮条目。 未列出的取值按未分类处理,沿用既有重试策略 - errors 形态一律防御性解析,按 errors.error_code 非空判定而非「有 errors 键」:参数校验 失败袋与订单服务层透传的业务错误都带 errors 键却不是分类标识 - error_code 进错误文本:服务端 msg 可能是「Unauthorized」这类无指向的通用文案,而 token_disabled 与 ip_not_allowed 的处置完全不同。retry_after 按新语义只表述 「N 秒后重试」,绝不写成「窗口还剩 N 秒」,否则运维读到的等待时间差一个整窗口 - HTTP 层删掉按状态码猜原因的 401/404 分支(业务失败恒 200,这两个分支对反代响应是 误导),429 移出重试集合——服务端刻意不用 429 表达限流,反代 429 的指数退避同样 全落在限流窗口内注定失败,只会把恢复时间往后推 - query_batch 删除翻页循环、不再发分页参数,单次请求取完即止;_parse_list_data 只认 新结构并对 data/data.data 显式校验形态,刻意不读 total——读了就给翻页循环留了接口 - 新增 validate_order_param 本地形态闸门,发请求前挡住域名、空参数与超 100 项; fetch_deploy_url 同口径先判一道,对按域名生成的旧链接给可执行提示而非服务端原文 - test_connection 改用「不带 order 必被判 invalid_order」作探针:该错误恰好证明请求已 穿过认证中间件抵达业务层参数校验,无需先持有真实订单号
- 订单状态按 spec §2.4 显式分类(classify_order_status 五类全覆盖),在途等待含 unpaid / cancelling,未知新增状态保守归等待。原实现用「其余即终态」兜底,服务端加一个 中间态就能把全量证书打进停机;unpaid 更严重——它被写成终态后既不在 TERMINAL_ISSUE_STATES (前置过滤拦不住)、又不等于 processing(不再走查询分支),下一轮直接落到 _submit_new_csr 发出 POST,而 POST 会触发服务端 pay 扣费 - 订单状态只写展示字段 last_order_status,绝不写 last_issue_state(后者语义是「有无在途 订单」)。保持在途标记不动,终态路径就恒为「只查询」,边界由无进展时限提供;等待分支也记 该字段,否则卡在 unpaid 的证书与正常等签发在面板上完全一样 - 证书更替检测修正两处:新序列号改由编排层从待部署 fullchain 直接解析——deploy_multi 只 update_metadata 写盘、不回写内存 cert_entry,从 metadata 读回的「新值」其实还是部署前的 旧值、与 prev 恒等,使每张正常续签的证书在第二次续签时被误判 failure,而服务端提醒是电平 驱动、健康证书就此永久留在失败视图;unchanged_cert_rounds 按 §3.8 移出部署成功清零列表, 计数所有权归检测本身。既有测试全是孤立单测,故补集成用例覆盖真实链路 - cap_stage 改名 capped_phase(与 spec/sslctl 对齐),并补齐迁移引擎缺失的 metadata 层: 规则须在 _fill_defaults 之前执行,否则该键将来若进默认表,rename 的「目标已存在则保留新值」 会让旧值被静默丢弃。v0.3.9 已发布旧名,不迁移则面板丢掉具体触顶阶段且旧键成死数据 - 轮内 token 黑名单按 (url, token) 拉黑:限流与认证失败由中间件下发、与订单无关,逐张重试 零收益,还会在 local 模式每张烧一次签发额度、把限流计数器继续推高。只活一轮不落盘—— 持久化等于升级成永久停止,token 换发后再也不会被重试 - CSR 提交路径对认证/限流类失败回滚 issue_retry_count:请求被拒于业务层之外,那次尝试事实上 从未发生。order_in_progress 归一 processing 并清掉本轮 pending——服务端签的是更早那个 CSR, 留着本轮私钥必然不配对,只会让配对校验抛错、把坑从签发侧挪到部署侧。其余永久码刻意不分档: 有界由计数上限提供、可见由 error_code 提供,立即终态反而会杀死自动恢复 - 无进展停更(no_progress_since)给纯查询路径绝对边界:轮询不计尝试计数,而到期闸门在 cert_expires_at 为空时整段失效,从未成功部署过的证书会每天空查询到永远;时限依赖时钟单调, 时间戳损坏/回拨/间隔不可信时重新锚定而非判定停更 - 环境阻断上报封顶(block_report_count):阻断不递增部署计数,此前唯一抑制是原因字符串相等, 而原因含 PID/路径/异常文本时每轮都算「变化」,回调因此无上限;环境恢复时清零 - 非关键上报熔断(连续 3 次失败跳过本轮剩余同类上报,部署结果回调与阻断上报共享计数): 单次回调最坏约 183 秒,批量 100 张时逐张干等会线性放大到数小时。熔断打开时跳过的阻断上报 不消耗额度,否则一次通道故障就让证书永久静默 - 面板:capped_phase 标签、订单级 error_code 归入停更分档、新增 AUTH_BLOCK_LABEL 与 renew_status.auth_blocks 红条——token 被拒时回调用的是同一个坏 token、必然也发不出去, 面板是唯一的用户侧提示入口
- 重写「部署 API 接口」章节:删除已作废的 currentPage/pageSize、「字符串=域名」、 「不传返回最新 active 订单」与分页响应示例,改为 order 必填只收 ID + 无分页结构 - 新增错误分类小节(auth_blocked / order_rejected 两个判据、计数纪律、轮末汇总), 以及 §2.6 提交路径分档(order_in_progress 归一及与 sslctl 的刻意差异、 为何不给永久码另造终态) - 记录订单状态分类与「不写 last_issue_state」的扣费路径、证书更替检测的两个陷阱 及「为什么必须有集成测试」、metadata 层迁移的执行顺序要求、非关键上报熔断 - docker-test 说明改为仓内 docker/mock-api,补 make mock-api-test
- 按 query-first 与 CSR 归属校验约束 local 重签,禁止不确定 POST 重放 - 接纳部分部署成功并独立重试失败绑定,收紧 pending 私钥生命周期 - 将首次部署、自动重签开关与计划任务启用顺序对齐 setup 契约 - 迁移计划任务为仓库薄入口并补充升级自愈与失败可见性 - 更新规范、开发说明、Docker E2E 与单元测试覆盖
- 识别 subject=CN 与旧版斜杠格式 - 保留 CSR 签名、公钥和 DER 哈希校验 - 增加 Linux OpenSSL 输出回归测试
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
发布 0.4.0 正式版。