synapse 2.175.0__py311-none-any.whl → 2.177.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (73) hide show
  1. synapse/axon.py +24 -9
  2. synapse/cortex.py +330 -168
  3. synapse/cryotank.py +46 -37
  4. synapse/datamodel.py +17 -4
  5. synapse/exc.py +19 -0
  6. synapse/lib/agenda.py +7 -13
  7. synapse/lib/ast.py +6 -5
  8. synapse/lib/auth.py +1520 -0
  9. synapse/lib/cell.py +255 -53
  10. synapse/lib/grammar.py +5 -0
  11. synapse/lib/hive.py +24 -3
  12. synapse/lib/hiveauth.py +6 -32
  13. synapse/lib/layer.py +7 -4
  14. synapse/lib/link.py +21 -17
  15. synapse/lib/lmdbslab.py +149 -0
  16. synapse/lib/modelrev.py +1 -1
  17. synapse/lib/schemas.py +136 -0
  18. synapse/lib/storm.py +70 -33
  19. synapse/lib/stormlib/aha.py +1 -1
  20. synapse/lib/stormlib/auth.py +185 -10
  21. synapse/lib/stormlib/cortex.py +16 -5
  22. synapse/lib/stormlib/gen.py +80 -0
  23. synapse/lib/stormlib/model.py +55 -0
  24. synapse/lib/stormlib/modelext.py +60 -0
  25. synapse/lib/stormlib/storm.py +117 -5
  26. synapse/lib/stormlib/tabular.py +212 -0
  27. synapse/lib/stormtypes.py +14 -1
  28. synapse/lib/trigger.py +1 -1
  29. synapse/lib/version.py +2 -2
  30. synapse/lib/view.py +55 -28
  31. synapse/models/base.py +7 -0
  32. synapse/models/biz.py +4 -0
  33. synapse/models/files.py +8 -1
  34. synapse/models/inet.py +31 -0
  35. synapse/tests/files/changelog/model_2.176.0_16ee721a6b7221344eaf946c3ab4602dda546b1a.yaml.gz +0 -0
  36. synapse/tests/files/changelog/model_2.176.0_2a25c58bbd344716cd7cbc3f4304d8925b0f4ef2.yaml.gz +0 -0
  37. synapse/tests/test_axon.py +7 -4
  38. synapse/tests/test_cortex.py +127 -82
  39. synapse/tests/test_cryotank.py +4 -4
  40. synapse/tests/test_datamodel.py +7 -0
  41. synapse/tests/test_lib_agenda.py +7 -0
  42. synapse/tests/{test_lib_hiveauth.py → test_lib_auth.py} +314 -11
  43. synapse/tests/test_lib_cell.py +161 -8
  44. synapse/tests/test_lib_httpapi.py +18 -14
  45. synapse/tests/test_lib_layer.py +33 -33
  46. synapse/tests/test_lib_link.py +42 -1
  47. synapse/tests/test_lib_lmdbslab.py +68 -0
  48. synapse/tests/test_lib_nexus.py +4 -4
  49. synapse/tests/test_lib_node.py +0 -7
  50. synapse/tests/test_lib_storm.py +45 -0
  51. synapse/tests/test_lib_stormlib_aha.py +1 -2
  52. synapse/tests/test_lib_stormlib_auth.py +21 -0
  53. synapse/tests/test_lib_stormlib_cortex.py +12 -12
  54. synapse/tests/test_lib_stormlib_gen.py +99 -0
  55. synapse/tests/test_lib_stormlib_model.py +108 -0
  56. synapse/tests/test_lib_stormlib_modelext.py +64 -0
  57. synapse/tests/test_lib_stormlib_storm.py +82 -1
  58. synapse/tests/test_lib_stormlib_tabular.py +226 -0
  59. synapse/tests/test_lib_stormsvc.py +4 -1
  60. synapse/tests/test_lib_stormtypes.py +10 -0
  61. synapse/tests/test_model_base.py +3 -0
  62. synapse/tests/test_model_biz.py +3 -0
  63. synapse/tests/test_model_files.py +12 -2
  64. synapse/tests/test_model_inet.py +55 -0
  65. synapse/tests/test_tools_changelog.py +196 -0
  66. synapse/tests/test_tools_healthcheck.py +4 -3
  67. synapse/tests/utils.py +1 -1
  68. synapse/tools/changelog.py +774 -15
  69. {synapse-2.175.0.dist-info → synapse-2.177.0.dist-info}/METADATA +3 -3
  70. {synapse-2.175.0.dist-info → synapse-2.177.0.dist-info}/RECORD +73 -67
  71. {synapse-2.175.0.dist-info → synapse-2.177.0.dist-info}/WHEEL +1 -1
  72. {synapse-2.175.0.dist-info → synapse-2.177.0.dist-info}/LICENSE +0 -0
  73. {synapse-2.175.0.dist-info → synapse-2.177.0.dist-info}/top_level.txt +0 -0
@@ -955,6 +955,42 @@ class StormTest(s_t_utils.SynTest):
955
955
  | merge --apply
