synapse 2.193.0__py311-none-any.whl → 2.195.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 (83) hide show
  1. synapse/cortex.py +9 -7
  2. synapse/datamodel.py +9 -6
  3. synapse/exc.py +1 -1
  4. synapse/lib/agenda.py +17 -4
  5. synapse/lib/ast.py +217 -86
  6. synapse/lib/auth.py +5 -2
  7. synapse/lib/link.py +33 -19
  8. synapse/lib/modelrev.py +6 -1
  9. synapse/lib/parser.py +4 -0
  10. synapse/lib/scrape.py +18 -1
  11. synapse/lib/snap.py +40 -11
  12. synapse/lib/storm.lark +16 -1
  13. synapse/lib/storm.py +6 -4
  14. synapse/lib/storm_format.py +1 -0
  15. synapse/lib/stormctrl.py +88 -6
  16. synapse/lib/stormlib/auth.py +15 -1
  17. synapse/lib/stormlib/cache.py +6 -2
  18. synapse/lib/stormlib/cell.py +11 -0
  19. synapse/lib/stormlib/infosec.py +2 -0
  20. synapse/lib/stormlib/scrape.py +1 -1
  21. synapse/lib/stormlib/stix.py +8 -8
  22. synapse/lib/stormtypes.py +13 -5
  23. synapse/lib/version.py +2 -2
  24. synapse/lib/view.py +20 -3
  25. synapse/models/geopol.py +1 -0
  26. synapse/models/geospace.py +53 -10
  27. synapse/models/inet.py +3 -0
  28. synapse/models/infotech.py +12 -5
  29. synapse/models/material.py +67 -8
  30. synapse/models/orgs.py +11 -3
  31. synapse/models/person.py +28 -17
  32. synapse/models/risk.py +4 -1
  33. synapse/models/syn.py +3 -0
  34. synapse/models/telco.py +10 -3
  35. synapse/models/transport.py +382 -49
  36. synapse/tests/test_axon.py +6 -6
  37. synapse/tests/test_cortex.py +134 -12
  38. synapse/tests/test_exc.py +1 -0
  39. synapse/tests/test_lib_agenda.py +125 -1
  40. synapse/tests/test_lib_aha.py +13 -6
  41. synapse/tests/test_lib_ast.py +258 -9
  42. synapse/tests/test_lib_auth.py +6 -7
  43. synapse/tests/test_lib_cell.py +10 -0
  44. synapse/tests/test_lib_grammar.py +14 -0
  45. synapse/tests/test_lib_layer.py +1 -1
  46. synapse/tests/test_lib_link.py +6 -1
  47. synapse/tests/test_lib_lmdbslab.py +3 -3
  48. synapse/tests/test_lib_modelrev.py +7 -0
  49. synapse/tests/test_lib_scrape.py +8 -0
  50. synapse/tests/test_lib_storm.py +201 -25
  51. synapse/tests/test_lib_stormctrl.py +65 -0
  52. synapse/tests/test_lib_stormhttp.py +5 -5
  53. synapse/tests/test_lib_stormlib_auth.py +31 -5
  54. synapse/tests/test_lib_stormlib_cache.py +38 -6
  55. synapse/tests/test_lib_stormlib_cell.py +3 -0
  56. synapse/tests/test_lib_stormlib_modelext.py +3 -3
  57. synapse/tests/test_lib_stormlib_scrape.py +4 -4
  58. synapse/tests/test_lib_stormlib_spooled.py +1 -1
  59. synapse/tests/test_lib_stormlib_xml.py +5 -5
  60. synapse/tests/test_lib_stormtypes.py +54 -57
  61. synapse/tests/test_lib_view.py +1 -1
  62. synapse/tests/test_model_base.py +1 -2
  63. synapse/tests/test_model_geopol.py +4 -0
  64. synapse/tests/test_model_geospace.py +43 -4
  65. synapse/tests/test_model_inet.py +3 -0
  66. synapse/tests/test_model_infotech.py +31 -4
  67. synapse/tests/test_model_material.py +18 -0
  68. synapse/tests/test_model_orgs.py +25 -3
  69. synapse/tests/test_model_person.py +26 -1
  70. synapse/tests/test_model_risk.py +11 -0
  71. synapse/tests/test_model_syn.py +9 -3
  72. synapse/tests/test_model_transport.py +168 -0
  73. synapse/tests/test_telepath.py +24 -5
  74. synapse/tests/test_tools_healthcheck.py +4 -4
  75. synapse/tests/test_utils.py +17 -18
  76. synapse/tests/utils.py +0 -35
  77. synapse/tools/changelog.py +14 -5
  78. synapse/tools/storm.py +1 -1
  79. {synapse-2.193.0.dist-info → synapse-2.195.0.dist-info}/METADATA +5 -5
  80. {synapse-2.193.0.dist-info → synapse-2.195.0.dist-info}/RECORD +83 -82
  81. {synapse-2.193.0.dist-info → synapse-2.195.0.dist-info}/WHEEL +1 -1
  82. {synapse-2.193.0.dist-info → synapse-2.195.0.dist-info}/LICENSE +0 -0
  83. {synapse-2.193.0.dist-info → synapse-2.195.0.dist-info}/top_level.txt +0 -0
