-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathconfig_ensure.go
249 lines (222 loc) · 5.88 KB
/
config_ensure.go
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
package gitdir
import (
"github.com/belak/go-gitdir/internal/yaml"
"github.com/belak/go-gitdir/models"
)
func ensureSampleConfig(data []byte) ([]byte, error) {
rootNode, modified, err := ensureSampleConfigYaml(data)
if err != nil {
return nil, err
}
if !modified {
return data, nil
}
return rootNode.Encode()
}
func ensureSampleConfigYaml(data []byte) (*yaml.Node, bool, error) {
rootNode, targetNode, err := yaml.EnsureDocument(data)
if err != nil {
return nil, false, err
}
vals := [5]bool{
ensureSampleInvites(targetNode),
ensureSampleUsers(targetNode),
ensureSampleGroups(targetNode),
ensureSampleOrgs(targetNode),
ensureSampleOptions(targetNode),
}
// If we had to make any of the modifications, we need to specify the node
// was updated.
return rootNode, vals[0] || vals[1] || vals[2] || vals[3], nil
}
func ensureSampleInvites(targetNode *yaml.Node) bool {
_, modified := targetNode.EnsureKey(
"invites",
yaml.NewMappingNode(),
&yaml.EnsureOptions{
Comment: `
Invites define temporary codes for a user to get in to the service. They
can SSH in using ssh invite:invite-code@go-code and it will add that public
key to their user.
#
Sample invites:
#
invites:
orai7Quaipoocungah1vee6Ieh8Ien: belak`,
},
)
return modified
}
func ensureSampleUsers(targetNode *yaml.Node) bool {
_, modified := targetNode.EnsureKey(
"users",
yaml.NewMappingNode(),
&yaml.EnsureOptions{
Comment: `
Users defines the users who have access to the service. They will need an
SSH key or invite added to their user account before they can access the
server.
#
Sample user (with all options set):
#
belak:
is_admin: true
disabled: false
keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDeQfBUWIqpGXS8xCOg/0RKVOGTnzpIdL7r9wK1/xA52 belak@tmp`,
},
)
return modified
}
func ensureSampleGroups(targetNode *yaml.Node) bool {
_, modified := targetNode.EnsureKey(
"groups",
yaml.NewMappingNode(),
&yaml.EnsureOptions{
Comment: `
Groups can be used in any place a normal user could be used. They are prefixed
with a $, so the admins group could be accessed with $admins. Groups can be
defined recursively, but they cannot have loops.
#
Sample groups:
#
groups:
admins:
- belak
- some-trusted-user
vault-members:
- $admins
- some-less-trusted-user`,
},
)
return modified
}
func ensureSampleOrgs(targetNode *yaml.Node) bool {
_, modified := targetNode.EnsureKey(
"orgs",
yaml.NewMappingNode(),
&yaml.EnsureOptions{
Comment: `
Org repos are accessible at @org-name/repo. Note that if admins is not
specified, the only users with admin access will be global admins. By
default, all members of an org will have read-write access to repos. This
can be changed with the read and write keys.
#
Sample org (with all options set):
#
vault:
admins:
- belak
write:
- some user
read:
- some-other-user
repos:
project-name-here:
public: false
write:
- belak
read:
- some-user
- some-other-user`,
},
)
return modified
}
// NOTE: this would make more sense as a map, but we want to keep the order.
var sampleOptions = []struct {
Name string
Comment string
Tag yaml.ScalarTag
Value string
}{
{
Name: "git_user",
Comment: "which username to use as the global git user",
Value: models.DefaultAdminConfigOptions.GitUser,
},
{
Name: "org_prefix",
Comment: "the prefix to use when cloning org repos",
Value: models.DefaultAdminConfigOptions.OrgPrefix,
},
{
Name: "user_prefix",
Comment: "the prefix to use when cloning user repos",
Value: models.DefaultAdminConfigOptions.UserPrefix,
},
{
Name: "invite_prefix",
Comment: "the prefix to use when sshing in with an invite",
Value: models.DefaultAdminConfigOptions.InvitePrefix,
},
{
Name: "implicit_repos",
Comment: `allow users with admin access to a given area to create repos by simply
pushing to them.`,
Tag: "!!bool",
Value: "false",
},
{
Name: "user_config_keys",
Comment: `allows users to specify ssh keys in their own config, rather than relying
on the main admin config.`,
Tag: "!!bool",
Value: "false",
},
{
Name: "user_config_repos",
Comment: `allows users to specify repos in their own config, rather than relying on
the main admin config.`,
Tag: "!!bool",
Value: "false",
},
{
Name: "org_config_repos",
Comment: `allows org admins to specify repos in their own config, rather than
relying on the main admin config.`,
Tag: "!!bool",
Value: "false",
},
}
func ensureSampleOptions(targetNode *yaml.Node) bool {
optionsVal, modified := targetNode.EnsureKey(
"options",
yaml.NewMappingNode(),
nil,
)
// Ensure all our options are on the options struct.
for _, opt := range sampleOptions {
_, added := optionsVal.EnsureKey(
opt.Name,
yaml.NewScalarNode(opt.Value, opt.Tag),
&yaml.EnsureOptions{Comment: opt.Comment},
)
modified = modified || added
}
return modified
}
func ensureAdminUser(data []byte, username, pubKey string) ([]byte, error) {
rootNode, modified, err := ensureAdminUserYaml(data, username, pubKey)
if err != nil {
return nil, err
}
if !modified {
return data, nil
}
return rootNode.Encode()
}
func ensureAdminUserYaml(data []byte, username, pubKey string) (*yaml.Node, bool, error) {
rootNode, targetNode, err := yaml.EnsureDocument(data)
if err != nil {
return nil, false, err
}
usersNode, _ := targetNode.EnsureKey("users", yaml.NewMappingNode(), nil)
userNode, _ := usersNode.EnsureKey(username, yaml.NewMappingNode(), nil)
keysNode, _ := userNode.EnsureKey("keys", yaml.NewSequenceNode(), nil)
modified := keysNode.AppendUniqueScalar(yaml.NewScalarNode(pubKey, ""))
// Ensure this user is an admin and isn't disabled
_, adminModified := userNode.EnsureKey("is_admin", yaml.NewScalarNode("true", yaml.ScalarTagBool), nil)
disabledModified := userNode.RemoveKey("disabled")
return rootNode, modified || disabledModified || adminModified, nil
}