Smail/backend/cmd/smail-admin/systemd_policy_test.go
smail 3ba7252948
Some checks are pending
Security Checks / security (push) Waiting to run
实现全新部署数据清理保护
部署脚本、外部数据库初始化保护及统一证书域名配置已完成;不保留旧运行数据。
2026-10-01 13:13:12 +08:00

168 lines
5.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestSystemdUnitIsManualStartOnly(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
unit, err := os.ReadFile(filepath.Join(root, "deploy", "systemd", "smail-admin.service"))
if err != nil {
t.Fatal(err)
}
content := string(unit)
for _, forbidden := range []string{
"[Install]",
"WantedBy=",
"RequiredBy=",
"Alias=",
"Restart=always",
"Restart=on-failure",
"ExecReload=",
"ReadWritePaths=/run/systemd/ask-password",
"PartOf=",
"BindsTo=",
"Wants=",
"Requires=",
"Upholds=",
"PropagatesReloadTo=",
"ReloadPropagatedFrom=",
} {
if strings.Contains(content, forbidden) {
t.Fatalf("smail-admin unit contains forbidden directive %q", forbidden)
}
}
for _, required := range []string{
"Type=oneshot",
"RemainAfterExit=no",
"Requisite=smail.service",
"Restart=no",
"PrivateNetwork=true",
"RestrictAddressFamilies=AF_UNIX",
"KillMode=mixed",
} {
if !strings.Contains(content, required) {
t.Fatalf("smail-admin unit is missing %q", required)
}
}
}
func TestInstallerDisablesAdminAutostart(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-systemd.sh"))
if err != nil {
t.Fatal(err)
}
content := string(installer)
for _, forbidden := range []string{
"systemctl enable smail-admin",
"systemctl enable --now smail-admin",
"systemctl start smail-admin",
"systemctl restart smail-admin",
} {
if strings.Contains(content, forbidden) {
t.Fatalf("installer contains forbidden smail-admin action %q", forbidden)
}
}
if strings.Contains(content, "systemctl preset smail-admin") {
t.Fatal("installer enables smail-admin")
}
if !strings.Contains(content, "systemctl disable smail-admin") {
t.Fatal("installer does not clear legacy smail-admin enablement")
}
}
func TestInstallerManagesProtectedEnvironmentFile(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-systemd.sh"))
if err != nil {
t.Fatal(err)
}
content := string(installer)
for _, required := range []string{
"/etc/smail/smail.env",
"install -d -o root -g root -m 0750 /etc/smail",
"if [ ! -e /etc/smail/smail.env ]; then",
"'SMAIL_ROOT=/opt/smail'",
"chmod 0600 /etc/smail/smail.env",
"每次部署都重新创建服务环境文件,不继承旧的凭据或代理配置。",
} {
if !strings.Contains(content, required) {
t.Fatalf("installer is missing protected environment-file behavior %q", required)
}
}
}
func TestInstallerRequiresExplicitFreshReset(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
installer, err := os.ReadFile(filepath.Join(root, "deploy", "install-systemd.sh"))
if err != nil {
t.Fatal(err)
}
content := string(installer)
for _, required := range []string{
"fresh=true",
"确认全新部署 Smail",
"for legacy_backup in /var/backups/smail-deploy-*",
"rm -rf -- \"$legacy_backup\"",
"find \"$runtime_dir\" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +",
"systemctl disable smail smail-admin",
} {
if !strings.Contains(content, required) {
t.Fatalf("installer is missing explicit fresh-reset behavior %q", required)
}
}
forbidden := []string{
"默认模式保留配置、数据库、证书、日志和插件",
"cp -a -- \"$runtime_dir/.\" \"$backup_dir/runtime/\"",
"cp -p -- /etc/smail/smail.env \"$backup_dir/smail.env\"",
"配置、数据库和证书未覆盖",
}
for _, value := range forbidden {
if strings.Contains(content, value) {
t.Fatalf("installer retains forbidden legacy-data behavior %q", value)
}
}
if strings.Contains(content, "全新部署已停止:$target 非空") {
t.Fatal("installer must not reject existing data without an explicit fresh-reset request")
}
}
func TestSmailServiceRetainsPluginIsolationCapabilities(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
unit, err := os.ReadFile(filepath.Join(root, "deploy", "systemd", "smail.service"))
if err != nil {
t.Fatal(err)
}
content := string(unit)
for _, required := range []string{
"EnvironmentFile=/etc/smail/smail.env",
"NoNewPrivileges=true",
"AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER",
"CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SYS_CHROOT CAP_SETUID CAP_SETGID CAP_CHOWN CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_FOWNER",
} {
if !strings.Contains(content, required) {
t.Fatalf("smail unit is missing %q", required)
}
}
usesEnvironmentFile := false
for _, line := range strings.Split(content, "\n") {
if strings.TrimSpace(line) == "EnvironmentFile=/etc/smail/smail.env" {
usesEnvironmentFile = true
break
}
}
if !usesEnvironmentFile {
t.Fatal("smail unit must define EnvironmentFile as a standalone directive")
}
if strings.Contains(content, "User=smail") || strings.Contains(content, "Group=smail") {
t.Fatal("smail unit must retain root privileges for plugin isolation")
}
if strings.Count(content, "CAP_NET_BIND_SERVICE") != 2 {
t.Fatal("smail unit does not retain the expected bind capability entries")
}
}