@@ -534,11 +534,29 @@ class InfotechModelTest(s_t_utils.SynTest):
534
534
  'ext:id': 'foo123',
535
535
  'image': image.ndef[1],
536
536
  }
537
- q = '''[(it:host=$valu :name=$p.name :desc=$p.desc :ipv4=$p.ipv4 :place=$p.place :latlong=$p.latlong
538
- :os=$p.os :manu=$p.manu :model=$p.model :serial=$p.serial :loc=$p.loc :operator=$p.operator
539
- :org=$p.org :ext:id=$p."ext:id" :image=$p.image)]'''
537
+ q = '''
538
+ [ it:host=$valu
539
+
540
+ :phys:mass=10kg
541
+ :phys:width=5m
542
+ :phys:height=10m
543
+ :phys:length=20m
544
+ :phys:volume=1000m
545
+
546
+ :name=$p.name :desc=$p.desc :ipv4=$p.ipv4 :place=$p.place :latlong=$p.latlong
547
+ :os=$p.os :manu=$p.manu :model=$p.model :serial=$p.serial :loc=$p.loc :operator=$p.operator
548
+ :org=$p.org :ext:id=$p."ext:id" :image=$p.image
549
+ ]
550
+ '''
540
551
  nodes = await core.nodes(q, opts={'vars': {'valu': host0, 'p': props}})
541
552
  self.len(1, nodes)
553
+
554
+ self.eq('10000', nodes[0].get('phys:mass'))
555
+ self.eq(5000, nodes[0].get('phys:width'))
556
+ self.eq(10000, nodes[0].get('phys:height'))
557
+ self.eq(20000, nodes[0].get('phys:length'))
558
+ self.eq(1000000, nodes[0].get('phys:volume'))
559
+
542
560
  node = nodes[0]
543
561
  self.eq(node.ndef[1], host0)
544
562
  self.eq(node.get('name'), 'bobs laptop')
@@ -761,7 +779,7 @@ class InfotechModelTest(s_t_utils.SynTest):
761
779
  'techniques': teqs,
762
780
  'url': url0,
763
781
  }
