synapse 2.155.0__py311-none-any.whl → 2.156.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 (64) hide show
  1. synapse/cmds/cortex.py +2 -14
  2. synapse/common.py +1 -28
  3. synapse/cortex.py +10 -510
  4. synapse/lib/ast.py +60 -1
  5. synapse/lib/cell.py +33 -8
  6. synapse/lib/certdir.py +11 -0
  7. synapse/lib/cmdr.py +0 -5
  8. synapse/lib/gis.py +2 -2
  9. synapse/lib/httpapi.py +1 -43
  10. synapse/lib/layer.py +64 -201
  11. synapse/lib/lmdbslab.py +11 -0
  12. synapse/lib/node.py +1 -3
  13. synapse/lib/parser.py +10 -0
  14. synapse/lib/snap.py +121 -21
  15. synapse/lib/storm.lark +23 -6
  16. synapse/lib/storm.py +15 -338
  17. synapse/lib/storm_format.py +5 -0
  18. synapse/lib/stormlib/gen.py +1 -2
  19. synapse/lib/stormlib/gis.py +41 -0
  20. synapse/lib/stormlib/stats.py +21 -2
  21. synapse/lib/stormlib/storm.py +16 -1
  22. synapse/lib/stormtypes.py +225 -12
  23. synapse/lib/version.py +2 -2
  24. synapse/lib/view.py +96 -21
  25. synapse/models/inet.py +60 -30
  26. synapse/models/infotech.py +56 -1
  27. synapse/models/orgs.py +3 -0
  28. synapse/models/risk.py +15 -0
  29. synapse/models/syn.py +0 -38
  30. synapse/tests/test_cmds_cortex.py +1 -1
  31. synapse/tests/test_cortex.py +32 -336
  32. synapse/tests/test_lib_agenda.py +19 -54
  33. synapse/tests/test_lib_aha.py +97 -0
  34. synapse/tests/test_lib_ast.py +402 -0
  35. synapse/tests/test_lib_grammar.py +30 -10
  36. synapse/tests/test_lib_httpapi.py +0 -46
  37. synapse/tests/test_lib_layer.py +19 -234
  38. synapse/tests/test_lib_lmdbslab.py +22 -0
  39. synapse/tests/test_lib_snap.py +9 -0
  40. synapse/tests/test_lib_storm.py +16 -309
  41. synapse/tests/test_lib_stormlib_gis.py +21 -0
  42. synapse/tests/test_lib_stormlib_stats.py +107 -20
  43. synapse/tests/test_lib_stormlib_storm.py +25 -0
  44. synapse/tests/test_lib_stormtypes.py +231 -8
  45. synapse/tests/test_lib_view.py +6 -13
  46. synapse/tests/test_model_base.py +1 -1
  47. synapse/tests/test_model_inet.py +15 -0
  48. synapse/tests/test_model_infotech.py +60 -0
  49. synapse/tests/test_model_orgs.py +10 -0
  50. synapse/tests/test_model_person.py +0 -3
  51. synapse/tests/test_model_risk.py +20 -0
  52. synapse/tests/test_model_syn.py +20 -34
  53. synapse/tests/test_tools_csvtool.py +2 -1
  54. synapse/tests/test_tools_feed.py +4 -30
  55. synapse/tools/csvtool.py +2 -1
  56. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/METADATA +3 -3
  57. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/RECORD +60 -62
  58. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/WHEEL +1 -1
  59. synapse/cmds/cron.py +0 -726
  60. synapse/cmds/trigger.py +0 -319
  61. synapse/tests/test_cmds_cron.py +0 -453
  62. synapse/tests/test_cmds_trigger.py +0 -176
  63. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/LICENSE +0 -0
  64. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/top_level.txt +0 -0
@@ -4064,6 +4064,15 @@ class StormTypesTest(s_test.SynTest):
4064
4064
  self.nn(iden)
4065
4065
  self.true(visi.allowed(('view', 'read'), gateiden=iden))
4066
4066
 
4067
+ await visi.addRule((True, ('view', 'add')))
4068
+
4069
+ msgs = await core.stormlist('$lib.view.get().fork()', opts={'user': visi.iden})
4070
+ self.stormHasNoWarnErr(msgs)
4071
+
4072
+ await visi.addRule((False, ('view', 'fork')), gateiden=core.view.iden)
4073
+ msgs = await core.stormlist('$lib.view.get().fork()', opts={'user': visi.iden})
4074
+ self.stormIsInErr('must have permission view.fork', msgs)
4075
+
4067
4076
  async def test_storm_view_deporder(self):
4068
4077
 
4069
4078
  async with self.getTestCore() as core:
@@ -4470,6 +4479,7 @@ class StormTypesTest(s_test.SynTest):
4470
4479
 
4471
4480
  async def test_storm_lib_cron_notime(self):
4472
4481
  # test cron APIs that don't require time stepping
4482
+
4473
4483
  async with self.getTestCore() as core:
4474
4484
 
4475
4485
  cdef = await core.callStorm('return($lib.cron.add(query="{[graph:node=*]}", hourly=30).pack())')
@@ -4499,13 +4509,11 @@ class StormTypesTest(s_test.SynTest):
4499
4509
  self.eq('mydoc', cdef.get('doc'))
