停用历史业务命令并明确CLI运维范围
This commit is contained in:
parent
25fd4cf89c
commit
d90ddaadbb
@ -6,6 +6,8 @@ Scert 是一个统一管理 SSL 证书、自动续期并部署到多台服务器
|
||||
|
||||
正式产品仅包含 Web 管理界面和 Windows/Linux 服务端。CLI 作为服务端运维入口,用于初始化、服务启动、运维诊断、数据库迁移、备份恢复、服务安装和卸载,不作为另一套业务管理界面。
|
||||
|
||||
旧业务 CLI 已停用并返回中文迁移提示,范围和迁移方法见 `doc/命令行运维范围说明.md`。自动续期仍由服务端调度,手动业务操作通过 Web 执行,不再提供绕过 Web 流程的第二套 CLI 入口。
|
||||
|
||||
`desktop/` 保留 Wails 历史源码,供参考和独立开发;桌面窗口、托盘、自动更新、桌面配置管理及桌面 UI 测试均不属于正式交付或验收范围。正式发布脚本不调用 Wails,也不需要 WebView2 或 GTK 开发依赖。
|
||||
|
||||
## 项目目录
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
Scert 是面向 Windows 和 Linux 的 SSL 证书管理服务。当前代码已覆盖核心证书生命周期、DNS-01、自动续期、SSH 部署、通知、认证和 Web 管理流程。
|
||||
|
||||
正式交付仅包含 Web 和服务端。CLI 限定为初始化、服务启动、运维诊断、数据库迁移、备份恢复、服务安装和卸载入口;历史 `domain` 命令保留兼容,不再扩展成另一套业务管理界面。Wails 历史实现不参与正式发布及测试门禁。
|
||||
正式交付仅包含 Web 和服务端。CLI 限定为初始化、服务启动、运维诊断、数据库维护、备份恢复、服务安装和卸载入口;历史 `domain`、`server`、`ssh-key`、`renew`、`deploy` 命令已停用,仅返回中文迁移提示,不执行原业务操作。命令边界见 `../doc/命令行运维范围说明.md`。Wails 历史实现不参与正式发布及测试门禁。
|
||||
|
||||
## 当前已实现
|
||||
|
||||
@ -13,7 +13,7 @@ Scert 是面向 Windows 和 Linux 的 SSL 证书管理服务。当前代码已
|
||||
- 三种数据库的迁移脚本、嵌入检查和迁移历史保护;实际版本及验证边界见 `../doc/构建版本与数据库支持矩阵.md`。
|
||||
- 域名基础模型与 Repository。
|
||||
- 健康检查、状态和域名基础 API。
|
||||
- 中文 CLI:`version`、`help`、`init`、`status`、`serve`、`domain list`、`domain add`。
|
||||
- 中文运维 CLI:`version`、`help`、`init`、`status`、`serve`、证书诊断、日志、配置、备份恢复和系统服务管理。
|
||||
- Vue 前端管理页面。
|
||||
|
||||
## 首轮运行
|
||||
@ -23,13 +23,13 @@ Scert 是面向 Windows 和 Linux 的 SSL 证书管理服务。当前代码已
|
||||
```powershell
|
||||
go run ./cmd/scert init --base-dir C:\ScertData
|
||||
go run ./cmd/scert status --base-dir C:\ScertData
|
||||
go run ./cmd/scert domain add --base-dir C:\ScertData --name example.com --type single
|
||||
go run ./cmd/scert domain list --base-dir C:\ScertData
|
||||
go run ./cmd/scert serve --base-dir C:\ScertData
|
||||
```
|
||||
|
||||
服务启动后可访问:
|
||||
|
||||
业务操作应在 Web 登录后进行。下列接口沿用服务端认证及授权规则,不能因列在运行示例中就视为允许匿名调用:
|
||||
|
||||
- `GET /healthz`
|
||||
- `GET /api/v1/status`
|
||||
- `GET /api/v1/domains`
|
||||
|
||||
@ -66,7 +66,7 @@ func TestSetConfigValueUpdatesAndValidatesAllowedFields(t *testing.T) {
|
||||
|
||||
func TestRootIncludesOperationalCommands(t *testing.T) {
|
||||
root := newRootCommand()
|
||||
for _, name := range []string{"certificate", "renew", "deploy", "logs", "config", "backup", "restore"} {
|
||||
for _, name := range []string{"certificate", "logs", "config", "backup", "restore", "service", "dns"} {
|
||||
if root.CommandPath() == name || root.Commands() == nil {
|
||||
t.Fatalf("根命令状态异常:%s", name)
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ func Execute() {
|
||||
}
|
||||
|
||||
func newRootCommand() *cobra.Command {
|
||||
root := &cobra.Command{Use: "scert", Short: "SSL 证书管理服务", SilenceUsage: true}
|
||||
root := &cobra.Command{Use: "scert", Short: "SSL 证书服务与运维工具,业务管理请使用 Web", SilenceUsage: true}
|
||||
root.CompletionOptions.DisableDefaultCmd = true
|
||||
root.SetHelpCommand(newHelpCommand())
|
||||
root.SetHelpTemplate(helpTemplate)
|
||||
@ -72,14 +72,30 @@ func newRootCommand() *cobra.Command {
|
||||
root.PersistentFlags().StringVar(&baseDir, "base-dir", "", "Windows 默认安装根目录")
|
||||
root.AddCommand(
|
||||
&cobra.Command{Use: "version", Short: "显示版本信息", Run: func(cmd *cobra.Command, args []string) { cmd.Printf("Scert %s\n", version) }},
|
||||
newInitCommand(), newStatusCommand(), newServeCommand(), newDomainCommand(), newCertificateCommand(),
|
||||
newRenewCommand(), newDeployCommand(), newLogsCommand(), newConfigCommand(), newBackupCommand(), newRestoreCommand(),
|
||||
newServerCommand(), newSSHKeyCommand(), newServiceCommand(), newDNSCommand(),
|
||||
newInitCommand(), newStatusCommand(), newServeCommand(), newCertificateCommand(),
|
||||
newLogsCommand(), newConfigCommand(), newBackupCommand(), newRestoreCommand(),
|
||||
newServiceCommand(), newDNSCommand(),
|
||||
)
|
||||
for _, name := range []string{"domain", "server", "ssh-key", "renew", "deploy"} {
|
||||
root.AddCommand(newRetiredBusinessCommand(name))
|
||||
}
|
||||
localizeHelpFlags(root)
|
||||
return root
|
||||
}
|
||||
|
||||
// 历史业务命令只保留迁移提示,不读取配置、凭据或数据库,也不执行远程操作。
|
||||
func newRetiredBusinessCommand(name string) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: name,
|
||||
Short: "业务命令已迁移至 Web 管理页面",
|
||||
Hidden: true,
|
||||
DisableFlagParsing: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("此业务命令已停用,请使用 Web 管理页面;CLI 仅保留初始化、服务运行和运维诊断、数据库维护、备份恢复及系统服务管理")
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newHelpCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "help [命令]",
|
||||
|
||||
@ -72,29 +72,29 @@ func TestHelpSupportsSubcommand(t *testing.T) {
|
||||
var output bytes.Buffer
|
||||
root.SetOut(&output)
|
||||
root.SetErr(&output)
|
||||
root.SetArgs([]string{"help", "domain"})
|
||||
root.SetArgs([]string{"help", "certificate"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("查看子命令帮助失败:%v", err)
|
||||
}
|
||||
text := output.String()
|
||||
if !strings.Contains(text, "管理托管域名") || !strings.Contains(text, "添加托管域名") {
|
||||
if !strings.Contains(text, "查询和校验证书") || !strings.Contains(text, "校验当前证书") {
|
||||
t.Fatalf("子命令帮助内容不正确:%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelpIncludesServerManagementCommands(t *testing.T) {
|
||||
func TestHelpIncludesSystemServiceCommands(t *testing.T) {
|
||||
root := newRootCommand()
|
||||
var output bytes.Buffer
|
||||
root.SetOut(&output)
|
||||
root.SetErr(&output)
|
||||
root.SetArgs([]string{"help", "server"})
|
||||
root.SetArgs([]string{"help", "service"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("查看服务器管理帮助失败:%v", err)
|
||||
t.Fatalf("查看系统服务帮助失败:%v", err)
|
||||
}
|
||||
text := output.String()
|
||||
for _, expected := range []string{"管理部署服务器", "添加部署服务器", "编辑部署服务器", "删除部署服务器"} {
|
||||
for _, expected := range []string{"管理系统服务", "注册 Scert 系统服务", "取消注册 Scert 系统服务"} {
|
||||
if !strings.Contains(text, expected) {
|
||||
t.Fatalf("服务器管理帮助缺少 %q:%s", expected, text)
|
||||
t.Fatalf("系统服务帮助缺少 %q:%s", expected, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -117,19 +117,19 @@ func TestServerCommandUsesDefaultCertificatePathTemplates(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelpIncludesSSHKeyManagementCommands(t *testing.T) {
|
||||
func TestHelpIncludesDNSDiagnosticCommand(t *testing.T) {
|
||||
root := newRootCommand()
|
||||
var output bytes.Buffer
|
||||
root.SetOut(&output)
|
||||
root.SetErr(&output)
|
||||
root.SetArgs([]string{"help", "ssh-key"})
|
||||
root.SetArgs([]string{"help", "dns"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatalf("查看 SSH 私钥管理帮助失败:%v", err)
|
||||
t.Fatalf("查看 DNS 诊断帮助失败:%v", err)
|
||||
}
|
||||
text := output.String()
|
||||
for _, expected := range []string{"管理 SSH 部署私钥", "安全录入 SSH 私钥", "删除未被服务器使用的 SSH 私钥"} {
|
||||
for _, expected := range []string{"检查指定域名的阿里云 RAM 权限", "验证当前权限"} {
|
||||
if !strings.Contains(text, expected) {
|
||||
t.Fatalf("SSH 私钥管理帮助缺少 %q:%s", expected, text)
|
||||
t.Fatalf("DNS 诊断帮助缺少 %q:%s", expected, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
87
backend/internal/cli/scope_test.go
Normal file
87
backend/internal/cli/scope_test.go
Normal file
@ -0,0 +1,87 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRootExposesOnlyOperationalCommands(t *testing.T) {
|
||||
allowed := map[string]bool{
|
||||
"version": true, "init": true, "status": true, "serve": true,
|
||||
"certificate": true, "logs": true, "config": true,
|
||||
"backup": true, "restore": true, "service": true, "dns": true,
|
||||
}
|
||||
root := newRootCommand()
|
||||
for _, command := range root.Commands() {
|
||||
if command.Hidden {
|
||||
continue
|
||||
}
|
||||
if !allowed[command.Name()] {
|
||||
t.Errorf("正式 CLI 暴露了范围外命令:%s", command.Name())
|
||||
}
|
||||
delete(allowed, command.Name())
|
||||
}
|
||||
if len(allowed) != 0 {
|
||||
t.Fatalf("正式 CLI 缺少运维命令:%v", allowed)
|
||||
}
|
||||
var output bytes.Buffer
|
||||
root.SetOut(&output)
|
||||
root.SetArgs([]string{"help"})
|
||||
if err := root.Execute(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, name := range []string{"domain", "server", "ssh-key", "renew", "deploy"} {
|
||||
if strings.Contains(output.String(), "\n "+name+" ") {
|
||||
t.Errorf("正式帮助仍展示历史业务命令:%s", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetiredBusinessCommandsRejectBeforeAccessingData(t *testing.T) {
|
||||
cases := [][]string{
|
||||
{"domain", "list"},
|
||||
{"domain", "add", "--name", "example.com"},
|
||||
{"domain", "issue", "--id", "example"},
|
||||
{"domain", "import", "--private-key", "not-a-real-key.pem"},
|
||||
{"server", "add", "--password", "test-secret-not-real"},
|
||||
{"server", "delete", "--id", "example"},
|
||||
{"ssh-key", "add", "--name", "example"},
|
||||
{"ssh-key", "delete", "--id", "example"},
|
||||
{"renew"},
|
||||
{"renew", "--id", "example"},
|
||||
{"deploy", "--id", "example"},
|
||||
}
|
||||
for _, args := range cases {
|
||||
t.Run(strings.Join(args[:min(2, len(args))], "_"), func(t *testing.T) {
|
||||
directory := t.TempDir()
|
||||
path := filepath.Join(directory, "invalid.json")
|
||||
original := []byte("invalid-config-sentinel")
|
||||
if err := os.WriteFile(path, original, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
root := newRootCommand()
|
||||
var output bytes.Buffer
|
||||
root.SetOut(&output)
|
||||
root.SetErr(&output)
|
||||
root.SetArgs(append([]string{"--config", path, "--base-dir", directory}, args...))
|
||||
err := root.Execute()
|
||||
if err == nil || !strings.Contains(err.Error(), "此业务命令已停用,请使用 Web 管理页面") {
|
||||
t.Fatalf("旧入口未在读取无效配置前拒绝:%v", err)
|
||||
}
|
||||
if strings.Contains(output.String()+err.Error(), "test-secret-not-real") {
|
||||
t.Fatal("迁移提示泄露了旧命令中的凭据参数")
|
||||
}
|
||||
content, readErr := os.ReadFile(path)
|
||||
if readErr != nil || !bytes.Equal(content, original) {
|
||||
t.Fatalf("被停用命令修改了配置:%v", readErr)
|
||||
}
|
||||
entries, readErr := os.ReadDir(directory)
|
||||
if readErr != nil || len(entries) != 1 {
|
||||
t.Fatalf("被停用命令创建了运行数据:%v", readErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
> 2026-09-27 范围调整:本文件保留早期开发历史,当前执行以《Scert整改合并优化清单》和《Scert整改任务执行清单》为准。正式交付仅为 Web 和 Windows/Linux 服务端;本文件中的 Wails 桌面窗口、托盘、桌面更新、桌面配置和桌面 UI 测试均退出正式开发及验收范围,不再作为未完成交付项。CLI 限定为初始化及服务运维,不另建业务管理界面。
|
||||
|
||||
> 同日 CLI 调整:下文 `domain`、`server`、`ssh-key`、`renew`、`deploy` 等业务命令及其测试结果仅为历史记录,当前正式入口已停用,请使用 Web;详见《命令行运维范围说明》。
|
||||
|
||||
> 2026-09-15 最新进展:见 [发布加固与实机验收记录](发布加固与实机验收记录.md)。初始化事务、远程部署锁、回滚与 SSH 安全依赖已加固;Linux 候选已构建并通过隔离实机推送验收。管理端仍未完成初始化,正式 ACME、业务 reload、TLS/SNI 和浏览器全流程继续标记 `[!]`,不是生产放行。
|
||||
|
||||
> 文档用途:作为 Scert 项目后续开发、进度跟踪、阶段复审和验收的执行清单。
|
||||
|
||||
@ -33,9 +33,9 @@
|
||||
|
||||
| 编号 | 状态 | 任务 | 当前问题 | 下一步交付 | 验证证据 |
|
||||
|---|---:|---|---|---|---|
|
||||
| P0-01 | [~] | 明确产品范围 | 已移除正式发布的 Wails 路径,历史源码保留;双平台实际包和 CLI 历史业务入口仍待复核 | 核查正式归档、兼容参数和运维 CLI 边界 | 范围审查、发布包文件清单 |
|
||||
| P0-01 | [~] | 明确产品范围 | 双平台和独立克隆发布范围验证通过;CLI 业务入口已停用,最终可执行文件待核查 | 核查收敛后的 CLI 发布产物,完成范围复审 | 范围审查、发布包文件清单、CLI 回归测试 |
|
||||
| P0-02 | [~] | 建立完整任务清单 | 已覆盖 44 项,逐项依赖、涉及文件和具体实机步骤仍需补充 | 持续维护状态、证据和复审结果 | 本文件提交记录 |
|
||||
| P0-03 | [~] | 整理源码、构建产物和部署产物 | 已取消跟踪桌面二进制和 dist,补强忽略规则,本地文件保留 | 独立克隆验证正式发布和生成物边界,不再要求桌面构建 | `git ls-files`、`git check-ignore`、工作区复核 |
|
||||
| P0-03 | [~] | 整理源码、构建产物和部署产物 | 独立克隆无桌面二进制和 dist,正式构建通过;根级归档及通用临时文件忽略规则仍需补齐 | 补齐全仓库忽略边界、发布及证据目录说明,保留本地历史文件 | `git ls-files`、`git check-ignore`、独立克隆发布验证 |
|
||||
| P0-04 | [~] | 统一开发和构建版本 | 模块实际使用 Go `1.26.6`,不存在此前误报的版本阻塞;历史文档仍需统一 | 统一模块、构建说明、锁文件和验收机版本记录 | 版本矩阵、构建日志 |
|
||||
| P0-05 | [!] | 确认数据库正式支持矩阵 | 三种数据库均有代码,但 README、文档和实机证据口径不完全一致 | 明确 SQLite、MySQL、PostgreSQL 的正式级别、版本和迁移回滚要求 | 三数据库迁移、备份恢复和连接测试 |
|
||||
| P0-06 | [~] | 建立统一领域模型 | 已有域名、证书、任务、服务器等实体,项目和部署关联仍需审查 | 补齐资源关系图、外键/归属和任务关联 | 模型文档、迁移检查、接口测试 |
|
||||
@ -147,5 +147,24 @@
|
||||
- 旧参数 `SkipDesktop` 仅警告并兼容,显式设假也不能恢复桌面构建;传入 `DesktopDirectory` 在构建前报错。
|
||||
- 保留路径扫描、Go `-trimpath`、文件及归档 SHA256、拒绝覆盖旧输出、源码提交和脏状态记录。
|
||||
- 已通过 PowerShell 语法解析、`go test -count=1 -timeout=3m ./internal/releasearchive ./cmd/scert-release`、`git diff --check`。
|
||||
- 待执行:从干净提交构建 Windows/Linux 正式范围候选包,核对清单、归档内容和校验和;验证旧参数拒绝路径。此为构建层验证,不代表 Windows/Linux 实机安装验收。
|
||||
- 待复核:历史 `domain` CLI 兼容入口仍存在,需确认收敛方式;因此 P0-01 继续保持 `[~]`,不提前标记整个任务完成。
|
||||
- 发布范围验证已完成,证据见下节;这仍是构建层验证,不代表 Windows/Linux 实机安装验收。
|
||||
- 历史业务 CLI 的执行入口已在后续批次停用,最终可执行文件仍待检查;P0-01 暂保持 `[~]`。
|
||||
|
||||
### 2026-09-27:双平台和独立克隆发布验证
|
||||
|
||||
- 源码提交:`25fd4cf`,已推送。默认双平台构建成功,`manifest.json` 的 `source_dirty=false`、`delivery_scope=[web,server]`、`desktop_requested=false`、路径检查通过。
|
||||
- 输出:`build/release-scope-20260927-25fd4cf/`。清单共 33 项(31 个包内文件、2 个归档),逐项文件长度和 SHA256 匹配。
|
||||
- 真实解包核对:Windows 9 个文件、8 条包内校验和;Linux 22 个文件、21 条包内校验和。解包内容与清单一致,无桌面产物。
|
||||
- `DesktopDirectory` 反例返回退出码 1,且没有创建输出目录。
|
||||
- 独立克隆:`build/checkout-scope-20260927-25fd4cf/`。执行 `npm.cmd ci --no-audit --no-fund`、`npm.cmd test`,150 项通过;显式 `-SkipDesktop:$false` 构建双平台通过,33 项清单的长度和 SHA256 再次匹配。
|
||||
- 独立克隆保留 `desktop/main.go`,不包含 `desktop/desktop.exe` 或桌面 dist。跟踪清单没有 `.runtime`、`node_modules`、dist、可执行文件、数据库或私钥后缀文件;克隆工作区仍干净。
|
||||
- `npm ci` 提示 esbuild 的安装脚本尚未列入批准清单,但命令、前端测试及构建均退出成功;未自动批准额外脚本。可复现安装策略仍归 P0-04 后续审查。
|
||||
|
||||
### 2026-09-27:CLI 运维范围收敛
|
||||
|
||||
- 依赖 P0-01 正式范围;涉及 `backend/internal/cli/root.go`、根命令/范围/运维测试、README 和《命令行运维范围说明》。
|
||||
- `domain`、`server`、`ssh-key`、`renew`、`deploy` 不再注册业务实现;仅保留隐藏的中文迁移提示,返回错误,不解析或回显旧凭据参数。
|
||||
- 保留初始化、服务启动、状态、证书诊断、DNS 诊断、配置、日志、备份恢复及系统服务运维;服务端自动续期未更改。
|
||||
- 新增命令树白名单和 11 类旧入口拒绝测试;用无效配置和模拟凭据证明拒绝先于配置读取,配置内容不变且没有新增运行数据。
|
||||
- CLI 定向测试、后端全量 `go test -p 1 -count=1 -timeout=3m ./...` 和 `go vet -p=1 ./...` 已通过。使用测试临时目录,没有清空或连接生产数据库。
|
||||
- 下一步:从本批干净提交构建发布包,运行实际 Windows 可执行文件的帮助和旧入口退出码检查;Linux 安装及服务运行仍需独立实机验证。
|
||||
|
||||
51
doc/命令行运维范围说明.md
Normal file
51
doc/命令行运维范围说明.md
Normal file
@ -0,0 +1,51 @@
|
||||
# 命令行运维范围说明
|
||||
|
||||
## 一、正式范围
|
||||
|
||||
依据《Scert整改合并优化清单》P0-01,正式产品为 Web 管理页面和 Windows/Linux 服务端。CLI 是本机运维入口,不再维护另一套域名、服务器或凭据业务管理界面。
|
||||
|
||||
| 入口 | 用途 | 边界 |
|
||||
|---|---|---|
|
||||
| `version`、`help` | 版本和中文帮助 | 不启动业务服务 |
|
||||
| `init` | 首次配置初始化 | 仍执行初始化参数、凭据和防火墙检查 |
|
||||
| `serve` | 启动正式服务及首次初始化入口 | 定时续期由服务端生命周期管理 |
|
||||
| `status` | 本机状态诊断 | 不替代公网 HTTPS 或生产验收 |
|
||||
| `certificate list/show/validate` | 查询现有证书及校验 | 不提供申请、导入、续期或部署操作 |
|
||||
| `logs` | 本机日志诊断 | 不替代完整审计中心 |
|
||||
| `config` | 本机配置诊断及受限配置调整 | 保留现有字段白名单,不允许直接写入密码摘要 |
|
||||
| `dns check` | 指定域名的 DNS 权限诊断 | 保留写入确认、保护域和精确清理限制,不能擅自执行真实 DNS 测试 |
|
||||
| `backup`、`restore` | 停服备份恢复及数据库维护 | 仍须校验维护锁、备份完整性、凭据、数据库版本及失败回滚 |
|
||||
| `service` | 注册、卸载、启停系统服务 | 必须遵循目标平台权限及安装要求 |
|
||||
| `scert-admin` | 超级管理员密码恢复 | 继续使用受保护本机 IPC,不开放公网重置接口 |
|
||||
|
||||
数据库迁移仍由现有初始化/应用加载路径执行,本次没有新增独立 `migrate` 命令;该说明不意味着三种数据库的实机迁移已经验收。
|
||||
|
||||
## 二、停用的业务入口
|
||||
|
||||
以下一级命令不再出现在默认帮助中,也不会执行原有操作:
|
||||
|
||||
- `domain`:域名增删改查、证书申请或导入、服务器关联等。
|
||||
- `server`:部署服务器管理。
|
||||
- `ssh-key`:部署私钥管理。
|
||||
- `renew`:手动续期或触发续期检查。
|
||||
- `deploy`:手动证书部署。
|
||||
|
||||
调用旧命令时返回非零退出状态及中文提示,要求使用 Web 管理页面。拒绝发生在读取配置、凭据或数据库之前,不尝试建立 SSH、DNS 或 ACME 连接,不输出旧参数中的密码。旧子命令和参数不会恢复原行为。
|
||||
|
||||
旧命令实现文件暂时保留以保存历史和已有回归测试,但正式命令树不再注册这些实现;不以隐藏帮助代替停用执行。
|
||||
|
||||
## 三、迁移方法
|
||||
|
||||
1. 保留用于启动服务、查看状态、诊断、备份恢复及平台服务管理的现有运维流程。
|
||||
2. 停止依赖旧业务命令的定时任务和自动化调用,避免非零退出被误当成成功。
|
||||
3. 在 Web 中管理域名、DNS 账户、服务器和 SSH 凭据,发起手动申请、续期、导入及部署。
|
||||
4. 自动续期继续由服务端执行,不需要额外配置 `scert renew` 定时任务。
|
||||
|
||||
这次变更只收敛 CLI 入口,不代表 Web 的统一任务中心、项目隔离、完整审计或生产门禁已全部完成;这些仍按对应整改项执行。
|
||||
|
||||
## 四、验证要求
|
||||
|
||||
- 根命令树只公开范围内运维入口,默认帮助不列出停用命令。
|
||||
- 旧命令包含原有参数、无效配置或模拟凭据时,都在访问数据前拒绝;不改动配置、不新建运行数据、不回显凭据。
|
||||
- 保留证书诊断、DNS 诊断、配置、备份恢复、初始化和服务管理测试。
|
||||
- 从实际构建的可执行文件检查帮助与旧入口退出码;单元测试不替代发布产物验证。
|
||||
Loading…
Reference in New Issue
Block a user