764
- q = '''[(it:prod:soft=$valu :name=$p.name :type=$p.type :names=$p.names
782
+ q = '''[(it:prod:soft=$valu :id="Foo " :name=$p.name :type=$p.type :names=$p.names
765
783
  :desc=$p.desc :desc:short=$p."desc:short" :author:org=$p."author:org" :author:email=$p."author:email"
766
784
  :author:acct=$p."author:acct" :author:person=$p."author:person"
767
785
  :techniques=$p.techniques :url=$p.url )]'''
@@ -769,6 +787,7 @@ class InfotechModelTest(s_t_utils.SynTest):
769
787
  self.len(1, nodes)
770
788
  node = nodes[0]
771
789
  self.eq(node.ndef, ('it:prod:soft', prod0))
790
+ self.eq(node.get('id'), 'Foo')
772
791
  self.eq(node.get('name'), 'balloon maker')
773
792
  self.eq(node.get('desc'), "Pennywise's patented balloon blower upper")
774
793
  self.eq(node.get('desc:short'), 'balloon blower')
@@ -786,6 +805,10 @@ class InfotechModelTest(s_t_utils.SynTest):
786
805
  self.eq(node.get('url'), url0)
787
806
  self.len(1, await core.nodes('it:prod:soft:name="balloon maker" -> it:prod:soft:taxonomy'))
788
807
  self.len(2, await core.nodes('it:prod:softname="balloon maker" -> it:prod:soft -> it:prod:softname'))
808
+
809
+ self.len(1, nodes := await core.nodes('[ it:prod:soft=({"name": "clowns inc"}) ]'))
810
+ self.eq(node.ndef, nodes[0].ndef)
811
+
789
812
  # it:prod:softver - this does test a bunch of property related callbacks
790
813
  ver0 = s_common.guid()
791
814
  url1 = 'https://vertex.link/products/balloonmaker/release_101-beta.exe'
@@ -819,6 +842,10 @@ class InfotechModelTest(s_t_utils.SynTest):
819
842
  self.eq(node.get('url'), url1)
820
843
  self.eq(node.get('name'), 'balloonmaker')
821
844
  self.eq(node.get('desc'), 'makes balloons')
845
+
846
+ self.len(1, nodes := await core.nodes('[ it:prod:softver=({"name": "clowns inc"}) ]'))
847
+ self.eq(node.ndef, nodes[0].ndef)
848
+
822
849
  # callback node creation checks
823
850
  self.len(1, await core.nodes('it:dev:str=V1.0.1-beta+exp.sha.5114f85'))
824
851
  self.len(1, await core.nodes('it:dev:str=amd64'))
@@ -43,3 +43,21 @@ class MatTest(s_t_utils.SynTest):
43
43
  self.eq(node3.props.get('file'), f0_valu)
44
44
 
45
45
  self.len(1, await core.nodes('mat:spec:name="f16 fighter jet" -> mat:item'))
46
+
47
+ async def test_model_material(self):
48
+
49
+ async with self.getTestCore() as core:
50
+
51
+ nodes = await core.nodes('''[
52
+ phys:contained=*
53
+ :period=(2024, ?)
54
+ :type=component
55
+ :object={[ mat:item=* :phys:volume=9000cm :place:loc=us.ny ]}
56
+ :container={[ mat:item=* :phys:volume=10000cm :place:loc=us.ny ]}
57
+ ]''')
58
+
59
+ self.nn(nodes[0].get('object'))
60
+ self.nn(nodes[0].get('container'))
61
+ self.eq('component.', nodes[0].get('type'))
62
+ self.eq((1704067200000, 9223372036854775807), nodes[0].get('period'))
63
+ self.len(1, await core.nodes('phys:contained -> phys:contained:type:taxonomy'))
@@ -60,6 +60,9 @@ class OuModelTest(s_t_utils.SynTest):
60
60
  self.eq(node.get('desc'), 'MyDesc')
61
61
  self.eq(node.get('prev'), goal)
62
62
 
63
+ self.len(1, nodes := await core.nodes('[ ou:goal=({"name": "foo goal"}) ]'))
64
+ self.eq(node.ndef, nodes[0].ndef)
65
+
63
66
  nodes = await core.nodes('[(ou:hasgoal=$valu :stated=$lib.true :window="2019,2020")]',
64
67
  opts={'vars': {'valu': (org0, goal)}})
65
68
  self.len(1, nodes)
@@ -69,12 +72,13 @@ class OuModelTest(s_t_utils.SynTest):
69
72
  self.eq(node.get('stated'), True)
70
73
  self.eq(node.get('window'), (1546300800000, 1577836800000))
71
74
 
75
+ altgoal = s_common.guid()
72
76
  timeline = s_common.guid()
73
77
 
74
78
  props = {
75
79
  'org': org0,
76
80
  'goal': goal,
77
- 'goals': (goal,),
81
+ 'goals': (goal, altgoal),
78
82
  'actors': (acto,),
79
83
  'camptype': 'get.pizza',
80
84
  'name': 'MyName',
@@ -103,7 +107,7 @@ class OuModelTest(s_t_utils.SynTest):
103
107
  self.eq(node.get('tag'), 'cno.camp.31337')
104
108
  self.eq(node.get('org'), org0)
105
109
  self.eq(node.get('goal'), goal)
106
- self.eq(node.get('goals'), (goal,))
110
+ self.eq(node.get('goals'), sorted((goal, altgoal)))
107
111
  self.eq(node.get('actors'), (acto,))
108
112
  self.eq(node.get('name'), 'myname')
109
113
  self.eq(node.get('names'), ('bar', 'foo'))
@@ -120,6 +124,10 @@ class OuModelTest(s_t_utils.SynTest):
120
124
  self.eq(node.get('mitre:attack:campaign'), 'C0011')
121
125
  self.eq(node.get('slogan'), 'for the people')
122
126
 
127
+ opts = {'vars': {'altgoal': altgoal}}
128
+ self.len(1, nodes := await core.nodes('[ ou:campaign=({"name": "foo", "goal": $altgoal}) ]', opts=opts))
129
+ self.eq(node.ndef, nodes[0].ndef)
130
+
123
131
  self.len(1, await core.nodes(f'ou:campaign={camp} :slogan -> lang:phrase'))
124
132
  nodes = await core.nodes(f'ou:campaign={camp} -> it:mitre:attack:campaign')
125
133
  self.len(1, nodes)
@@ -405,6 +413,9 @@ class OuModelTest(s_t_utils.SynTest):
405
413
  self.eq(node.get('place'), place0)
406
414
  self.eq(node.get('url'), 'http://arrowcon.org/2018')
407
415
 
416
+ self.len(1, nodes := await core.nodes('[ ou:conference=({"name": "arrcon18"}) ]'))
417
+ self.eq(node.ndef, nodes[0].ndef)
418
+
408
419
  props = {
409
420
  'arrived': '201803010800',
410
421
  'departed': '201803021500',
@@ -466,14 +477,21 @@ class OuModelTest(s_t_utils.SynTest):
466
477
  self.eq(node.get('departed'), 1519945200000)
467
478
  self.eq(node.get('roles'), ('speaker', 'staff'))
468
479
 
469
- nodes = await core.nodes('[ ou:id:type=* :org=* :name=foobar :url="http://foobar.com/ids"]')
480
+ nodes = await core.nodes('[ ou:id:type=* :org=* :name=foobar :names=(alt1,alt2) :url="http://foobar.com/ids"]')
470
481
  self.len(1, nodes)
471
482
  self.nn(nodes[0].get('org'))
472
483
  self.eq('foobar', nodes[0].get('name'))
484
+ self.eq(('alt1', 'alt2'), nodes[0].get('names'))
473
485
  self.eq('http://foobar.com/ids', nodes[0].get('url'))
474
486
 
475
487
  iden = await core.callStorm('ou:id:type return($node.value())')
476
488
 
489
+ self.len(1, alts := await core.nodes('[ ou:id:type=({"name": "foobar"}) ]'))
490
+ self.eq(nodes[0].ndef, alts[0].ndef)
491
+
492
+ self.len(1, alts := await core.nodes('[ ou:id:type=({"name": "alt1"}) ]'))
493
+ self.eq(nodes[0].ndef, alts[0].ndef)
494
+
477
495
  opts = {'vars': {'type': iden}}
478
496
  nodes = await core.nodes('''