956
956
  ''', opts=opts)
957
957
 
958
+ # make a few more edits and merge some of them to test --wipe
959
+ await core.stormlist('[ inet:fqdn=hehehaha.com inet:fqdn=woottoow.com ]')
960
+
961
+ layrcount = len(core.layers.values())
962
+ await core.stormlist('[ inet:fqdn=hehehaha.com inet:fqdn=woottoow.com ]', opts=opts)
963
+ oldlayr = await core.callStorm('return($lib.view.get().layers.0.iden)', opts=opts)
964
+ msgs = await core.stormlist('inet:fqdn=hehehaha.com | merge --apply --wipe', opts=opts)
965
+ self.stormHasNoWarnErr(msgs)
966
+ newlayr = await core.callStorm('return($lib.view.get().layers.0.iden)', opts=opts)
967
+ self.ne(oldlayr, newlayr)
968
+ msgs = await core.stormlist('''
969
+ $layr = $lib.view.get().layers.0.iden
970
+ $user = $lib.auth.users.byname(visi)
971
+ $role = $lib.auth.roles.add(ninjas)
972
+
973
+ $user.grant($role.iden)
974
+
975
+ $user.setAdmin((true), gateiden=$layr)
976
+ $user.addRule(([true, ["foo", "bar"]]), gateiden=$layr)
977
+ $role.addRule(([true, ["baz", "faz"]]), gateiden=$layr)
978
+ ''', opts=opts)
979
+ self.stormHasNoWarnErr(msgs)
980
+ await core.callStorm('$lib.view.get().swapLayer()', opts=opts)
981
+ self.ne(newlayr, await core.callStorm('return($lib.view.get().layers.0.iden)', opts=opts))
982
+
983
+ self.true(await core.callStorm('''
984
+ $layr = $lib.view.get().layers.0.iden
985
+ return($lib.auth.users.byname(visi).allowed(foo.bar, gateiden=$layr))
986
+ ''', opts=opts))
987
+ self.true(await core.callStorm('''
988
+ $layr = $lib.view.get().layers.0.iden
989
+ return($lib.auth.users.byname(visi).allowed(baz.faz, gateiden=$layr))
990
+ ''', opts=opts))
991
+
992
+ self.len(0, await core.nodes('diff', opts=opts))
993
+
958
994
  self.len(0, await core.callStorm('''
959
995
  $list = $lib.list()