4500
4510
  self.eq('myname', cdef.get('name'))
4501
4511
 
4502
- async with core.getLocalProxy() as proxy:
4512
+ cdef = await core.callStorm('$cron=$lib.cron.get($iden) return ( $cron.set(name, lolz) )', opts=opts)
4513
+ self.eq('lolz', cdef.get('name'))
4503
4514
 
4504
- cdef = await proxy.editCronJob(iden0, 'name', 'lolz')
4505
- self.eq('lolz', cdef.get('name'))
4506
-
4507
- cdef = await proxy.editCronJob(iden0, 'doc', 'zoinks')
4508
- self.eq('zoinks', cdef.get('doc'))
4515
+ cdef = await core.callStorm('$cron=$lib.cron.get($iden) return ( $cron.set(doc, zoinks) )', opts=opts)
4516
+ self.eq('zoinks', cdef.get('doc'))
4509
4517
 
4510
4518
  async def test_storm_lib_cron(self):
4511
4519
 
@@ -4592,8 +4600,6 @@ class StormTypesTest(s_test.SynTest):
4592
4600
  self.stormIsInErr("Unexpected token '}' at line 1, column 10", mesgs)
4593
4601
 
4594
4602
  ##################
4595
- oldsplicespos = (await alist(prox.splices(None, 1000)))[-1][0][0]
4596
- nextoffs = (oldsplicespos + 1, 0, 0)
4597
4603
  layr = core.getLayer()
4598
4604
  nextlayroffs = await layr.getEditOffs() + 1
4599
4605
 
@@ -5919,6 +5925,7 @@ class StormTypesTest(s_test.SynTest):
5919
5925
 
5920
5926
  async def test_stormtypes_layer_counts(self):
5921
5927
  async with self.getTestCore() as core:
5928
+
5922
5929
  self.eq(0, await core.callStorm('return($lib.layer.get().getTagCount(foo.bar))'))
5923
5930
  await core.nodes('[ inet:ipv4=1.2.3.4 inet:ipv4=5.6.7.8 :asn=20 inet:asn=20 +#foo.bar ]')
5924
5931
  self.eq(0, await core.callStorm('return($lib.layer.get().getPropCount(ps:person))'))
@@ -5937,6 +5944,111 @@ class StormTypesTest(s_test.SynTest):
5937
5944
  with self.raises(s_exc.NoSuchProp):
5938
5945
  await core.callStorm("return($lib.layer.get().getPropCount('.newp'))")
5939
5946
 