479
497
  [ ou:id:number=($type, visi)
@@ -870,6 +888,7 @@ class OuModelTest(s_t_utils.SynTest):
870
888
  ] '''
871
889
  nodes = await core.nodes(q)
872
890
  self.len(1, nodes)
891
+ node = nodes[0]
873
892
  self.nn(nodes[0].get('reporter'))
874
893
  self.eq('foo bar', nodes[0].get('name'))
875
894
  self.eq('vertex', nodes[0].get('reporter:name'))
@@ -884,6 +903,9 @@ class OuModelTest(s_t_utils.SynTest):
884
903
  self.len(3, nodes)
885
904
  self.len(3, await core.nodes('ou:industryname=baz -> ou:industry -> ou:industryname'))
886
905
 
906
+ self.len(1, nodes := await core.nodes('[ ou:industry=({"name": "faz"}) ]'))
907
+ self.eq(node.ndef, nodes[0].ndef)
908
+
887
909
  async def test_ou_opening(self):
888
910
 
889
911
  async with self.getTestCore() as core:
@@ -60,6 +60,9 @@ class PsModelTest(s_t_utils.SynTest):
60
60
  self.eq(node.get('names'), ['billy bob'])
61
61
  self.eq(node.get('photo'), file0)
62
62
 
63
+ self.len(1, nodes := await core.nodes('[ ps:person=({"name": "billy bob"}) ]'))
64
+ self.eq(node.ndef, nodes[0].ndef)
65
+
63
66
  props = {
64
67
  'dob': '2000',
65
68
  'img': file0,
@@ -147,9 +150,11 @@ class PsModelTest(s_t_utils.SynTest):
147
150
  'id:numbers': (('*', 'asdf'), ('*', 'qwer')),
148
151
  'users': ('visi', 'invisigoth'),
149
152
  'crypto:address': 'btc/1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2',
153
+ 'langs': (lang00 := s_common.guid(),),
150
154
  }
151
155
  opts = {'vars': {'valu': con0, 'p': props}}
152
156
  q = '''[(ps:contact=$valu
157
+ :bio="I am ironman."
153
158
  :org=$p.org :asof=$p.asof :person=$p.person
154
159
  :place=$p.place :place:name=$p."place:name" :name=$p.name
155
160
  :title=$p.title :orgname=$p.orgname :user=$p.user
@@ -165,7 +170,7 @@ class PsModelTest(s_t_utils.SynTest):
165
170
  :birth:place:name=$p."birth:place:name"
166
171
  :death:place=$p."death:place" :death:place:loc=$p."death:place:loc"
167
172
  :death:place:name=$p."death:place:name"
168
- :service:accounts=(*, *)
173
+ :service:accounts=(*, *) :langs=$p.langs
169
174
  )]'''
170
175
  nodes = await core.nodes(q, opts=opts)
171
176
  self.len(1, nodes)
@@ -178,6 +183,7 @@ class PsModelTest(s_t_utils.SynTest):
178
183
  self.eq(node.get('place'), place)
179
184
  self.eq(node.get('place:name'), 'the shire')
180
185
  self.eq(node.get('name'), 'tony stark')
186
+ self.eq(node.get('bio'), 'I am ironman.')
181
187
  self.eq(node.get('title'), 'ceo')
182
188
  self.eq(node.get('titles'), ('haha', 'hehe'))
183
189
  self.eq(node.get('orgname'), 'stark industries, inc')
@@ -211,6 +217,22 @@ class PsModelTest(s_t_utils.SynTest):
211
217
  self.len(1, await core.nodes('ps:contact :death:place -> geo:place'))
212
218
  self.len(2, await core.nodes('ps:contact :service:accounts -> inet:service:account'))
213
219
 
220
+ opts = {
221
+ 'vars': {
222
+ 'ctor': {
223
+ 'email': 'v@vtx.lk',
224
+ 'id:number': node.get('id:numbers')[0],
225
+ 'lang': lang00,
226
+ 'name': 'vi',
227
+ 'orgname': 'vertex',
228
+ 'title': 'haha',
229
+ 'user': 'invisigoth',
230
+ },
231
+ },
232
+ }
233
+ self.len(1, nodes := await core.nodes('[ ps:contact=$ctor ]', opts=opts))
234
+ self.eq(node.ndef, nodes[0].ndef)
235
+
214
236
  nodes = await core.nodes('''[
215
237
  ps:achievement=*
216
238
  :award=*
@@ -347,6 +369,7 @@ class PsModelTest(s_t_utils.SynTest):
347
369
  :econ:currency=usd
348
370
  :econ:net:worth=100
349
371
  :econ:annual:income=1000
372
+ :phys:mass=100lbs
350
373
  ]
351
374
  { -> ps:person [ :vitals={ps:vitals} ] }
352
375
  { -> ps:contact [ :vitals={ps:vitals} ] }