960
996
  for ($buid, $sode) in $lib.view.get().layers.0.getStorNodes() {
@@ -4235,6 +4271,15 @@ class StormTest(s_t_utils.SynTest):
4235
4271
  msgs = await core.stormlist(pushq, opts={'user': visi.iden, 'vars': varz})
4236
4272
  self.stormHasNoWarnErr(msgs)
4237
4273
 
4274
+ l1iden = l1.get('iden')
4275
+ pdef = list(core.getLayer(l1iden).layrinfo['pushs'].values())[0]
4276
+ self.none(await core.addLayrPush(l1iden, pdef))
4277
+ self.len(1, list(core.getLayer(l1iden).layrinfo['pushs'].values()))
4278
+
4279
+ pdef = list(core.getLayer(l1iden).layrinfo['pulls'].values())[0]
4280
+ self.none(await core.addLayrPull(l1iden, pdef))
4281
+ self.len(1, list(core.getLayer(l1iden).layrinfo['pulls'].values()))
4282
+
4238
4283
  async def test_storm_tagprune(self):
4239
4284
 
4240
4285
  async with self.getTestCore() as core:
@@ -146,8 +146,7 @@ Member: 00.cell.loop.vertex.link'''
146
146
  network='loop.vertex.link')
147
147
 
148
148
  msgs = await core00.stormlist('aha.svc.list --nexus')
149
- emsg = '00.newp.loop.vertex.link null false null 0.0.0.0 3030 ' \
150
- 'Service is not online. Will not attempt to retrieve its nexus offset.'
149
+ emsg = '00.newp.loop.vertex.link null false null 0.0.0.0 3030 <offline>'
151
150
  self.stormIsInPrint(emsg, msgs)
152
151
 
153
152
  self.none(await core00.callStorm('return($lib.aha.del(00.newp...))'))
@@ -480,6 +480,9 @@ class StormLibAuthTest(s_test.SynTest):
480
480
 
481
481
  await core.callStorm('$lib.user.vars.set(foo, foovalu)', opts=asvisi)
482
482
 
483
+ msgs = await core.stormlist('for $valu in $lib.user.vars { $lib.print($valu) }', opts=asvisi)
484
+ self.stormIsInPrint("('foo', 'foovalu')", msgs)
485
+
483
486
  q = 'return($lib.auth.users.byname(visi).vars.foo)'
484
487
  self.eq('foovalu', await core.callStorm(q, opts=asvisi))
485
488
 
@@ -494,6 +497,24 @@ class StormLibAuthTest(s_test.SynTest):
494
497
  await core.callStorm('$lib.auth.users.byname(visi).vars.foo=$lib.undef')
495
498
  self.none(await core.callStorm('return($lib.auth.users.byname(visi).vars.foo)'))
496
499
 
500
+ with self.raises(s_exc.StormRuntimeError):
501
+ await core.callStorm('$lib.user.vars.set((1), newp)')
502
+
503
+ await core.callStorm('$lib.user.profile.set(bar, foovalu)', opts=asvisi)
504
+
505
+ self.eq('foovalu', await core.callStorm('return($lib.user.profile.get(bar))', opts=asvisi))
506
+
507
+ self.eq((('bar', 'foovalu'),), await core.callStorm('return($lib.user.profile.list())', opts=asvisi))
508
+
509
+ msgs = await core.stormlist('for $valu in $lib.user.profile { $lib.print($valu) }', opts=asvisi)
510
+ self.stormIsInPrint("('bar', 'foovalu')", msgs)
511
+
512
+ await core.callStorm('$lib.user.profile.pop(bar)', opts=asvisi)
513
+ self.none(await core.callStorm('return($lib.user.profile.get(bar))', opts=asvisi))
514
+
515
+ with self.raises(s_exc.StormRuntimeError):
516
+ await core.callStorm('$lib.user.profile.set((1), newp)')
517
+
497
518
  async def test_stormlib_auth_base(self):
498
519
 
499
520
  async with self.getTestCore() as core:
@@ -489,10 +489,10 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
489
489
  await core.callStorm(q, opts={'vars': {'iden': iden3}})
490
490
 
491
491
  msgs = await core.stormlist('cortex.httpapi.list')
492
- self.stormIsInPrint(f'0 {iden0}', msgs)
493
- self.stormIsInPrint(f'1 {iden1}', msgs)
494
- self.stormIsInPrint(f'2 {iden2}', msgs)
495
- self.stormIsInPrint(f'3 {iden3}', msgs)
492
+ self.stormIsInPrint(f'0 | {iden0}', msgs)
493
+ self.stormIsInPrint(f'1 | {iden1}', msgs)
494
+ self.stormIsInPrint(f'2 | {iden2}', msgs)
495
+ self.stormIsInPrint(f'3 | {iden3}', msgs)
496
496
 
497
497
  q = '''
498
498
  $ret = $lib.null $api = $lib.cortex.httpapi.getByPath($path)
@@ -528,10 +528,10 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
528
528
  self.eq(iden0, await core.callStorm(q, opts={'vars': {'path': 'hehe/ohmy'}}))
529
529
 
530
530
  msgs = await core.stormlist('cortex.httpapi.list')
531
- self.stormIsInPrint(f'0 {iden1}', msgs)
532
- self.stormIsInPrint(f'1 {iden0}', msgs)
533
- self.stormIsInPrint(f'2 {iden2}', msgs)
534
- self.stormIsInPrint(f'3 {iden3}', msgs)
531
+ self.stormIsInPrint(f'0 | {iden1}', msgs)
532
+ self.stormIsInPrint(f'1 | {iden0}', msgs)
533
+ self.stormIsInPrint(f'2 | {iden2}', msgs)
534
+ self.stormIsInPrint(f'3 | {iden3}', msgs)
535
535
 
536
536
  # The wildcard handler does not match the more specific request as a result of the new order
537
537
  async with self.getHttpSess(auth=('root', 'root'), port=hport) as sess:
@@ -569,10 +569,10 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
569
569
  self.stormIsInPrint(f'Set HTTP API {iden0} to index 3', msgs)
570
570
 
571
571
  msgs = await core.stormlist('cortex.httpapi.list')
572
- self.stormIsInPrint(f'0 {iden1}', msgs)
573
- self.stormIsInPrint(f'1 {iden2}', msgs)
574
- self.stormIsInPrint(f'2 {iden3}', msgs)
575
- self.stormIsInPrint(f'3 {iden0}', msgs)
572
+ self.stormIsInPrint(f'0 | {iden1}', msgs)
573
+ self.stormIsInPrint(f'1 | {iden2}', msgs)
574
+ self.stormIsInPrint(f'2 | {iden3}', msgs)
575
+ self.stormIsInPrint(f'3 | {iden0}', msgs)
576
576
 
577
577
  # iden Prefix + name matching
578
578
  msgs = await core.stormlist('cortex.httpapi.index $iden 0', opts={'vars': {'iden': iden1[:6]}})
@@ -1,4 +1,5 @@
1
1
  import synapse.exc as s_exc
2
+ import synapse.common as s_common
2
3
 
3
4
  import synapse.tests.utils as s_test
4
5
 
@@ -245,3 +246,101 @@ class StormLibGenTest(s_test.SynTest):
245
246
  names = nodes[0].get('names')
246
247
  self.len(1, names)
247
248
  self.isin('rhodesia', names)
249
+
250
+ async def test_stormlib_gen_fileBytes(self):
251
+
252
+ async with self.getTestCore() as core:
253
+ sha256 = s_common.buid().hex()
254
+ opts = {'vars': {'sha256': sha256}}
255
+
256
+ nodes = await core.nodes('yield $lib.gen.fileBytesBySha256($sha256)', opts=opts)
257
+ self.len(1, nodes)
258
+ self.eq(nodes[0].get('sha256'), sha256)
259
+
260
+ sha256 = s_common.buid().hex()
261
+ opts = {'vars': {'sha256': sha256}}
262
+
263
+ q = '''
264
+ [ file:bytes=(file1,) :sha256=$sha256 ]
265
+ spin |
266
+ yield $lib.gen.fileBytesBySha256($sha256)
267
+ '''
268
+ nodes = await core.nodes(q, opts=opts)
269
+ self.len(1, nodes)
270
+ self.eq(nodes[0].repr(), 'guid:' + s_common.guid(('file1',)))
271
+
272
+ with self.raises(s_exc.BadTypeValu):
273
+ await core.callStorm('$lib.gen.fileBytesBySha256(newp)', opts=opts)
274
+
275
+ q = 'return($lib.gen.fileBytesBySha256(newp, try=$lib.true))'
276
+ self.none(await core.callStorm(q, opts=opts))
277
+
278
+ async def test_stormlib_gen_inetTlsServerCert(self):
279
+
280
+ async with self.getTestCore() as core:
281
+ sha256 = s_common.buid().hex()
282
+ opts = {'vars': {'sha256': sha256}}
283
+
284
+ q = '''
285
+ $server = {[ inet:server="1.2.3.4:443" ]}
286
+ yield $lib.gen.inetTlsServerCertByServerAndSha256($server, $sha256)
287
+ '''
288
+ nodes = await core.nodes(q, opts=opts)
289
+ self.len(1, nodes)
290
+ self.eq(nodes[0].get('server'), 'tcp://1.2.3.4:443')
291
+ cert = nodes[0].get('cert')
292
+ self.nn(cert)
293
+
294
+ nodes = await core.nodes('crypto:x509:cert:sha256=$sha256', opts=opts)
295
+ self.len(1, nodes)
296
+ self.eq(nodes[0].repr(), cert)
297
+
298
+ with self.raises(s_exc.BadTypeValu):
299
+ await core.callStorm('$lib.gen.inetTlsServerCertByServerAndSha256(newp, $sha256)', opts=opts)
300
+
301
+ q = 'return($lib.gen.inetTlsServerCertByServerAndSha256(newp, $sha256, try=$lib.true))'
302
+ self.none(await core.callStorm(q, opts=opts))
303
+
304
+ async def test_stormlib_gen_cryptoX509Cert(self):
305
+
306
+ async with self.getTestCore() as core:
307
+
308
+ # Check guid generation
309
+ sha256 = s_common.buid().hex()
310
+ opts = {'vars': {'sha256': sha256}}
311
+ nodes = await core.nodes('yield $lib.gen.cryptoX509CertBySha256($sha256)', opts=opts)
312
+ self.len(1, nodes)
313
+ self.eq(nodes[0].get('sha256'), sha256)
314
+ self.eq(nodes[0].repr(), s_common.guid(sha256))
315
+
316
+ # Check invalid values, no try
317
+ with self.raises(s_exc.BadTypeValu):
318
+ await core.callStorm('$lib.gen.cryptoX509CertBySha256(newp)')
319
+
320
+ # Check invalid values, with try
321
+ self.none(await core.callStorm('return($lib.gen.cryptoX509CertBySha256(newp, try=$lib.true))'))
322
+
323
+ # Check node matching with same sha256 values
324
+ sha256 = s_common.buid().hex()
325
+ opts = {'vars': {'sha256': sha256}}
326
+ nodes = await core.nodes('[crypto:x509:cert=* :sha256=$sha256]', opts=opts)
327
+ self.len(1, nodes)
328
+ self.eq(nodes[0].get('sha256'), sha256)
329
+ self.ne(nodes[0].repr(), s_common.guid(sha256))
330
+ crypto = nodes[0].repr()
331
+
332
+ nodes = await core.nodes('yield $lib.gen.cryptoX509CertBySha256($sha256)', opts=opts)
333
+ self.len(1, nodes)
334
+ self.eq(nodes[0].repr(), crypto)
335
+
336
+ # Check node matching, crypto:x509:cert -> file with matching sha256
337
+ sha256 = s_common.buid().hex()
338
+ opts = {'vars': {'sha256': sha256}}
339
+ nodes = await core.nodes('[crypto:x509:cert=* :file={[ file:bytes=$sha256 ]} ]', opts=opts)
340
+ self.len(1, nodes)
341
+ self.none(nodes[0].get('sha256'))
342
+ crypto = nodes[0].repr()
343
+
344
+ nodes = await core.nodes('yield $lib.gen.cryptoX509CertBySha256($sha256)', opts=opts)
345
+ self.len(1, nodes)
346
+ self.eq(nodes[0].repr(), crypto)
@@ -1,4 +1,6 @@
1
1
  import synapse.exc as s_exc
2
+ import synapse.common as s_common
3
+
2
4
  import synapse.lib.time as s_time
3
5
  import synapse.lib.layer as s_layer
4
6
 
@@ -827,3 +829,109 @@ class StormlibModelTest(s_test.SynTest):
827
829
  with self.raises(s_exc.BadArg) as ectx:
828
830
  await core.nodes('$lib.model.migration.s.riskHasVulnToVulnerable(newp)')
829
831
  self.isin('must be a node', ectx.exception.errinfo['mesg'])
832
+
833
+ async def test_stormlib_model_migration_s_inet_ssl_to_tls_servercert(self):
834
+ async with self.getRegrCore('inet_ssl_to_tls_servercert') as core:
835
+ nodes = await core.nodes('meta:source')
836
+ self.len(1, nodes)
837
+
838
+ nodes = await core.nodes('meta:source -(seen)> *')
839
+ self.len(3, nodes)
840
+ for node in nodes:
841
+ self.eq(node.ndef[0], 'inet:ssl:cert')
842
+
843
+ nodes = await core.nodes('inet:ssl:cert')
844
+ self.len(3, nodes)
845
+
846
+ nodes = await core.nodes('file:bytes')
847
+ self.len(3, nodes)
848
+
849
+ nodes = await core.nodes('crypto:x509:cert')
850
+ self.len(2, nodes)
851
+
852
+ nodes = await core.nodes('inet:tls:servercert')
853
+ self.len(0, nodes)
854
+
855
+ q = 'inet:ssl:cert | $lib.model.migration.s.inetSslCertToTlsServerCert($node)'
856
+ await core.nodes(q)
857
+
858
+ nodes = await core.nodes('file:bytes')
859
+ self.len(3, nodes)
860
+
861
+ nodes = await core.nodes('crypto:x509:cert')
862
+ self.len(3, nodes)
863
+
864
+ nodes = await core.nodes('inet:tls:servercert')
865
+ self.len(3, nodes)
866
+
867
+ nodes = await core.nodes('crypto:x509:cert=(cert1,)')
868
+ self.len(1, nodes)
869
+ cert1 = nodes[0]
870
+
871
+ nodes = await core.nodes('inet:tls:servercert:server="tcp://1.2.3.4:443"')
872
+ self.len(1, nodes)
873
+ self.eq(nodes[0].get('.seen'), (1688947200000, 1688947200001))
874
+ self.eq(nodes[0].get('server'), 'tcp://1.2.3.4:443')
875
+ self.eq(nodes[0].get('cert'), cert1.ndef[1])
876
+ self.isin('ssl.migration.one', nodes[0].tags)
877
+
878
+ nodes = await core.nodes('crypto:x509:cert=(cert2,)')
879
+ self.len(1, nodes)
880
+ cert2 = nodes[0]
881
+
882
+ nodes = await core.nodes('inet:tls:servercert:server="tcp://[fe80::1]:8080"')
883
+ self.len(1, nodes)
884
+ self.none(nodes[0].get('.seen'))
885
+ self.eq(nodes[0].get('server'), 'tcp://[fe80::1]:8080')
886
+ self.eq(nodes[0].get('cert'), cert2.ndef[1])
887
+ self.isin('ssl.migration.two', nodes[0].tags)
888
+
889
+ sha256 = 'aa0366ffb013ba2053e45cd7e4bcc8acd6a6c1bafc82eddb4e155876734c5e25'
890
+ opts = {'vars': {'sha256': sha256}}
891
+
892
+ nodes = await core.nodes('file:bytes=$sha256', opts=opts)
893
+ self.len(1, nodes)
894
+ file = nodes[0]
895
+
896
+ # This cert was created by the migration code so do a little extra
897
+ # checking
898
+ nodes = await core.nodes('crypto:x509:cert:file=$sha256', opts=opts)
899
+ self.len(1, nodes)
900
+ self.eq(nodes[0].get('file'), file.ndef[1])
901
+ self.eq(nodes[0].ndef, ('crypto:x509:cert', s_common.guid(sha256)))
902
+ cert3 = nodes[0]
903
+
904
+ nodes = await core.nodes('inet:tls:servercert:server="tcp://8.8.8.8:53" $node.data.load(foo)')
905
+ self.len(1, nodes)
906
+ self.none(nodes[0].get('.seen'))
907
+ self.eq(nodes[0].get('server'), 'tcp://8.8.8.8:53')
908
+ self.eq(nodes[0].get('cert'), cert3.ndef[1])
909
+ self.isin('ssl.migration.three', nodes[0].tags)
910
+ self.eq(nodes[0].nodedata, {'foo': 'bar'})
911
+
912
+ # Check that edges were migrated
913
+ nodes = await core.nodes('meta:source -(seen)> *')
914
+ self.len(6, nodes)
915
+ self.sorteq(
916
+ [k.ndef[0] for k in nodes],
917
+ (
918
+ 'inet:ssl:cert', 'inet:ssl:cert', 'inet:ssl:cert',
919
+ 'inet:tls:servercert', 'inet:tls:servercert', 'inet:tls:servercert',
920
+ )
921
+ )
922
+
923
+ with self.raises(s_exc.BadArg) as exc:
924
+ await core.callStorm('inet:server | $lib.model.migration.s.inetSslCertToTlsServerCert($node)')
925
+ self.isin(', not inet:server', exc.exception.get('mesg'))
926
+
927
+ async with self.getRegrCore('inet_ssl_to_tls_servercert') as core:
928
+ q = 'inet:ssl:cert | $lib.model.migration.s.inetSslCertToTlsServerCert($node, nodata=$lib.true)'
929
+ await core.nodes(q)
930
+
931
+ nodes = await core.nodes('inet:tls:servercert:server="tcp://8.8.8.8:53" $node.data.load(foo)')
932
+ self.len(1, nodes)
933
+ self.none(nodes[0].get('.seen'))
934
+ self.eq(nodes[0].get('server'), 'tcp://8.8.8.8:53')
935
+ self.eq(nodes[0].get('cert'), cert3.ndef[1])
936
+ self.isin('ssl.migration.three', nodes[0].tags)
937
+ self.eq(nodes[0].nodedata, {'foo': None})
@@ -22,6 +22,9 @@ class StormtypesModelextTest(s_test.SynTest):
22
22
 
23
23
  $pinfo = ({"doc": "Extended a core model."})
24
24
  $lib.model.ext.addFormProp(test:int, _tick, (time, ({})), $propinfo)
25
+
26
+ $edgeinfo = ({"doc": "A test edge."})
27
+ $lib.model.ext.addEdge(inet:user, _copies, *, $edgeinfo)
25
28
  ''')
26
29
 
27
30
  nodes = await core.nodes('[ _visi:int=10 :tick=20210101 ._woot=30 +#lol:score=99 ]')
@@ -44,6 +47,12 @@ class StormtypesModelextTest(s_test.SynTest):
44
47
  q = '''$lib.model.ext.addUnivProp(_woot, (time, ({})), ({}))'''
45
48
  await core.callStorm(q)
46
49
 
50
+ with self.raises(s_exc.DupEdgeType):
51
+ q = '''$lib.model.ext.addEdge(inet:user, _copies, *, ({}))'''
52
+ await core.callStorm(q)
53
+
54
+ self.nn(core.model.edge(('inet:user', '_copies', None)))
55
+
47
56
  # Grab the extended model definitions
48
57
  model_defs = await core.callStorm('return ( $lib.model.ext.getExtModel() )')
49
58
  self.isinstance(model_defs, dict)
@@ -55,6 +64,7 @@ class StormtypesModelextTest(s_test.SynTest):
55
64
  $lib.model.ext.delFormProp(_visi:int, tick)
56
65
  $lib.model.ext.delFormProp(test:int, _tick)
57
66
  $lib.model.ext.delForm(_visi:int)
67
+ $lib.model.ext.delEdge(inet:user, _copies, *)
58
68
  ''')