5947
+ await core.nodes('.created | delnode --force')
5948
+
5949
+ await core.addTagProp('score', ('int', {}), {})
5950
+
5951
+ q = '''[
5952
+ inet:ipv4=1
5953
+ inet:ipv4=2
5954
+ inet:ipv4=3
5955
+ :asn=4
5956
+
5957
+ (ou:org=*
5958
+ ou:org=*
5959
+ :names=(foo, bar))
5960
+
5961
+ .seen=2020
5962
+ .univarray=(1, 2)
5963
+ +#foo:score=2
5964
+
5965
+ test:arrayform=(1,2,3)
5966
+ test:arrayform=(2,3,4)
5967
+ ]'''
5968
+ await core.nodes(q)
5969
+
5970
+ q = 'return($lib.layer.get().getPropCount(inet:ipv4:asn, valu=1))'
5971
+ self.eq(0, await core.callStorm(q))
5972
+
5973
+ q = 'return($lib.layer.get().getPropCount(inet:ipv4:loc, valu=1))'
5974
+ self.eq(0, await core.callStorm(q))
5975
+
5976
+ q = 'return($lib.layer.get().getPropCount(inet:ipv4:asn, valu=4))'
5977
+ self.eq(3, await core.callStorm(q))
5978
+
5979
+ q = 'return($lib.layer.get().getPropCount(inet:ipv4.seen, valu=2020))'
5980
+ self.eq(3, await core.callStorm(q))
5981
+
5982
+ q = 'return($lib.layer.get().getPropCount(".seen", valu=2020))'
5983
+ self.eq(5, await core.callStorm(q))
5984
+
5985
+ q = 'return($lib.layer.get().getPropCount(".test:univ", valu=1))'
5986
+ self.eq(0, await core.callStorm(q))
5987
+
5988
+ q = 'return($lib.layer.get().getPropCount(inet:ipv4, valu=1))'
5989
+ self.eq(1, await core.callStorm(q))
5990
+
5991
+ q = 'return($lib.layer.get().getPropCount(ou:org:names, valu=(foo, bar)))'
5992
+ self.eq(2, await core.callStorm(q))
5993
+
5994
+ q = 'return($lib.layer.get().getPropCount(".univarray", valu=(1, 2)))'
5995
+ self.eq(5, await core.callStorm(q))
5996
+
5997
+ with self.raises(s_exc.NoSuchProp):
5998
+ q = 'return($lib.layer.get().getPropCount(newp, valu=1))'
5999
+ await core.callStorm(q)
6000
+
6001
+ q = 'return($lib.layer.get().getPropArrayCount(ou:org:names))'
6002
+ self.eq(4, await core.callStorm(q))
6003
+
6004
+ q = 'return($lib.layer.get().getPropArrayCount(ou:org:names, valu=foo))'
6005
+ self.eq(2, await core.callStorm(q))
6006
+
6007
+ q = 'return($lib.layer.get().getPropArrayCount(".univarray"))'
6008
+ self.eq(10, await core.callStorm(q))
6009
+
6010
+ q = 'return($lib.layer.get().getPropArrayCount(".univarray", valu=2))'
6011
+ self.eq(5, await core.callStorm(q))
6012
+
6013
+ q = 'return($lib.layer.get().getPropArrayCount(test:arrayform))'
6014
+ self.eq(6, await core.callStorm(q))
6015
+
6016
+ q = 'return($lib.layer.get().getPropArrayCount(test:arrayform, valu=2))'
6017
+ self.eq(2, await core.callStorm(q))
6018
+
6019
+ q = 'return($lib.layer.get().getPropArrayCount(ou:org:subs))'
6020
+ self.eq(0, await core.callStorm(q))
6021
+
6022
+ q = 'return($lib.layer.get().getPropArrayCount(ou:org:subs, valu=*))'
6023
+ self.eq(0, await core.callStorm(q))
6024
+
6025
+ with self.raises(s_exc.NoSuchProp):
6026
+ q = 'return($lib.layer.get().getPropArrayCount(newp, valu=1))'
6027
+ await core.callStorm(q)
6028
+
6029
+ with self.raises(s_exc.BadTypeValu):
6030
+ q = 'return($lib.layer.get().getPropArrayCount(inet:ipv4, valu=1))'
6031
+ await core.callStorm(q)
6032
+
6033
+ q = 'return($lib.layer.get().getTagPropCount(foo, score))'
6034
+ self.eq(5, await core.callStorm(q))
6035
+
6036
+ q = 'return($lib.layer.get().getTagPropCount(foo, score, valu=2))'
6037
+ self.eq(5, await core.callStorm(q))
6038
+
6039
+ q = 'return($lib.layer.get().getTagPropCount(foo, score, form=ou:org, valu=2))'
6040
+ self.eq(2, await core.callStorm(q))
6041
+
6042
+ q = 'return($lib.layer.get().getTagPropCount(bar, score))'
6043
+ self.eq(0, await core.callStorm(q))
6044
+
6045
+ q = 'return($lib.layer.get().getTagPropCount(bar, score, valu=2))'
6046
+ self.eq(0, await core.callStorm(q))
6047
+
6048
+ with self.raises(s_exc.NoSuchTagProp):
6049
+ q = 'return($lib.layer.get().getTagPropCount(foo, newp, valu=2))'
6050
+ await core.callStorm(q)
6051
+
5940
6052
  async def test_lib_stormtypes_cmdopts(self):