@@ -356,6 +379,8 @@ class PsModelTest(s_t_utils.SynTest):
356
379
  self.eq(1828, nodes[0].get('height'))
357
380
  self.eq('90718.4', nodes[0].get('weight'))
358
381
 
382
+ self.eq('45359.2', nodes[0].get('phys:mass'))
383
+
359
384
  self.eq('usd', nodes[0].get('econ:currency'))
360
385
  self.eq('100', nodes[0].get('econ:net:worth'))
361
386
  self.eq('1000', nodes[0].get('econ:annual:income'))
@@ -253,6 +253,9 @@ class RiskModelTest(s_t_utils.SynTest):
253
253
  self.len(1, await core.nodes('risk:attack :target -> ps:contact'))
254
254
  self.len(1, await core.nodes('risk:attack :attacker -> ps:contact'))
255
255
 
256
+ self.len(1, nodes := await core.nodes('[ risk:vuln=({"name": "hehe"}) ]'))
257
+ self.eq(node.ndef, nodes[0].ndef)
258
+
256
259
  node = await addNode(f'''[
257
260
  risk:hasvuln={hasv}
258
261
  :vuln={vuln}
@@ -399,6 +402,7 @@ class RiskModelTest(s_t_utils.SynTest):
399
402
  ]
400
403
  ''')
401
404
  self.len(1, nodes)
405
+ node = nodes[0]
402
406
  self.eq('vtx-apt1', nodes[0].get('name'))
403
407
  self.eq('VTX-APT1', nodes[0].get('desc'))
404
408
  self.eq(40, nodes[0].get('activity'))
@@ -424,6 +428,9 @@ class RiskModelTest(s_t_utils.SynTest):
424
428
  self.len(1, await core.nodes('risk:threat:merged:isnow -> risk:threat'))
425
429
  self.len(1, await core.nodes('risk:threat -> it:mitre:attack:group'))
426
430
 
431
+ self.len(1, nodes := await core.nodes('[ risk:threat=({"org:name": "comment crew"}) ]'))
432
+ self.eq(node.ndef, nodes[0].ndef)
433
+
427
434
  nodes = await core.nodes('''[ risk:leak=*
428
435
  :name="WikiLeaks ACME Leak"
429
436
  :desc="WikiLeaks leaked ACME stuff."
@@ -618,6 +625,7 @@ class RiskModelTest(s_t_utils.SynTest):
618
625
  ]
619
626
  ''')
620
627
  self.len(1, nodes)
628
+ node = nodes[0]
621
629
  self.nn(nodes[0].get('soft'))
622
630
 
623
631
  self.nn(nodes[0].get('reporter'))
@@ -640,6 +648,9 @@ class RiskModelTest(s_t_utils.SynTest):
640
648
  self.len(1, await core.nodes('risk:tool:software -> syn:tag'))
641
649
  self.len(1, await core.nodes('risk:tool:software -> it:mitre:attack:software'))
642
650
 
651
+ self.len(1, nodes := await core.nodes('[ risk:tool:software=({"soft:name": "beacon"}) ]'))
652
+ self.eq(node.ndef, nodes[0].ndef)
653
+
643
654
  nodes = await core.nodes('''
644
655
  [ risk:vuln:soft:range=*
645
656
  :vuln={[ risk:vuln=* :name=woot ]}
@@ -612,10 +612,16 @@ class SynModelTest(s_t_utils.SynTest):
612
612
  nodes = await core.nodes('syn:cmd +:package')
613
613
  self.len(0, nodes)
614
614
 
615
- await core.nodes(f'service.add test {url}')
616
- iden = core.getStormSvcs()[0].iden
615
+ with self.getLoggerStream('synapse.cortex') as stream:
616
+ await core.nodes(f'service.add test {url}')
617
+ iden = core.getStormSvcs()[0].iden
617
618
 
618
- await core.nodes('$lib.service.wait(test)')
619
+ await core.nodes('$lib.service.wait(test)')
620
+
621
+ stream.seek(0)
622
+ warn = "Storm command definition 'forms' key is deprecated and will be removed " \
623
+ "in 3.0.0 (command foobar in package foo)"
624
+ self.isin(warn, stream.read())
619
625
 
620
626
  # check that runt nodes for new commands are created
621
627
  nodes = await core.nodes('syn:cmd +:package')
@@ -88,6 +88,7 @@ class TransportTest(s_test.SynTest):
88
88
  :mmsi=123456789
89
89
  :name="Slice of Life"
90
90
  :flag=us
91
+ :type=cargo.tanker.oil
91
92
  :imo="IMO 1234567"
92
93
  :built=2020
93
94
  :make="The Vertex Project"
@@ -98,6 +99,7 @@ class TransportTest(s_test.SynTest):
98
99
  ]'''))[0]
99
100
  self.eq('123456789', vessel.get('mmsi'))
100
101
  self.eq('slice of life', vessel.get('name'))
102
+ self.eq('cargo.tanker.oil.', vessel.get('type'))
101
103
  self.eq('the vertex project', vessel.get('make'))
102
104
  self.eq('speed boat 9000', vessel.get('model'))