59
69
 
60
70
  self.none(core.model.form('_visi:int'))
@@ -62,6 +72,7 @@ class StormtypesModelextTest(s_test.SynTest):
62
72
  self.none(core.model.prop('_visi:int:tick'))
63
73
  self.none(core.model.prop('test:int:_tick'))
64
74
  self.none(core.model.tagprop('score'))
75
+ self.none(core.model.edge(('inet:user', '_copies', None)))
65
76
 
66
77
  # Underscores can exist in extended names but only at specific locations
67
78
  q = '''$l =$lib.list('str', ({})) $d=({"doc": "Foo"})
@@ -105,6 +116,26 @@ class StormtypesModelextTest(s_test.SynTest):
105
116
  q = '''$lib.model.ext.addTagProp(_someones:_score^value, (int, ({})), ({}))'''
106
117
  await core.callStorm(q)
107
118
 
119
+ with self.raises(s_exc.BadEdgeDef):
120
+ q = '''$lib.model.ext.addEdge(*, does, *, ({}))'''
121
+ await core.callStorm(q)
122
+
123
+ with self.raises(s_exc.BadEdgeDef):
124
+ q = '''$lib.model.ext.addEdge(*, _NEWP, *, ({}))'''
125
+ await core.callStorm(q)
126
+
127
+ with self.raises(s_exc.BadEdgeDef):
128
+ q = '''$lib.model.ext.addEdge(*, "_ne wp", *, ({}))'''
129
+ await core.callStorm(q)
130
+
131
+ with self.raises(s_exc.BadEdgeDef):
132
+ q = f'''$lib.model.ext.addEdge(*, "_{'a'*201}", *, ({{}}))'''
133
+ await core.callStorm(q)
134
+
135
+ with self.raises(s_exc.BadEdgeDef):
136
+ q = '''$lib.model.ext.delEdge(*, "_ne wp", *)'''
137
+ await core.callStorm(q)
138
+
108
139
  # Permission errors
109
140
  visi = await core.auth.addUser('visi')
110
141
  opts = {'user': visi.iden}
@@ -133,6 +164,10 @@ class StormtypesModelextTest(s_test.SynTest):
133
164
  $lib.model.ext.addTagProp(score, (int, ({})), $tagpropinfo)
134
165
  ''', opts=opts)
