-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy_test.go
More file actions
126 lines (110 loc) · 4.07 KB
/
deploy_test.go
File metadata and controls
126 lines (110 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"strings"
"testing"
)
func TestBuildDeployScript_Admin(t *testing.T) {
pubKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@host"
script := buildDeployScript(pubKey, true)
checks := []struct {
name string
contain string
}{
{"admin key path", `C:\ProgramData\ssh\administrators_authorized_keys`},
{"admin ssh dir", `C:\ProgramData\ssh`},
{"public key present", pubKey},
{"BOM-less UTF8", "New-Object System.Text.UTF8Encoding $false"},
{"AppendAllText", "[System.IO.File]::AppendAllText"},
{"icacls SYSTEM SID", "*S-1-5-18:(F)"},
{"icacls Administrators SID", "*S-1-5-32-544:(F)"},
{"icacls user SID", "*${userSid}:(F)"},
{"user SID lookup", "WindowsIdentity]::GetCurrent()).User.Value"},
{"duplicate check", "Select-String"},
{"inheritance remove keyFile", "icacls $keyFile /inheritance:r"},
{"inheritance remove sshDir", "icacls $sshDir /inheritance:r"},
{"LASTEXITCODE check", "LASTEXITCODE"},
}
for _, c := range checks {
t.Run(c.name, func(t *testing.T) {
if !strings.Contains(script, c.contain) {
t.Errorf("script should contain %q\n\nscript:\n%s", c.contain, script)
}
})
}
}
func TestBuildDeployScript_NormalUser(t *testing.T) {
pubKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@host"
script := buildDeployScript(pubKey, false)
checks := []struct {
name string
contain string
}{
{"user key path", `.ssh\authorized_keys`},
{"user ssh dir", `.ssh`},
{"public key present", pubKey},
{"BOM-less UTF8", "New-Object System.Text.UTF8Encoding $false"},
{"icacls SYSTEM SID", "*S-1-5-18:(F)"},
{"icacls Administrators SID", "*S-1-5-32-544:(F)"},
{"icacls user SID", "*${userSid}:(F)"},
{"user SID lookup", "WindowsIdentity]::GetCurrent()).User.Value"},
{"duplicate check", "Select-String"},
{"inheritance remove sshDir", "icacls $sshDir /inheritance:r"},
{"LASTEXITCODE check", "LASTEXITCODE"},
}
for _, c := range checks {
t.Run(c.name, func(t *testing.T) {
if !strings.Contains(script, c.contain) {
t.Errorf("script should contain %q\n\nscript:\n%s", c.contain, script)
}
})
}
// Admin専用のパスが含まれないことを確認
if strings.Contains(script, `C:\ProgramData\ssh\administrators_authorized_keys`) {
t.Error("normal user script should not contain admin key path")
}
}
func TestBuildDeployScript_AclValidation(t *testing.T) {
pubKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExample user@host"
for _, isAdmin := range []bool{true, false} {
name := "normal"
if isAdmin {
name = "admin"
}
t.Run(name, func(t *testing.T) {
script := buildDeployScript(pubKey, isAdmin)
if !strings.Contains(script, "ACL_SET_FAILED_DIR") || !strings.Contains(script, "ACL_SET_FAILED_FILE") {
t.Errorf("script should contain ACL_SET_FAILED_DIR and ACL_SET_FAILED_FILE markers\n\nscript:\n%s", script)
}
})
}
}
func TestBuildDeployScript_EscapesSingleQuotes(t *testing.T) {
pubKey := "ssh-ed25519 AAAAC3 it's a test"
script := buildDeployScript(pubKey, false)
if !strings.Contains(script, "it''s a test") {
t.Errorf("single quotes should be escaped with double single quotes\n\nscript:\n%s", script)
}
}
func TestBuildDeployScript_ErrorActionPreference(t *testing.T) {
script := buildDeployScript("ssh-ed25519 AAAA test", false)
if !strings.Contains(script, "$ErrorActionPreference = 'Stop'") {
t.Error("script should set ErrorActionPreference to Stop")
}
}
func TestBuildDeployScript_NoHardcodedPrincipalNames(t *testing.T) {
script := buildDeployScript("ssh-ed25519 AAAA test", false)
// 名前ベースのプリンシパルがicaclsコマンドに含まれないことを確認
// (SIDベースの *S-1-5-18 等を使用すべき)
lines := strings.Split(script, "\n")
for _, line := range lines {
if !strings.Contains(line, "icacls") {
continue
}
if strings.Contains(line, "'SYSTEM:(F)'") {
t.Errorf("icacls should use SID (*S-1-5-18) instead of name 'SYSTEM'\nline: %s", line)
}
if strings.Contains(line, "'Administrators:(F)'") {
t.Errorf("icacls should use SID (*S-1-5-32-544) instead of name 'Administrators'\nline: %s", line)
}
}
}