103
105
  self.eq('us', vessel.get('flag'))
@@ -108,6 +110,7 @@ class TransportTest(s_test.SynTest):
108
110
  self.nn(vessel.get('operator'))
109
111
 
110
112
  self.len(1, await core.nodes('transport:sea:vessel:imo^="IMO 123"'))
113
+ self.len(1, await core.nodes('transport:sea:vessel -> transport:sea:vessel:type:taxonomy'))
111
114
 
112
115
  seatelem = (await core.nodes('''[
113
116
  transport:sea:telem=*
@@ -166,6 +169,7 @@ class TransportTest(s_test.SynTest):
166
169
  :make=lotus
167
170
  :model=elise
168
171
  :registration=$regid
172
+ :type=car
169
173
  :owner={gen.ps.contact.email us.va.dmv visi@vertex.link}
170
174
  ]}
171
175
 
@@ -192,12 +196,14 @@ class TransportTest(s_test.SynTest):
192
196
 
193
197
  nodes = await core.nodes('transport:land:registration:id=zeroday :vehicle -> transport:land:vehicle')
194
198
  self.len(1, nodes)
199
+ self.eq(nodes[0].get('type'), 'car.')
195
200
  self.eq(nodes[0].get('make'), 'lotus')
196
201
  self.eq(nodes[0].get('model'), 'elise')
197
202
  self.eq(nodes[0].get('serial'), 'V-31337')
198
203
  self.eq(nodes[0].get('built'), 1104537600000)
199
204
  self.nn(nodes[0].get('owner'))
200
205
  self.nn(nodes[0].get('registration'))
206
+ self.len(1, await core.nodes('transport:land:vehicle -> transport:land:vehicle:type:taxonomy'))
201
207
 
202
208
  nodes = await core.nodes('transport:land:registration:id=zeroday -> transport:land:license')
203
209
  self.len(1, nodes)
@@ -208,3 +214,165 @@ class TransportTest(s_test.SynTest):
208
214
 
209
215
  self.nn(nodes[0].get('issuer'))
210
216
  self.nn(nodes[0].get('contact'))
217
+
218
+ nodes = await core.nodes('''[
219
+ transport:land:drive=*
220
+ :vehicle={transport:land:vehicle}
221
+ ]''')
222
+
223
+ self.eq('transport:land:vehicle', nodes[0].get('vehicle')[0])
224
+
225
+ async def test_model_transport_rail(self):
226
+
227
+ async with self.getTestCore() as core:
228
+ nodes = await core.nodes('''[
229
+ transport:rail:train=*
230
+
231
+ :status=completed
232
+ :occupants=1
233
+ :cargo:mass=10kg
234
+ :cargo:volume=10m
235
+
236
+ :duration=03:00:00
237
+ :scheduled:duration=03:00:00
238
+
239
+ :departed=202501171030
240
+ :departed:point=2C
241
+ :departed:place={[ geo:place=* :name="grand central station" ]}
242
+
243
+ :scheduled:departure=202501171030
244
+ :scheduled:departure:point=2C
245
+ :scheduled:departure:place={ geo:place:name="grand central station" }
246
+
247
+ :arrived=202501171330
248
+ :arrived:place={[ geo:place=* :name="union station" ]}
249
+ :arrived:point=2C
250
+
251
+ :scheduled:arrival=202501171330
252
+ :scheduled:arrival:place={ geo:place:name="union station" }
253
+ :scheduled:arrival:point=2C
254
+
255
+ :vehicle={[
256
+ transport:rail:consist=*
257
+ :max:occupants=2
258
+ :cars={[
259
+ transport:rail:car=*
260
+ :serial=001
261
+ :type=engine.diesel
262
+ :built=20221212
263
+ :manufacturer:name=acme
264
+ :manufacturer={[ ou:org=({"name": "acme"}) ]}
265
+ :model="Engine That Could"
266
+ :max:occupants=2
267
+ :max:cargo:mass=1000kg
268
+ :max:cargo:volume=1000m
269
+ :owner={[ ps:contact=* :name="road runner" ]}
270
+ ]}
271
+ ]}
272
+ :operator={[ ps:contact=* :name="visi" ]}
273
+ ]''')
274
+
275
+ self.eq(10800000, nodes[0].get('duration'))
276
+ self.eq(10800000, nodes[0].get('scheduled:duration'))
277
+
278
+ self.eq(1737109800000, nodes[0].get('departed'))
279
+ self.eq('2c', nodes[0].get('departed:point'))
280
+ self.nn(nodes[0].get('departed:place'))
281
+
282
+ self.eq(1737109800000, nodes[0].get('scheduled:departure'))
283
+ self.eq('2c', nodes[0].get('scheduled:departure:point'))
284
+ self.nn(nodes[0].get('scheduled:departure:place'))
285
+
286
+ self.eq(1737120600000, nodes[0].get('arrived'))
287
+ self.nn(nodes[0].get('arrived:place'))
288
+ self.eq('2c', nodes[0].get('arrived:point'))
289
+
290
+ self.eq(1737120600000, nodes[0].get('scheduled:arrival'))
291
+ self.nn(nodes[0].get('scheduled:arrival:place'))
292
+ self.eq('2c', nodes[0].get('scheduled:arrival:point'))
293
+
294
+ nodes = await core.nodes('transport:rail:consist')
295
+ self.eq(2, nodes[0].get('max:occupants'))
296
+ self.len(1, nodes[0].get('cars'))
297
+
298
+ nodes = await core.nodes('transport:rail:car')
299
+ self.eq('001', nodes[0].get('serial'))
300
+ self.eq('engine.diesel.', nodes[0].get('type'))
301
+ self.eq(1670803200000, nodes[0].get('built'))
302
+ self.eq('acme', nodes[0].get('manufacturer:name'))
303
+ self.eq('engine that could', nodes[0].get('model'))
304
+ self.eq(2, nodes[0].get('max:occupants'))
305
+ self.eq('1000000', nodes[0].get('max:cargo:mass'))
306
+ self.eq(1000000, nodes[0].get('max:cargo:volume'))
307
+ self.len(1, await core.nodes('transport:rail:car -> transport:rail:car:type:taxonomy'))
308
+
309
+ self.nn(nodes[0].get('owner'))
310
+
311
+ nodes = await core.nodes('''[
312
+ transport:stop=*
313
+ :arrived:place={[ geo:place=* :name="BWI Rail Station" ]}
314
+ :trip={ transport:rail:train }
315
+ ]''')
316
+ self.nn(nodes[0].get('arrived:place'))
317
+ self.eq('transport:rail:train', nodes[0].get('trip')[0])
318
+
319
+ nodes = await core.nodes('''[
320
+ transport:occupant=*
321
+ :role=passenger
322
+ :contact={[ ps:contact=({"name": "visi"}) ]}
323
+ :trip={ transport:rail:train }
324
+ :vehicle={ transport:rail:consist }
325
+ :seat=2c
326
+ :boarded=202501171020
327
+ :boarded:point=2c
328
+ :boarded:place={ geo:place:name="grand central station" }
329
+
330
+ :disembarked=202501171335
331
+ :disembarked:point=2c
332
+ :disembarked:place={ geo:place:name="union station" }
333
+ ]''')
334
+ self.nn(nodes[0].get('contact'))
335
+ self.eq('2c', nodes[0].get('seat'))
336
+ self.eq('passenger.', nodes[0].get('role'))
337
+ self.eq('transport:rail:train', nodes[0].get('trip')[0])
338
+ self.eq('transport:rail:consist', nodes[0].get('vehicle')[0])
339
+
340
+ self.eq(1737109200000, nodes[0].get('boarded'))
341
+ self.nn(nodes[0].get('boarded:place'))
342
+ self.eq('2c', nodes[0].get('boarded:point'))
343
+
344
+ self.eq(1737120900000, nodes[0].get('disembarked'))
345
+ self.nn(nodes[0].get('disembarked:place'))
346
+ self.eq('2c', nodes[0].get('disembarked:point'))
347
+ self.len(1, await core.nodes('transport:occupant -> transport:occupant:role:taxonomy'))
348
+
349
+ nodes = await core.nodes('''[
350
+ transport:cargo=*
351
+
352
+ :trip={ transport:rail:train }
353
+ :vehicle={ transport:rail:consist }
354
+
355
+ :container={ transport:rail:car }
356
+ :object={[ transport:shipping:container=({"serial": "007"}) ]}
357
+
358
+ :loaded=202501171020
359
+ :loaded:point=2c
360
+ :loaded:place={ geo:place:name="grand central station" }
361
+
362
+ :unloaded=202501171335
363
+ :unloaded:point=2c
364
+ :unloaded:place={ geo:place:name="union station" }
365
+ ]''')
366
+
367
+ self.eq('transport:rail:train', nodes[0].get('trip')[0])
368
+ self.eq('transport:rail:car', nodes[0].get('container')[0])
369
+ self.eq('transport:rail:consist', nodes[0].get('vehicle')[0])
370
+ self.eq('transport:shipping:container', nodes[0].get('object')[0])
371
+
372
+ self.eq(1737109200000, nodes[0].get('loaded'))
373
+ self.nn(nodes[0].get('loaded:place'))
374
+ self.eq('2c', nodes[0].get('loaded:point'))
375
+
376
+ self.eq(1737120900000, nodes[0].get('unloaded'))
377
+ self.nn(nodes[0].get('unloaded:place'))
378
+ self.eq('2c', nodes[0].get('unloaded:point'))
@@ -19,6 +19,7 @@ import synapse.telepath as s_telepath
19
19
  import synapse.lib.cell as s_cell
20
20
  import synapse.lib.coro as s_coro
21
21
  import synapse.lib.link as s_link
22
+ import synapse.lib.const as s_const
22
23
  import synapse.lib.share as s_share
23
24
  import synapse.lib.certdir as s_certdir
24
25
  import synapse.lib.version as s_version
@@ -68,6 +69,10 @@ class Foo:
68
69
  def echo(self, x):
69
70
  return x
70
71
 
72
+ def echosize(self, array: list[bytes]):
73
+ total = sum([len(bytz) for bytz in array])
74
+ return total
75
+
71
76
  def speed(self):
72
77
  return
73
78
 
@@ -230,11 +235,13 @@ class TeleTest(s_t_utils.SynTest):
230
235
  # Add an additional prox.fini handler.
231
236
  prox.onfini(evt.set)
232
237
 
233
- # check a standard return value
234
- self.eq(30, await prox.bar(10, 20))
238
+ with mock.patch('synapse.lib.link.MAXWRITE', 2):
235
239
 
236
- # check a coroutine return value
237
- self.eq(25, await prox.corovalu(10, 5))
240
+ # check a standard return value
241
+ self.eq(30, await prox.bar(10, 20))
242
+
243
+ # check a coroutine return value
244
+ self.eq(25, await prox.corovalu(10, 5))
238
245
 
239
246
  # check a generator return channel
240
247
  genr = await prox.genr()
@@ -1227,7 +1234,7 @@ class TeleTest(s_t_utils.SynTest):
1227
1234
  self.isin('synapse.tests.test_telepath.Foo', proxy._getClasses())
1228
1235
  self.eq(await proxy.echo('oh hi mark!'), 'oh hi mark!')
1229
1236
 
1230
- async def test_tls_ciphers(self):
1237
+ async def test_tls_support_and_ciphers(self):
1231
1238
 
1232
1239
  self.thisHostMustNot(platform='darwin')
1233
1240
 
@@ -1249,6 +1256,18 @@ class TeleTest(s_t_utils.SynTest):
1249
1256
  async with await s_telepath.openurl(f'ssl://{hostname}/foo', port=port) as prox:
1250
1257
  self.eq(30, await prox.bar(10, 20))
1251
1258
 
1259
+ # This will generate a large msgpack object which can cause
1260
+ # openssl to have malloc failures. Prior to the write chunking
1261
+ # changes, this would cause a generally fatal error to any
1262
+ # processes which rely on the calls work, such as mirror loops.
1263
+ blob = b'V' * s_const.mebibyte * 256
1264
+ nblobs = 8
1265
+ total = nblobs * len(blob)
1266
+ blobarray = []
1267
+ for i in range(nblobs):
1268
+ blobarray.append(blob)
1269
+ self.eq(await prox.echosize(blobarray), total)
1270
+
1252
1271
  sslctx = ssl.SSLContext(protocol=ssl.PROTOCOL_TLSv1)
1253
1272
  with self.raises((ssl.SSLError, ConnectionResetError)):
1254
1273
  link = await s_link.connect(hostname, port=port, ssl=sslctx)
@@ -45,7 +45,7 @@ class HealthcheckTest(s_t_utils.SynTest):
45
45
  await asyncio.sleep(0.6)
46
46
  core.addHealthFunc(sleep)
47
47
  outp.clear()
48
- retn = await s_t_healthcheck.main(['-c', curl, '-t', '0.2'], outp)
48
+ retn = await s_t_healthcheck.main(['-c', curl, '-t', '0.4'], outp)
49
49
  self.eq(retn, 1)
50
50
  resp = json.loads(str(outp))
51
51
  self.eq(resp.get('components')[0].get('name'), 'error')
@@ -58,7 +58,7 @@ class HealthcheckTest(s_t_utils.SynTest):
58
58
  _, port = await core.dmon.listen('tcp://127.0.0.1:0')
59
59
  root = await core.auth.getUserByName('root')
60
60
  await root.setPasswd('secret')
61
- retn = await s_t_healthcheck.main(['-c', f'tcp://root:newp@127.0.0.1:{port}/cortex', '-t', '0.2'], outp)
61
+ retn = await s_t_healthcheck.main(['-c', f'tcp://root:newp@127.0.0.1:{port}/cortex', '-t', '0.4'], outp)
62
62
  self.eq(retn, 1)
63
63
  resp = json.loads(str(outp))
64
64
  self.eq(resp.get('components')[0].get('name'), 'error')
@@ -70,7 +70,7 @@ class HealthcheckTest(s_t_utils.SynTest):
70
70
 
71
71
  logger.info('Checking without perms')
72
72
  outp.clear()
73
- retn = await s_t_healthcheck.main(['-c', f'tcp://visi:secret@127.0.0.1:{port}/cortex', '-t', '0.2'], outp)
73
+ retn = await s_t_healthcheck.main(['-c', f'tcp://visi:secret@127.0.0.1:{port}/cortex', '-t', '0.4'], outp)
74
74
  self.eq(retn, 1)
75
75
  resp = json.loads(str(outp))
76
76
  self.eq(resp.get('components')[0].get('name'), 'error')
@@ -83,7 +83,7 @@ class HealthcheckTest(s_t_utils.SynTest):
83
83
  await core.fini()
84
84
  await asyncio.sleep(0)
85
85
  outp.clear()
86
- retn = await s_t_healthcheck.main(['-c', curl, '-t', '0.2'], outp)
86
+ retn = await s_t_healthcheck.main(['-c', curl, '-t', '0.4'], outp)
87
87
  self.eq(retn, 1)
88
88
  resp = json.loads(str(outp))
89
89
  self.eq(resp.get('components')[0].get('name'), 'error')