135
166
 
167
+ with self.raises(s_exc.AuthDeny):
168
+ q = '''$lib.model.ext.addEdge(*, _does, *, ({}))'''
169
+ await core.callStorm(q, opts=opts)
170
+
136
171
  # Reload the model extensions automatically
137
172
  async with self.getTestCore() as core:
138
173
  opts = {'vars': {'model_defs': model_defs}}
@@ -174,6 +209,9 @@ class StormtypesModelextTest(s_test.SynTest):
174
209
 
175
210
  $pinfo = ({"doc": "NEWP"})
176
211
  $lib.model.ext.addFormProp(test:int, _tick, (time, ({})), $propinfo)
212
+
213
+ $edgeinfo = ({"doc": "NEWP"})
214
+ $lib.model.ext.addEdge(inet:user, _copies, *, $edgeinfo)
177
215
  ''')
178
216
 
179
217
  q = '''return ($lib.model.ext.addExtModel($model_defs))'''
@@ -196,6 +234,11 @@ class StormtypesModelextTest(s_test.SynTest):
196
234
  opts = {'vars': {'model_defs': {'univs': model_defs['univs']}}}
197
235
  await core.callStorm(q, opts)
198
236
 
237
+ q = '''return ($lib.model.ext.addExtModel($model_defs))'''
238
+ with self.raises(s_exc.BadEdgeDef) as cm:
239
+ opts = {'vars': {'model_defs': {'edges': model_defs['edges']}}}
240
+ await core.callStorm(q, opts)
241
+
199
242
  # Reload the model extensions from the dump by hand
200
243
  async with self.getTestCore() as core:
201
244
  opts = {'vars': {'model_defs': model_defs}}
@@ -212,6 +255,10 @@ class StormtypesModelextTest(s_test.SynTest):
212
255
  for ($prop, $def, $info) in $model_defs.univs {
213
256
  $lib.model.ext.addUnivProp($prop, $def, $info)
214
257
  }
258
+ for ($edge, $info) in $model_defs.edges {
259
+ ($n1form, $verb, $n2form) = $edge
260
+ $lib.model.ext.addEdge($n1form, $verb, $n2form, $info)
261
+ }
215
262
  '''
