Some checks are pending
Security Checks / security (push) Waiting to run
部署脚本、外部数据库初始化保护及统一证书域名配置已完成;不保留旧运行数据。
110 lines
3.5 KiB
Go
110 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestWindowsDeploymentScriptsKeepAdminChannelManual(t *testing.T) {
|
|
root := filepath.Clean(filepath.Join("..", "..", ".."))
|
|
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-windows.ps1"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
content := string(installer)
|
|
for _, required := range []string{
|
|
"sc.exe",
|
|
"smail-admin.exe",
|
|
"Set-RestrictedAcl",
|
|
"sidtype",
|
|
"$PackageRoot = $null",
|
|
"$PackageRoot = Split-Path -Parent $PSScriptRoot",
|
|
"NT SERVICE\\Smail:(F)",
|
|
"不会自动注册或启动服务",
|
|
} {
|
|
if !strings.Contains(content, required) {
|
|
t.Fatalf("Windows installer is missing %q", required)
|
|
}
|
|
}
|
|
if !hasUTF8BOM(installer) {
|
|
t.Fatal("Windows installer must be encoded as UTF-8 with BOM for Windows PowerShell")
|
|
}
|
|
serviceSetup := strings.Index(content, `"sidtype", "Smail", "unrestricted"`)
|
|
aclSetup := strings.Index(content, "Set-RestrictedAcl -Root $resolvedInstallRoot")
|
|
if serviceSetup < 0 || aclSetup < 0 || serviceSetup > aclSetup {
|
|
t.Fatal("Windows installer must create the service SID before applying service ACLs")
|
|
}
|
|
for _, forbidden := range []string{
|
|
"create SmailAdmin",
|
|
"Start-Service -Name \"SmailAdmin\"",
|
|
"start= auto" + "\n" + "start= auto",
|
|
} {
|
|
if strings.Contains(content, forbidden) {
|
|
t.Fatalf("Windows installer contains forbidden admin-service action %q", forbidden)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWindowsInstallerRequiresExplicitFreshReset(t *testing.T) {
|
|
root := filepath.Clean(filepath.Join("..", "..", ".."))
|
|
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-windows.ps1"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
content := string(installer)
|
|
for _, required := range []string{
|
|
"[switch]$Fresh",
|
|
"确认全新部署 Smail",
|
|
".smail-fresh-backup-",
|
|
"不会保留旧配置、数据库、证书、日志、插件或绑定信息。",
|
|
"Remove-Item -LiteralPath $item.FullName -Recurse -Force",
|
|
} {
|
|
if !strings.Contains(content, required) {
|
|
t.Fatalf("Windows installer is missing explicit fresh-reset behavior %q", required)
|
|
}
|
|
}
|
|
forbidden := []string{
|
|
"Copy-Item -LiteralPath $item.FullName -Destination (Join-Path $backupRoot $item.Name) -Recurse -Force",
|
|
"$backupRoot = Join-Path",
|
|
"正常升级不会覆盖配置、证书或数据库",
|
|
}
|
|
for _, value := range forbidden {
|
|
if strings.Contains(content, value) {
|
|
t.Fatalf("Windows installer retains forbidden legacy-data behavior %q", value)
|
|
}
|
|
}
|
|
if strings.Contains(content, "全新部署已停止:$existing 不是空目录") {
|
|
t.Fatal("Windows installer must not reject existing data without an explicit fresh-reset request")
|
|
}
|
|
}
|
|
|
|
func hasUTF8BOM(data []byte) bool {
|
|
return len(data) >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[2] == 0xBF
|
|
}
|
|
|
|
func TestWindowsUninstallerPreservesData(t *testing.T) {
|
|
root := filepath.Clean(filepath.Join("..", "..", ".."))
|
|
uninstaller, err := os.ReadFile(filepath.Join(root, "deploy", "uninstall-windows.ps1"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
content := string(uninstaller)
|
|
if !hasUTF8BOM(uninstaller) {
|
|
t.Fatal("Windows uninstaller must be encoded as UTF-8 with BOM for Windows PowerShell")
|
|
}
|
|
if strings.Contains(content, "Remove-Item -LiteralPath $resolvedInstallRoot -Recurse") {
|
|
t.Fatal("Windows uninstaller recursively removes the data root")
|
|
}
|
|
for _, required := range []string{
|
|
"smail.exe",
|
|
"smail-admin.exe",
|
|
"配置、数据库、证书和用户数据未删除",
|
|
} {
|
|
if !strings.Contains(content, required) {
|
|
t.Fatalf("Windows uninstaller is missing %q", required)
|
|
}
|
|
}
|
|
}
|