forked from beameio/beame-insta-ssl
-
Notifications
You must be signed in to change notification settings - Fork 1
/
test.ngs
executable file
·347 lines (287 loc) · 10.2 KB
/
test.ngs
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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/usr/bin/env ngs
assert('BEAME_INTERNAL_AUTH_SERVER_FQDN' in ENV, 'Environment variable BEAME_INTERNAL_AUTH_SERVER_FQDN must be set')
HOME = ENV.HOME
BEAME_DIR = HOME / '.beame'
if Path(BEAME_DIR) {
throw Error("Beame directory exists ($BEAME_DIR). Will not run tests.")
}
BEAME_INSTA_SSL_BIN = HOME / 'beame-insta-ssl/main.js'
BEAME_SDK_BIN = HOME / 'beame-sdk/src/cli/beame.js'
BEAME_DEV_AUTH_FQDN = 'n6ge8i9q4b4b5vb6.h40d7vrwir2oxlnn.v1.d.beameio.net'
EXPECTED_EXPORTED_FILE_EXTENSIONS = %[pem key chain.p7b pkcs12 pkcs12.pwd]
# ---------- Utilities ----------
F base64encode(s:Str) {
fname = "/tmp/base64.${c_getpid()}"
$(echo $s >$fname)
ret = `base64 -w0 <$fname`
$(rm $fname)
log("base64 done")
ret
}
F base64decode(s:Str) {
fname = "/tmp/base64decode.${c_getpid()}"
$(echo $s >$fname)
ret = `base64 -d <$fname`
$(rm $fname)
log("base64 decode done")
ret
}
F fqdn_dir(fqdn) "$HOME/.beame/v2/$fqdn"
# ---------- Tests code ----------
doc Copies Beame test requests signing credential into store for L0 entity creation
F copy_to_store() {
$(cp -a "$HOME/$BEAME_DEV_AUTH_FQDN" ${fqdn_dir(BEAME_DEV_AUTH_FQDN)})
TestMessage('Copied')
}
doc Creates token needed for signing request for level 0 entity
F create_token() {
global token = `$BEAME_SDK_BIN token create --fqdn $BEAME_DEV_AUTH_FQDN --data NONE`
assert(token is Str, "Token expected to be a string")
TestMessage(token)
}
doc Creates level 0 entity
F create_entity() {
global fqdn
t = time()
beame_insta_ssl_token = {
'authToken': token.base64decode().parse()
'authSrvFqdn': ENV.BEAME_INTERNAL_AUTH_SERVER_FQDN
'name': "insta-ssl-test-L0-$t"
'email': "insta-ssl-L0-${t}@example.com"
}
entity = ``$BEAME_INSTA_SSL_BIN creds getCreds --regToken ${beame_insta_ssl_token.encode_json()} --format json``
assert_hash(entity, "Entity must be hash")
fqdn = entity.fqdn
TestMessage("Entity $fqdn created")
}
doc Removes Beame test requests signing credential from store
F remove_from_store() {
$(rm -r ${fqdn_dir(BEAME_DEV_AUTH_FQDN)})
TestMessage('Removed')
}
doc Checks that process outputs specific text and exists with non-zero code
F should_fail_with_text(cmd:Command, text:Str) {
try {
$($cmd)
throw TestFail('Exited with code 0')
} catch(e:ProcessFail) {
text not in e.process.stdout throws TestFail("No expected text in output")
return 'Expected text found'
}
}
doc Tests non-terminating tunnel
F https_target_tunnel(cmd:Command) {
t = time().Str()
cmd.options['&'] = true
processes = [
$(node testHttpsServer.js $fqdn $t &)
$($cmd)
]
$(sleep 10)
out = try `curl --silent --max-time 30 "https://$fqdn/"`
processes % kill
out != t throws TestFail("Result from server is missing or incorrect: '$out' vs '$t'")
TestMessage('Result from server is OK')
}
doc Tests terminating tunnel
F http_target_tunnel(cmd:Command, expected_hostname:Str, proto='https') {
t = time().Str()
cmd.options['&'] = true
processes = [
$(node testHttpServer.js $t &)
$($cmd)
]
$(sleep 10)
out = try `curl --silent --max-time 30 "$proto://$fqdn/"`
processes % kill
out != "$t-$expected_hostname" throws TestFail("Result from server is missing or incorrect: '$out' vs '$t-$expected_hostname'")
TestMessage('Result from server is OK')
}
doc Waits till hostname becomes resolvable (has DNS record)
F wait_resolvable(h:Str) {
test("Waiting for hostname $h to be resolvable", {
for(i;45) {
resolve = `dig "+short" $h`
resolve returns "Resolves to ${resolve.lines()[-1]}"
$(sleep 2)
}
throw TestFail("No resolve for $h")
})
}
F corrupt_metadata_json() {
metadata = ``cat "${fqdn_dir(fqdn)}/metadata.json"``
metadata.edge_fqdn = 'corrupted'
$(echo ${metadata.encode_json()} >"${fqdn_dir(fqdn)}/metadata.json")
metadata_json_ok(fqdn) throws TestFail("Metadata JSON is OK while should be corrupted")
TestMessage("Metadata file corrupted")
}
F metadata_json_ok(fqdn) {
metadata = ``cat "${fqdn_dir(fqdn)}/metadata.json"``
metadata.edge_fqdn != 'corrupted'
}
# ---------- No certificates test ----------
test("Run without certificates (old CLI)") with {
should_fail_with_text(%($BEAME_INSTA_SSL_BIN list), 'you have no certificates')
}
test("Run without certificates (new CLI, text)") with {
should_fail_with_text(%($BEAME_INSTA_SSL_BIN creds list), 'you have no certificates')
}
test("Run without certificates (new CLI, json)") with {
should_fail_with_text(%($BEAME_INSTA_SSL_BIN creds list --format json), 'you have no certificates')
}
# ---------- One certificate test ----------
test("Copy $BEAME_DEV_AUTH_FQDN into store", copy_to_store)
test("Create token for test L0 entity", create_token)
test("Create test L0 entity", create_entity);
test("Remove $BEAME_DEV_AUTH_FQDN from store", remove_from_store)
test("List certificates - one certificate (old CLI)", {
fqdns = `$BEAME_INSTA_SSL_BIN list`.lines()
assert(fqdns == [fqdn])
TestMessage('List is OK')
})
test("List certificates - one certificate (new CLI, text)", {
out = `$BEAME_INSTA_SSL_BIN creds list`.lines()
assert(out.len() == 5)
assert(out[1] ~ /name.*fqdn.*parent.*valid.*priv/)
assert(fqdn in out[3])
TestMessage('List is OK')
})
test("List certificates - one certificate (new CLI, json)", {
certs = ``$BEAME_INSTA_SSL_BIN creds list --format json``
assert(certs.metadata.fqdn == [fqdn])
TestMessage('List is OK')
})
test("Fix metadata (old CLI)", {
corrupt_metadata_json()
$($BEAME_INSTA_SSL_BIN syncmeta)
metadata_json_ok(fqdn).not() throws TestFail("Metadata JSON is not OK")
})
test("Fix metadata (new CLI)", {
corrupt_metadata_json()
$($BEAME_INSTA_SSL_BIN creds syncmeta --fqdn $fqdn)
metadata_json_ok(fqdn).not() throws TestFail("Metadata JSON is not OK")
})
each({
"old": %($BEAME_INSTA_SSL_BIN export $fqdn DIR)
"new": %($BEAME_INSTA_SSL_BIN creds exportCred --fqdn $fqdn --dir DIR)
}, F(cli_type:Str, c:Command) {
test("Export certificate ($cli_type CLI)", {
dir = `mktemp --tmpdir -d test-beame-insta-ssl.XXXXXXXXXX` - MaybeSfx('\n')
c.argv .= replace('DIR', dir)
finally()
body => {
$($c)
EXPECTED_EXPORTED_FILE_EXTENSIONS.each(F(ext) {
f = "$dir/$fqdn.$ext"
not($(test -s $f)) throws TestFail("File $f not found")
})
}
cleanup => {
$(rm -r $dir)
}
TestMessage('All expected files are present')
})
})
wait_resolvable(fqdn)
each({
"old": %[65500]
"new": %[make --dst 65500 --proto]
}, F (cli_type:Str, argv:Arr) {
test("eehttp tunnel without fqdn ($cli_type CLI)", {
http_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv eehttp), fqdn, 'http')
})
test("Non-terminating tunnel without fqdn ($cli_type CLI)", {
https_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv https))
})
test("Terminating tunnel without fqdn ($cli_type CLI)", {
http_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv http), 'localhost')
})
})
# ---------- 2 or more certificates test ----------
old_fqdn = fqdn
test("Copy $BEAME_DEV_AUTH_FQDN into store", copy_to_store)
test("Create token for additional test L0 entity", create_token)
test("Create additional test L0 entity", create_entity)
test("Remove $BEAME_DEV_AUTH_FQDN from store", remove_from_store)
test("Fix metadata (old CLI)", {
corrupt_metadata_json()
$($BEAME_INSTA_SSL_BIN syncmeta --fqdn $fqdn)
metadata_json_ok(fqdn).not() throws TestFail("Metadata JSON is not OK")
})
test("Fix metadata (new CLI)", {
corrupt_metadata_json()
$($BEAME_INSTA_SSL_BIN creds syncmeta --fqdn $fqdn)
metadata_json_ok(fqdn).not() throws TestFail("Metadata JSON is not OK")
})
test("List certificates - two certificates (old CLI)", {
certs = `$BEAME_INSTA_SSL_BIN list`.lines()
assert(certs.sort() == [old_fqdn, fqdn].sort())
})
test("List certificates - two certificates (new CLI, text)", {
# TODO: factor out textual output check
out = `$BEAME_INSTA_SSL_BIN creds list`.lines()
assert(out.len() == 7)
assert(out[1] ~ /name.*fqdn.*parent.*valid.*priv/)
assert(out.any(fqdn in X))
assert(out.any(old_fqdn in X))
TestMessage('List is OK')
})
test("List certificates - two certificates (new CLI, json)", {
certs = ``$BEAME_INSTA_SSL_BIN creds list --format json``
assert(certs.metadata.fqdn.sort() == [old_fqdn, fqdn].sort())
TestMessage('List is OK')
})
test("Run tunnel not specifying fqdn", {
should_fail_with_text(%($BEAME_INSTA_SSL_BIN tunnel 65500 https), 'more than one')
})
wait_resolvable(fqdn)
each({
"old": %[65500]
"new": %[make --dst 65500 --proto]
}, F (cli_type:Str, argv:Arr) {
test("eehttp tunnel with fqdn ($cli_type CLI)", {
http_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv eehttp --fqdn $fqdn), fqdn, 'http')
})
test("Non-terminating tunnel with fqdn ($cli_type CLI)", {
https_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv https --fqdn $fqdn))
})
test("Terminating tunnel with fqdn ($cli_type CLI)", {
http_target_tunnel(%($BEAME_INSTA_SSL_BIN tunnel $*argv http --fqdn $fqdn --hostname test1.example.com), 'test1.example.com')
})
})
test("Renewing cert for $fqdn") with {
# TODO: check with other args
s = ``$BEAME_INSTA_SSL_BIN creds renewCert --fqdn $fqdn --format json``
assert_hash_keys_values(s, {'status': 'ok'}, "Status OK")
}
# TESTS FROM SDK
test("[Registration token] Generate") with {
global reg_token
t = time()
reg_token = `$BEAME_INSTA_SSL_BIN creds getRegToken --fqdn $fqdn --name "insta-ssl-test-L1-$t" --email "insta-ssl-L1-${t}@example.com"`
}
test("[Registration token] Use") with {
# TODO: check content
child_entity = ``$BEAME_INSTA_SSL_BIN creds getCreds --regToken $reg_token --format json``
}
entity_name_pfx = "sdk-test-${time()}-${pid()}"
F create_entity_under_fqdn(fqdn, idx) {
entity_name_pfx = "insta-ssl-test-${time()}-${pid()}"
entity = ``$BEAME_INSTA_SSL_BIN creds getCreds --name "${entity_name_pfx}-${idx}" --email "${entity_name_pfx}-${idx}@example.com" --fqdn $fqdn --format json``
entity.assert_hash_keys(%[parent_fqdn level email name], "Entity hash keys")
entity.fqdn
}
for(i;2) {
# These tests must be towards the end as they update fqdn variable
test("Iteration [${i+1}/2] [fqdn $fqdn]") with {
global fqdn
fqdn = create_entity_under_fqdn(fqdn, i)
TestMessage("New entity: $fqdn")
}
}
test("Revoke cert") with {
# TODO: real test
# TODO: test with children - should get "can't be revoked, because children exists"
s = ``$BEAME_INSTA_SSL_BIN creds revokeCert --signerFqdn $fqdn --fqdn $fqdn --format json``
assert_hash_keys_values(s, {'status': 'ok'}, "Status OK")
}