216
263
  await core.nodes(q, opts)
217
264
 
@@ -227,6 +274,8 @@ class StormtypesModelextTest(s_test.SynTest):
227
274
  self.eq(nodes[0].ndef, ('test:int', 1234))
228
275
  self.eq(nodes[0].get('_tick'), 1609459200000)
229
276
 
277
+ self.nn(core.model.edge(('inet:user', '_copies', None)))
278
+
230
279
  async def test_lib_stormlib_behold_modelext(self):
231
280
  self.skipIfNexusReplay()
232
281
  async with self.getTestCore() as core:
@@ -252,6 +301,7 @@ class StormtypesModelextTest(s_test.SynTest):
252
301
  $lib.model.ext.addFormProp(_behold:score, rank, (int, ({})), ({"doc": "second string"}))
253
302
  $lib.model.ext.addUnivProp(_beep, (int, ({})), ({"doc": "third string"}))
254
303
  $lib.model.ext.addTagProp(thingy, (int, ({})), ({"doc": "fourth string"}))
304
+ $lib.model.ext.addEdge(*, _goes, geo:place, ({"doc": "fifth string"}))
255
305
  ''')
256
306
 
257
307
  formmesg = await sock.receive_json()
@@ -279,11 +329,17 @@ class StormtypesModelextTest(s_test.SynTest):
279
329
  self.eq(tagpmesg['data']['info']['name'], 'thingy')
280
330
  self.eq(tagpmesg['data']['info']['info'], {'doc': 'fourth string'})
281
331
 
332
+ edgemesg = await sock.receive_json()
333
+ self.eq(edgemesg['data']['event'], 'model:edge:add')
334
+ self.eq(edgemesg['data']['info']['edge'], (None, '_goes', 'geo:place'))
335
+ self.eq(edgemesg['data']['info']['info'], {'doc': 'fifth string'})
336
+
282
337
  await core.callStorm('''