5941
6053
  pdef = {
5942
6054
  'name': 'foo',
@@ -6764,3 +6876,114 @@ words\tword\twrd'''
6764
6876
  '''
6765
6877
  msgs = await core.stormlist(q, opts={'readonly': True, 'vars': {'iden': user}})
6766
6878
  self.stormIsInErr(mesg, msgs)
6879
+
6880
+ async def test_storm_view_counts(self):
6881
+
6882
+ async with self.getTestCore() as core:
6883
+
6884
+ await core.addTagProp('score', ('int', {}), {})
6885
+
6886
+ view2 = await core.view.fork()
6887
+ forkopts = {'view': view2['iden']}
6888
+
6889
+ q = '''[
6890
+ inet:ipv4=1
6891
+ inet:ipv4=2
6892
+ inet:ipv4=3
6893
+ :asn=4
6894
+
6895
+ (ou:org=*
6896
+ ou:org=*
6897
+ :names=(foo, bar))
6898
+
6899
+ .seen=2020
6900
+ .univarray=(1, 2)
6901
+ +#foo:score=2
6902
+
6903
+ test:arrayform=(1,2,3)
6904
+ test:arrayform=(2,3,4)
6905
+ ]'''
6906
+ await core.nodes(q)
6907
+
6908
+ q = '''[
6909
+ inet:ipv4=4
6910
+ inet:ipv4=5
6911
+ inet:ipv4=6
6912
+ :asn=4
6913
+
6914
+ (ou:org=*
6915
+ ou:org=*
6916
+ :names=(foo, bar))
6917
+
6918
+ .seen=2020
6919
+ .univarray=(1, 2)
6920
+ +#foo:score=2
6921
+
6922
+ test:arrayform=(3,4,5)
6923
+ test:arrayform=(4,5,6)
6924
+ ]'''
6925
+ await core.nodes(q, opts=forkopts)
6926
+
6927
+ q = 'return($lib.view.get().getPropCount(inet:ipv4:asn))'
6928
+ self.eq(6, await core.callStorm(q, opts=forkopts))
6929
+
6930
+ q = 'return($lib.view.get().getPropCount(inet:ipv4:asn, valu=1))'
6931
+ self.eq(0, await core.callStorm(q, opts=forkopts))
6932
+
6933
+ q = 'return($lib.view.get().getPropCount(inet:ipv4:loc, valu=1))'
6934
+ self.eq(0, await core.callStorm(q, opts=forkopts))
6935
+
6936
+ q = 'return($lib.view.get().getPropCount(inet:ipv4:asn, valu=4))'
6937
+ self.eq(6, await core.callStorm(q, opts=forkopts))
6938
+
6939
+ q = 'return($lib.view.get().getPropCount(inet:ipv4.seen, valu=2020))'
6940
+ self.eq(6, await core.callStorm(q, opts=forkopts))
6941
+
6942
+ q = 'return($lib.view.get().getPropCount(".seen", valu=2020))'
6943
+ self.eq(10, await core.callStorm(q, opts=forkopts))
6944
+
6945
+ q = 'return($lib.view.get().getPropCount(inet:ipv4, valu=1))'
6946
+ self.eq(1, await core.callStorm(q, opts=forkopts))
6947
+
6948
+ q = 'return($lib.view.get().getPropCount(ou:org:names, valu=(foo, bar)))'
6949
+ self.eq(4, await core.callStorm(q, opts=forkopts))
6950
+
6951
+ q = 'return($lib.view.get().getPropCount(".univarray", valu=(1, 2)))'
6952
+ self.eq(10, await core.callStorm(q, opts=forkopts))
6953
+
6954
+ with self.raises(s_exc.NoSuchProp):
6955
+ q = 'return($lib.view.get().getPropCount(newp, valu=1))'
6956
+ await core.callStorm(q, opts=forkopts)
6957
+
6958
+ q = 'return($lib.view.get().getPropArrayCount(ou:org:names))'
6959
+ self.eq(8, await core.callStorm(q, opts=forkopts))
6960
+
6961
+ q = 'return($lib.view.get().getPropArrayCount(ou:org:names, valu=foo))'
6962
+ self.eq(4, await core.callStorm(q, opts=forkopts))
6963
+
6964
+ q = 'return($lib.view.get().getPropArrayCount(".univarray", valu=2))'
6965
+ self.eq(10, await core.callStorm(q, opts=forkopts))
6966
+
6967
+ q = 'return($lib.view.get().getPropArrayCount(test:arrayform, valu=3))'
6968
+ self.eq(3, await core.callStorm(q, opts=forkopts))
6969
+
6970
+ with self.raises(s_exc.NoSuchProp):
6971
+ q = 'return($lib.view.get().getPropArrayCount(newp, valu=1))'
6972
+ await core.callStorm(q, opts=forkopts)
6973
+
6974
+ with self.raises(s_exc.BadTypeValu):
6975
+ q = 'return($lib.view.get().getPropArrayCount(inet:ipv4, valu=1))'
6976
+ await core.callStorm(q, opts=forkopts)
6977
+
6978
+ q = 'return($lib.view.get().getTagPropCount(foo, score))'
6979
+ self.eq(10, await core.callStorm(q, opts=forkopts))
6980
+
6981
+ q = 'return($lib.view.get().getTagPropCount(foo, score, valu=2))'
6982
+ self.eq(10, await core.callStorm(q, opts=forkopts))
6983
+
6984
+ q = 'return($lib.view.get().getTagPropCount(foo, score, form=ou:org, valu=2))'
6985
+ self.eq(4, await core.callStorm(q, opts=forkopts))
6986
+
6987
+ with self.raises(s_exc.NoSuchTagProp):
6988
+ q = 'return($lib.view.get().getTagPropCount(foo, newp, valu=2))'
6989
+ await core.callStorm(q, opts=forkopts)
@@ -147,8 +147,8 @@ class ViewTest(s_t_utils.SynTest):
147
147
  # Add a node back
148
148
  await self.agenlen(1, view2.eval('[ test:int=12 ]'))
149
149
 
150
- # Add a bunch of nodes to require chunking of splices when merging
151
- for i in range(1000):
150
+ # Add a bunch of test nodes to the view.
151
+ for i in range(20):
152
152
  await self.agenlen(1, view2.eval('[test:int=$val]', opts={'vars': {'val': i + 1000}}))
153
153
 
154
154
  # Add prop that will only exist in the child
@@ -217,7 +217,7 @@ class ViewTest(s_t_utils.SynTest):
217
217
  await view2.wipeLayer()
218
218
 
219
219
  # The parent counts includes all the nodes that were merged
220
- self.eq(1005, (await core.view.getFormCounts()).get('test:int'))
220
+ self.eq(25, (await core.view.getFormCounts()).get('test:int'))
221
221
 
222
222
  # A node added to the child is now present in the parent
223
223
  nodes = await core.nodes('test:int=12')
@@ -247,13 +247,15 @@ class ViewTest(s_t_utils.SynTest):
247
247
  self.len(2, await core.nodes('test:int -(refs)> *'))
248
248
 
249
249
  # The child count includes all the nodes in the view
250
- self.eq(1005, (await view2.getFormCounts()).get('test:int'))
250
+ self.eq(25, (await view2.getFormCounts()).get('test:int'))
251
251
 
252
252
  # The child can see nodes that got merged
253
253
  nodes = await view2.nodes('test:int=12')
254
254
  self.len(1, nodes)
255
255
  nodes = await view2.nodes('test:int=1000')
256
256
  self.len(1, nodes)
257
+ nodes = await view2.nodes('test:int=1019')
258
+ self.len(1, nodes)
257
259
 
258
260
  await core.delView(view2.iden)
259
261
  await core.view.addLayer(layriden)
@@ -411,15 +413,6 @@ class ViewTest(s_t_utils.SynTest):
411
413
  self.eq(2, count['node:edits'])
412
414
  self.eq(0, count['node:add'])
413
415
 
414
- mesgs = await core.stormlist('[test:str=foo2 :hehe=bar]', opts={'editformat': 'splices'})
415
- count = collections.Counter(m[0] for m in mesgs)
416
- self.eq(1, count['init'])
417
- self.eq(1, count['node:add'])
418
- self.eq(2, count['prop:set']) # .created and .hehe
419
- self.eq(0, count['node:edits'])
420
- self.eq(1, count['node'])
421
- self.eq(1, count['fini'])
422
-
423
416
  mesgs = await core.stormlist('[test:str=foo3 :hehe=bar]', opts={'editformat': 'count'})
424
417
  count = collections.Counter(m[0] for m in mesgs)
425
418
  self.eq(1, count['init'])
@@ -243,7 +243,7 @@ class BaseTest(s_t_utils.SynTest):
243
243
  r2 = await snap.addNode('edge:refs', (cnode.ndef, ('test:int', 1234)))
244
244
 
245
245
  # Gather up all the nodes in the cluster
246
- nodes = await snap.eval(f'graph:cluster={guid} -+> edge:refs -+> * | uniq').list()
246
+ nodes = await core.nodes(f'graph:cluster={guid} -+> edge:refs -+> * | uniq')
247
247
  self.len(5, nodes)
248
248
 
249
249
  async def test_model_base_rules(self):
@@ -953,6 +953,12 @@ class InetModelTest(s_t_utils.SynTest):
953
953
  with self.raises(s_exc.BadTypeValu):
954
954
  await core.nodes('[inet:ipv4=foo-bar-duck.com]')
955
955
 
956
+ with self.raises(s_exc.BadTypeValu):
957
+ await core.nodes('[inet:ipv4=3.87/nice/index.php]')
958
+
959
+ with self.raises(s_exc.BadTypeValu):
960
+ await core.nodes('[inet:ipv4=3.87/33]')
961
+
956
962
  with self.raises(s_exc.BadTypeValu):
957
963
  await core.nodes('[test:str="foo"] [inet:ipv4=$node.value()]')
958
964
 
@@ -2778,3 +2784,12 @@ class InetModelTest(s_t_utils.SynTest):
2778
2784
  self.eq(nodes[0].get('client'), 'tcp://1.2.3.4')
2779
2785
  self.eq(nodes[0].get('client:ipv4'), 0x01020304)
2780
2786
  self.eq(nodes[0].get('client:ipv6'), '::1')
2787
+
2788
+ async def test_model_inet_onset_depth(self):
2789
+
2790
+ async with self.getTestCore() as core:
2791
+ fqdn = '.'.join(['x' for x in range(150)]) + '.foo.com'
2792
+ q = f'[ inet:fqdn="{fqdn}"]'
2793
+ nodes = await core.nodes(q)
2794
+ self.len(1, nodes)
2795
+ self.eq(nodes[0].get('zone'), 'foo.com')
@@ -164,6 +164,34 @@ class InfotechModelTest(s_t_utils.SynTest):
164
164
  self.eq(nodes[0].get('addresses'), ('T0100', 'T0200'))
165
165
  self.eq(nodes[0].get('matrix'), 'enterprise')
166
166
 
167
+ nodes = await core.nodes('''[
168
+ it:mitre:attack:campaign=C0001
169
+ :created = 20231101
170
+ :desc = "Much campaign, many sophisticated."
171
+ :groups = (G0100,)
172
+ :matrices = (enterprise,ics)
173
+ :name = "much campaign"
174
+ :names = ('much campaign', 'many sophisticated')
175
+ :software = (S0100,)
176
+ :techniques = (T0200,T0100)
177
+ :updated = 20231102
178
+ :url = https://attack.mitre.org/campaigns/C0001
179
+ :period = (20151201, 20160101)
180
+ ]''')
181
+ self.len(1, nodes)
182
+ self.eq(nodes[0].ndef, ('it:mitre:attack:campaign', 'C0001'))
183
+ self.eq(nodes[0].props.get('name'), 'much campaign')
184
+ self.eq(nodes[0].props.get('names'), ('many sophisticated', 'much campaign'))
185
+ self.eq(nodes[0].props.get('desc'), 'Much campaign, many sophisticated.')
186
+ self.eq(nodes[0].props.get('url'), 'https://attack.mitre.org/campaigns/C0001')
187
+ self.eq(nodes[0].props.get('matrices'), ('enterprise', 'ics'))
188
+ self.eq(nodes[0].props.get('groups'), ('G0100',))
189
+ self.eq(nodes[0].props.get('software'), ('S0100',))
190
+ self.eq(nodes[0].props.get('techniques'), ('T0100', 'T0200'))
191
+ self.eq(nodes[0].props.get('created'), 1698796800000)
192
+ self.eq(nodes[0].props.get('updated'), 1698883200000)
193
+ self.eq(nodes[0].props.get('period'), (1448928000000, 1451606400000))
194
+
167
195
  nodes = await core.nodes('''[
168
196
  it:exec:thread=*
169
197
  :proc=*
@@ -296,6 +324,8 @@ class InfotechModelTest(s_t_utils.SynTest):
296
324
  :target:host={[ it:host=* :name=visihost ]}
297
325
  :target:fqdn=vertex.link
298
326
  :target:url=https://vertex.link
327
+ :target:ipv4=1.2.3.4
328
+ :target:ipv6='::1'
299
329
  :multi:scan={[ it:av:scan:result=*
300
330
  :scanner:name="visi total"
301
331
  :multi:count=10
@@ -310,6 +340,8 @@ class InfotechModelTest(s_t_utils.SynTest):
310
340
  self.eq('visi scan', nodes[0].get('scanner:name'))
311
341
  self.eq('vertex.link', nodes[0].get('target:fqdn'))
312
342
  self.eq('https://vertex.link', nodes[0].get('target:url'))
343
+ self.eq(0x01020304, nodes[0].get('target:ipv4'))
344
+ self.eq('::1', nodes[0].get('target:ipv6'))
313
345
  self.eq('omgwtfbbq', nodes[0].get('signame'))
314
346
 
315
347
  self.len(1, await core.nodes('it:av:scan:result:scanner:name="visi scan" -> it:host'))
@@ -484,6 +516,34 @@ class InfotechModelTest(s_t_utils.SynTest):
484
516
  self.eq(7260000, nodes[1].get('duration'))
485
517
  self.eq('02:01:00.000', nodes[1].repr('duration'))
486
518
 
519
+ # Sample SIDs from here:
520
+ # https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/81d92bba-d22b-4a8c-908a-554ab29148ab
521
+ sids = [
522
+ 'S-1-0-0', 'S-1-1-0', 'S-1-2-0', 'S-1-2-1', 'S-1-3', 'S-1-3-0',
523
+ 'S-1-3-1', 'S-1-3-2', 'S-1-3-3', 'S-1-3-4', 'S-1-5', 'S-1-5-1',
524
+ 'S-1-5-2', 'S-1-5-3', 'S-1-5-4', 'S-1-5-6', 'S-1-5-7', 'S-1-5-8',
525
+ 'S-1-5-9', 'S-1-5-10', 'S-1-5-11', 'S-1-5-12', 'S-1-5-13', 'S-1-5-14',
526
+ 'S-1-5-15', 'S-1-5-17', 'S-1-5-18', 'S-1-5-19', 'S-1-5-20',
527
+ 'S-1-5-21-0-0-0-496', 'S-1-5-21-0-0-0-497', 'S-1-5-32-544',
528
+ 'S-1-5-32-545', 'S-1-5-32-546', 'S-1-5-32-547', 'S-1-5-32-548',
529
+ 'S-1-5-32-549', 'S-1-5-32-550', 'S-1-5-32-551', 'S-1-5-32-552',
530
+ 'S-1-5-32-554', 'S-1-5-32-555', 'S-1-5-32-556', 'S-1-5-32-557',
531
+ 'S-1-5-32-558', 'S-1-5-32-559', 'S-1-5-32-560', 'S-1-5-32-561',
532
+ 'S-1-5-32-562', 'S-1-5-32-568', 'S-1-5-32-569', 'S-1-5-32-573',
533
+ 'S-1-5-32-574', 'S-1-5-32-575', 'S-1-5-32-576', 'S-1-5-32-577',
534
+ 'S-1-5-32-578', 'S-1-5-32-579', 'S-1-5-32-580', 'S-1-5-32-582',
535
+ 'S-1-5-33', 'S-1-5-64-10', 'S-1-5-64-14', 'S-1-5-64-21', 'S-1-5-65-1',
536
+ 'S-1-5-80', 'S-1-5-80-0', 'S-1-5-83-0', 'S-1-5-84-0-0-0-0-0',
537
+ 'S-1-5-90-0', 'S-1-5-113', 'S-1-5-114', 'S-1-5-1000', 'S-1-15-2-1',
538
+ 'S-1-16-0', 'S-1-16-4096', 'S-1-16-8192', 'S-1-16-8448', 'S-1-16-12288',
539
+ 'S-1-16-16384', 'S-1-16-20480', 'S-1-16-28672', 'S-1-18-1', 'S-1-18-2',
540
+ 'S-1-18-3', 'S-1-18-4', 'S-1-18-5', 'S-1-18-6',
541
+ ]
542
+
543
+ opts = {'vars': {'sids': sids}}
544
+ nodes = await core.nodes('for $sid in $sids {[ it:account=* :windows:sid=$sid ]}', opts=opts)
545
+ self.len(88, nodes)
546
+
487
547
  nodes = await core.nodes('inet:email=visi@vertex.link -> ps:contact -> it:account -> it:logon +:time>=2021 -> it:host')
488
548
  self.len(1, nodes)
489
549
  self.eq('it:host', nodes[0].ndef[0])
@@ -68,6 +68,10 @@ class OuModelTest(s_t_utils.SynTest):
68
68
 
69
69
  timeline = s_common.guid()
70
70
 
71
+ nodes = await core.nodes('[ it:mitre:attack:campaign=C0011 ]')
72
+ self.len(1, nodes)
73
+ attack = nodes[0].ndef
74
+
71
75
  props = {
72
76
  'org': org0,
73
77
  'goal': goal,
@@ -85,6 +89,7 @@ class OuModelTest(s_t_utils.SynTest):
85
89
  'reporter': '*',
86
90
  'reporter:name': 'vertex',
87
91
  'timeline': timeline,
92
+ 'mitre:attack:campaign': 'C0011',
88
93
  }
89
94
  node = await snap.addNode('ou:campaign', camp, props=props)
90
95
  self.eq(node.get('tag'), 'cno.camp.31337')
@@ -101,10 +106,15 @@ class OuModelTest(s_t_utils.SynTest):
101
106
  self.eq(node.get('camptype'), 'get.pizza.')
102
107
  self.eq(node.get('techniques'), tuple(sorted(teqs)))
103
108
  self.eq(node.get('timeline'), timeline)
109
+ self.eq(node.get('mitre:attack:campaign'), 'C0011')
104
110
 
105
111
  self.nn(node.get('reporter'))
106
112
  self.eq(node.get('reporter:name'), 'vertex')
107
113
 
114
+ nodes = await core.nodes(f'ou:campaign={camp} -> it:mitre:attack:campaign')
115
+ self.len(1, nodes)
116
+ self.eq(nodes[0].ndef, attack)
117
+
108
118
  # type norming first
109
119
  # ou:name
110
120
  t = core.model.type('ou:name')
@@ -67,8 +67,6 @@ class PsModelTest(s_t_utils.SynTest):
67
67
  self.eq(node.get('name:given'), 'эммануэль')
68
68
  self.eq(node.get('nicks'), ['beeper88', 'w1ntermut3'])
69
69
  self.eq(node.get('names'), ['bob ross'])
70
- # self.eq(node.get('img'), '') # fixme file:bytes
71
- # self.eq(node.get('guidname'), '') # fixme guid aliases
72
70
 
73
71
  node = await snap.addNode('ps:person:has', (person0, ('test:str', 'sewer map')))
74
72
  self.eq(node.ndef[1], (person0, ('test:str', 'sewer map')))
@@ -94,7 +92,6 @@ class PsModelTest(s_t_utils.SynTest):
94
92
  'place': place,
95
93
  'place:name': 'The Shire',
96
94
  'orgname': 'Stark Industries, INC',
97
- # 'img': '', # fixme file:bytes
98
95
  'user': 'ironman',
99
96
  'web:acct': ('twitter.com', 'ironman'),
100
97
  'web:group': ('twitter.com', 'avengers'),
@@ -157,6 +157,8 @@ class RiskModelTest(s_t_utils.SynTest):
157
157
  :timeline:vendor:fixed=2020-01-14
158
158
  :timeline:published=2020-01-14
159
159
 
160
+ :id=" Vtx-000-1234 "
161
+
160
162
  :cve=cve-2013-0000
161
163
  :cve:desc="Woot Woot"
162
164
  :cve:references=(http://vertex.link,)
@@ -208,6 +210,8 @@ class RiskModelTest(s_t_utils.SynTest):
208
210
  self.eq(node.get('timeline:vendor:fixed'), 1578960000000)
209
211
  self.eq(node.get('timeline:published'), 1578960000000)
210
212
 
213
+ self.eq(node.get('id'), 'Vtx-000-1234')
214
+
211
215
  self.eq(node.get('cve'), 'cve-2013-0000')
212
216
  self.eq(node.get('cve:desc'), 'Woot Woot')
213
217
  self.eq(node.get('cve:references'), ('http://vertex.link',))
@@ -471,6 +475,22 @@ class RiskModelTest(s_t_utils.SynTest):
471
475
  self.len(1, await core.nodes('risk:extortion -> risk:compromise :target -> ps:contact +:orgname=acme'))
472
476
  self.len(1, await core.nodes('risk:extortion :reporter -> ou:org +:name=vertex'))
473
477
 
478
+ nodes = await core.nodes('''[
479
+ risk:technique:masquerade=*
480
+ :node=(inet:fqdn, microsoft-verify.com)
481
+ :target=(inet:fqdn, microsoft.com)
482
+ :technique={[ ou:technique=* :name=masq ]}
483
+ :period=(2021, 2022)
484
+ ]''')
485
+ self.len(1, nodes)
486
+ self.eq(('inet:fqdn', 'microsoft.com'), nodes[0].get('target'))
487
+ self.eq(('inet:fqdn', 'microsoft-verify.com'), nodes[0].get('node'))
488
+ self.eq((1609459200000, 1640995200000), nodes[0].get('period'))
489
+ self.nn(nodes[0].get('technique'))
490
+ self.len(1, await core.nodes('risk:technique:masquerade -> ou:technique'))
491
+ self.len(1, await core.nodes('risk:technique:masquerade :node -> * +inet:fqdn=microsoft-verify.com'))
492
+ self.len(1, await core.nodes('risk:technique:masquerade :target -> * +inet:fqdn=microsoft.com'))
493
+
474
494
  async def test_model_risk_mitigation(self):
475
495
  async with self.getTestCore() as core:
476
496
  nodes = await core.nodes('''[
@@ -65,13 +65,6 @@ class SynModelTest(s_t_utils.SynTest):
65
65
  node = await snap.getNodeByNdef(('syn:tag', 'foo'))
66
66
  self.nn(node)
67
67
 
68
- # We can safely do a pivot in from a syn:tag node
69
- # which will attempt a syn:splice lift which will
70
- # yield no nodes.
71
- self.len(0, await core.nodes('syn:tag=foo.bar.baz <- *'))
72
- nodes = await core.nodes('syn:tag=foo.bar.baz [ :doc:url="http://vertex.link" ]')
73
- self.eq('http://vertex.link', nodes[0].get('doc:url'))
74
-
75
68
  async def test_syn_model_runts(self):
76
69
 
77
70
  async def addExtModelConfigs(cortex):
@@ -292,11 +285,6 @@ class SynModelTest(s_t_utils.SynTest):
292
285
  q = core.nodes('test:str [ +(newp)> { syn:form } ]')
293
286
  await self.asyncraises(s_exc.IsRuntForm, q)
294
287
 
295
- # Syn:splice uses a null lift handler
296
- self.len(1, await core.nodes('[test:str=test]'))
297
- self.len(0, await core.nodes('syn:splice'))
298
- self.len(0, await core.nodes('syn:splice:tag'))
299
-
300
288
  # Ensure that the model runts are re-populated after a model load has occurred.
301
289
  with self.getTestDir() as dirn:
302
290
 
@@ -518,29 +506,27 @@ class SynModelTest(s_t_utils.SynTest):
518
506
 
519
507
  async with self.getTestCore() as core:
520
508
 
521
- visi = await core.auth.addUser('visi')
522
- await visi.addRule((True, ('cron', 'add')))
509
+ visi = await core.addUser('visi')
523
510
 
524
- async with core.getLocalProxy(user='visi') as proxy:
525
- cdef = {'storm': 'inet:ipv4', 'reqs': {'hour': 2}}
526
- adef = await proxy.addCronJob(cdef)
527
- iden = adef.get('iden')
511
+ cdef = {'storm': 'inet:ipv4', 'reqs': {'hour': 2}, 'creator': visi.get('iden')}
512
+ adef = await core.addCronJob(cdef)
513
+ iden = adef.get('iden')
528
514
 
529
- nodes = await core.nodes('syn:cron')
530
- self.len(1, nodes)
531
- self.eq(nodes[0].ndef, ('syn:cron', iden))
532
- self.eq(nodes[0].get('doc'), '')
533
- self.eq(nodes[0].get('name'), '')
534
- self.eq(nodes[0].get('storm'), 'inet:ipv4')
515
+ nodes = await core.nodes('syn:cron')
516
+ self.len(1, nodes)
517
+ self.eq(nodes[0].ndef, ('syn:cron', iden))
518
+ self.eq(nodes[0].get('doc'), '')
519
+ self.eq(nodes[0].get('name'), '')
520
+ self.eq(nodes[0].get('storm'), 'inet:ipv4')
535
521
 
536
- nodes = await core.nodes(f'syn:cron={iden} [ :doc=hehe :name=haha ]')
537
- self.len(1, nodes)
538
- self.eq(nodes[0].ndef, ('syn:cron', iden))
539
- self.eq(nodes[0].get('doc'), 'hehe')
540
- self.eq(nodes[0].get('name'), 'haha')
522
+ nodes = await core.nodes(f'syn:cron={iden} [ :doc=hehe :name=haha ]')
523
+ self.len(1, nodes)
524
+ self.eq(nodes[0].ndef, ('syn:cron', iden))
525
+ self.eq(nodes[0].get('doc'), 'hehe')
526
+ self.eq(nodes[0].get('name'), 'haha')
541
527
 
542
- nodes = await core.nodes(f'syn:cron={iden}')
543
- self.len(1, nodes)
544
- self.eq(nodes[0].ndef, ('syn:cron', iden))
545
- self.eq(nodes[0].get('doc'), 'hehe')
546
- self.eq(nodes[0].get('name'), 'haha')
528
+ nodes = await core.nodes(f'syn:cron={iden}')
529
+ self.len(1, nodes)
530
+ self.eq(nodes[0].ndef, ('syn:cron', iden))
531
+ self.eq(nodes[0].get('doc'), 'hehe')
532
+ self.eq(nodes[0].get('name'), 'haha')
@@ -68,9 +68,10 @@ class CsvToolTest(s_t_utils.SynTest):
68
68
  argv = ['--csv-header', '--debug', '--cortex', url, '--logfile', logpath, stormpath, csvpath]
69
69
  outp = self.getTestOutp()
70
70
 
71
- await s_csvtool.main(argv, outp=outp)
71
+ self.eq(0, await s_csvtool.main(argv, outp=outp))
72
72
  outp.expect('oh hai')
73
73
  outp.expect('2 nodes')
74
+ outp.expect('node:edits') # node edits are present in debug output
74
75
 
75
76
  with mock.patch('synapse.telepath.Proxy._getSynVers', self._getOldSynVers):
76
77
  outp = self.getTestOutp()