283
338
  $lib.model.ext.delTagProp(thingy)
284
339
  $lib.model.ext.delUnivProp(_beep)
285
340
  $lib.model.ext.delFormProp(_behold:score, rank)
286
341
  $lib.model.ext.delForm(_behold:score)
342
+ $lib.model.ext.delEdge(*, _goes, geo:place)
287
343
  ''')
288
344
  deltagp = await sock.receive_json()
289
345
  self.eq(deltagp['data']['event'], 'model:tagprop:del')
@@ -302,6 +358,10 @@ class StormtypesModelextTest(s_test.SynTest):
302
358
  self.eq(delform['data']['event'], 'model:form:del')
303
359
  self.eq(delform['data']['info']['form'], '_behold:score')
304
360
 
361
+ deledge = await sock.receive_json()
362
+ self.eq(deledge['data']['event'], 'model:edge:del')
363
+ self.eq(deledge['data']['info']['edge'], (None, '_goes', 'geo:place'))
364
+
305
365
  async def test_lib_stormlib_modelext_delform(self):
306
366
  '''
307
367
  Verify extended forms can't be deleted if they have associated extended props
@@ -385,6 +445,10 @@ class StormtypesModelextTest(s_test.SynTest):
385
445
  '$lib.model.ext.addTagProp(_foo:bar, (), ())',
386
446
  'Tag property definitions should be a dict.'
387
447
  ),
448
+ (
449
+ '$lib.model.ext.addEdge(*, _foo, *, ())',
450
+ 'Edge info should be a dict.'
451
+ ),
388
452
  )
389
453
 
390
454
  async with self.getTestCore() as core:
@@ -5,7 +5,7 @@ import synapse.tests.utils as s_test
5
5
 
6
6
  class LibStormTest(s_test.SynTest):
7
7
 
8
- async def test_lib_stormlib_storm(self):
8
+ async def test_lib_stormlib_storm_eval(self):
9
9
  async with self.getTestCore() as core:
10
10
 
11
11
  opts = {'vars': {'text': '(10)'}}
@@ -61,3 +61,84 @@ class LibStormTest(s_test.SynTest):
61
61
 
62
62
  mesg = f'Executing storm query via $lib.storm.eval() {{{q}}} as [root]'
63
63
  self.isin(mesg, data)
64
+
65
+ async def test_lib_stormlib_storm(self):
66
+
67
+ async with self.getTestCore() as core:
68
+
69
+ q = '''
70
+ $query = '[ inet:fqdn=foo.com inet:fqdn=bar.com ]'
71
+ storm.exec $query
72
+ '''
73
+ self.len(2, await core.nodes(q))
74
+
75
+ q = '''[
76
+ (inet:ipv4=1.2.3.4 :asn=4)
77
+ (inet:ipv4=1.2.3.5 :asn=5)
78
+ (inet:ipv4=1.2.3.6 :asn=10)
79
+ ]'''
80
+ await core.nodes(q)
81
+
82
+ q = '''
83
+ $filter = '-:asn=10'
84
+ inet:ipv4:asn
85
+ storm.exec $filter
86
+ '''
87
+ nodes = await core.nodes(q)
88
+ self.len(2, nodes)
89
+ for node in nodes:
90
+ self.ne(node.get('asn'), 10)
91
+
92
+ q = '''
93
+ $pivot = ${ -> inet:asn }
94
+ inet:ipv4:asn
95
+ storm.exec $pivot
96
+ '''
97
+ nodes = await core.nodes(q)
98
+ self.len(3, nodes)
99
+ for node in nodes:
100
+ self.eq(node.form.name, 'inet:asn')
101
+
102
+ # Exec a non-runtsafe query
103
+ q = '''
104
+ inet:ipv4:asn
105
+ $filter = `+:asn={$node.repr().split('.').'-1'}`
106
+ storm.exec $filter
107
+ '''
108
+ nodes = await core.nodes(q)
109
+ self.len(2, nodes)
110
+ for node in nodes:
111
+ self.ne(node.get('asn'), 10)
112
+
113
+ iden = await core.callStorm('return($lib.view.get().fork().iden)')
114
+ msgs = await core.stormlist('''
115
+ $query = "[inet:fqdn=vertex.link +#haha] $lib.print(woot)"
116
+ $opts = ({"view": $view})
117
+ for $mesg in $lib.storm.run($query, opts=$opts) {
118
+ if ($mesg.0 = "print") { $lib.print($mesg.1.mesg) }
119
+ }
120
+ ''', opts={'vars': {'view': iden}})
121
+ self.stormIsInPrint('woot', msgs)
122
+ self.len(1, await core.nodes('inet:fqdn#haha', opts={'view': iden}))
123
+
124
+ visi = await core.auth.addUser('visi')
125
+ msgs = await core.stormlist('''
126
+ $opts=({"user": $lib.auth.users.byname(root).iden})
127
+ for $mesg in $lib.storm.run("$lib.print(lolz)", opts=$opts) {
128
+ if ($mesg.0 = "err") { $lib.print($mesg) }
129
+ if ($mesg.0 = "print") { $lib.print($mesg) }
130
+ }
131
+ ''', opts={'user': visi.iden})
132
+ self.stormIsInErr('must have permission impersonate', msgs)
133
+ self.stormNotInPrint('lolz', msgs)
134
+
135
+ # no opts provided
136
+ msgs = await core.stormlist('''
137
+ $q = ${ $lib.print('hello') }
138
+ for $mesg in $lib.storm.run($q) {
139
+ if ( $mesg.0 = 'print' ) {
140
+ $lib.print(`mesg={$mesg.1.mesg}`)
141
+ }
142
+ }
143
+ ''')
144
+ self.stormIsInPrint('mesg=hello', msgs)