synapse 2.177.0__py311-none-any.whl → 2.179.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/cortex.py +170 -31
  2. synapse/datamodel.py +47 -1
  3. synapse/exc.py +1 -0
  4. synapse/lib/aha.py +362 -88
  5. synapse/lib/ast.py +26 -22
  6. synapse/lib/base.py +39 -12
  7. synapse/lib/cell.py +315 -119
  8. synapse/lib/config.py +15 -11
  9. synapse/lib/coro.py +27 -0
  10. synapse/lib/drive.py +551 -0
  11. synapse/lib/layer.py +0 -5
  12. synapse/lib/link.py +1 -1
  13. synapse/lib/lmdbslab.py +3 -3
  14. synapse/lib/nexus.py +24 -12
  15. synapse/lib/schemas.py +39 -0
  16. synapse/lib/snap.py +17 -7
  17. synapse/lib/storm.py +3 -1
  18. synapse/lib/stormhttp.py +1 -0
  19. synapse/lib/stormlib/imap.py +6 -2
  20. synapse/lib/stormlib/modelext.py +29 -3
  21. synapse/lib/stormlib/smtp.py +12 -2
  22. synapse/lib/stormlib/stix.py +40 -17
  23. synapse/lib/stormlib/vault.py +2 -2
  24. synapse/lib/stormtypes.py +1 -1
  25. synapse/lib/types.py +9 -0
  26. synapse/lib/version.py +2 -2
  27. synapse/lookup/pe.py +303 -38
  28. synapse/models/dns.py +24 -1
  29. synapse/models/geospace.py +4 -1
  30. synapse/models/infotech.py +26 -1
  31. synapse/telepath.py +32 -17
  32. synapse/tests/files/aha/certs/cas/synapse.crt +28 -0
  33. synapse/tests/files/aha/certs/cas/synapse.key +51 -0
  34. synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.crt +30 -0
  35. synapse/tests/files/aha/certs/hosts/00.aha.loop.vertex.link.key +51 -0
  36. synapse/tests/files/aha/certs/users/root@synapse.crt +29 -0
  37. synapse/tests/files/aha/certs/users/root@synapse.key +51 -0
  38. synapse/tests/files/rstorm/testsvc.py +1 -1
  39. synapse/tests/test_axon.py +1 -1
  40. synapse/tests/test_cortex.py +67 -60
  41. synapse/tests/test_lib_agenda.py +3 -3
  42. synapse/tests/test_lib_aha.py +353 -490
  43. synapse/tests/test_lib_base.py +20 -0
  44. synapse/tests/test_lib_cell.py +273 -22
  45. synapse/tests/test_lib_config.py +4 -3
  46. synapse/tests/test_lib_coro.py +12 -0
  47. synapse/tests/test_lib_nexus.py +8 -0
  48. synapse/tests/test_lib_stormhttp.py +40 -0
  49. synapse/tests/test_lib_stormlib_aha.py +35 -35
  50. synapse/tests/test_lib_stormlib_cell.py +4 -15
  51. synapse/tests/test_lib_stormlib_imap.py +14 -3
  52. synapse/tests/test_lib_stormlib_modelext.py +55 -3
  53. synapse/tests/test_lib_stormlib_smtp.py +51 -0
  54. synapse/tests/test_lib_stormlib_stix.py +15 -0
  55. synapse/tests/test_lib_stormlib_vault.py +11 -1
  56. synapse/tests/test_lib_stormtypes.py +5 -0
  57. synapse/tests/test_lib_types.py +9 -0
  58. synapse/tests/test_model_dns.py +8 -0
  59. synapse/tests/test_model_geospace.py +3 -1
  60. synapse/tests/test_model_infotech.py +47 -0
  61. synapse/tests/test_model_syn.py +11 -0
  62. synapse/tests/test_tools_aha.py +78 -101
  63. synapse/tests/test_utils_stormcov.py +1 -1
  64. synapse/tests/utils.py +86 -120
  65. synapse/tools/aha/clone.py +50 -0
  66. synapse/tools/aha/enroll.py +2 -1
  67. synapse/tools/backup.py +2 -2
  68. synapse/tools/changelog.py +31 -1
  69. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/METADATA +48 -48
  70. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/RECORD +73 -65
  71. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/WHEEL +1 -1
  72. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/LICENSE +0 -0
  73. {synapse-2.177.0.dist-info → synapse-2.179.0.dist-info}/top_level.txt +0 -0
synapse/lib/ast.py CHANGED
@@ -1953,7 +1953,7 @@ class PivotOut(PivotOper):
1953
1953
  typename = prop.type.opts.get('type')
1954
1954
  if runt.model.forms.get(typename) is not None:
1955
1955
  for item in valu:
1956
- async for pivo in runt.snap.nodesByPropValu(typename, '=', item):
1956
+ async for pivo in runt.snap.nodesByPropValu(typename, '=', item, norm=False):
1957
1957
  yield pivo, path.fork(pivo)
1958
1958
 
1959
1959
  form = runt.model.forms.get(prop.type.name)
@@ -2090,11 +2090,13 @@ class PivotIn(PivotOper):
2090
2090
  name, valu = node.ndef
2091
2091
 
2092
2092
  for prop in runt.model.getPropsByType(name):
2093
- async for pivo in runt.snap.nodesByPropValu(prop.full, '=', valu):
2093
+ norm = node.form.typehash is not prop.typehash
2094
+ async for pivo in runt.snap.nodesByPropValu(prop.full, '=', valu, norm=norm):
2094
2095
  yield pivo, path.fork(pivo)
2095
2096
 
2096
2097
  for prop in runt.model.getArrayPropsByType(name):
2097
- async for pivo in runt.snap.nodesByPropArray(prop.full, '=', valu):
2098
+ norm = node.form.typehash is not prop.arraytypehash
2099
+ async for pivo in runt.snap.nodesByPropArray(prop.full, '=', valu, norm=norm):
2098
2100
  yield pivo, path.fork(pivo)
2099
2101
 
2100
2102
  async for refsbuid in runt.snap.getNdefRefs(node.buid):
@@ -2141,7 +2143,7 @@ class PivotInFrom(PivotOper):
2141
2143
  if self.isjoin:
2142
2144
  yield node, path
2143
2145
 
2144
- async for pivo in runt.snap.nodesByPropValu(full, '=', node.ndef):
2146
+ async for pivo in runt.snap.nodesByPropValu(full, '=', node.ndef, norm=False):
2145
2147
  yield pivo, path.fork(pivo)
2146
2148
 
2147
2149
  return
@@ -2179,7 +2181,7 @@ class FormPivot(PivotOper):
2179
2181
  if isinstance(prop.type, s_types.Ndef):
2180
2182
 
2181
2183
  async def pgenr(node, strict=True):
2182
- async for pivo in runt.snap.nodesByPropValu(prop.full, '=', node.ndef):
2184
+ async for pivo in runt.snap.nodesByPropValu(prop.full, '=', node.ndef, norm=False):
2183
2185
  yield pivo
2184
2186
 
2185
2187
  elif not prop.isform:
@@ -2190,13 +2192,14 @@ class FormPivot(PivotOper):
2190
2192
  async def pgenr(node, strict=True):
2191
2193
  if isarray:
2192
2194
  if isinstance(prop.type.arraytype, s_types.Ndef):
2193
- ngenr = runt.snap.nodesByPropArray(prop.full, '=', node.ndef)
2195
+ ngenr = runt.snap.nodesByPropArray(prop.full, '=', node.ndef, norm=False)
2194
2196
  else:
2195
- ngenr = runt.snap.nodesByPropArray(prop.full, '=', node.ndef[1])
2197
+ norm = prop.arraytypehash is not node.form.typehash
2198
+ ngenr = runt.snap.nodesByPropArray(prop.full, '=', node.ndef[1], norm=norm)
2196
2199
  else:
2197
- ngenr = runt.snap.nodesByPropValu(prop.full, '=', node.ndef[1])
2200
+ norm = prop.typehash is not node.form.typehash
2201
+ ngenr = runt.snap.nodesByPropValu(prop.full, '=', node.ndef[1], norm=norm)
2198
2202
 
2199
- # TODO cache/bypass normalization in loop!
2200
2203
  async for pivo in ngenr:
2201
2204
  yield pivo
2202
2205
 
@@ -2206,7 +2209,7 @@ class FormPivot(PivotOper):
2206
2209
  full = prop.name + ':n1'
2207
2210
 
2208
2211
  async def pgenr(node, strict=True):
2209
- async for pivo in runt.snap.nodesByPropValu(full, '=', node.ndef):
2212
+ async for pivo in runt.snap.nodesByPropValu(full, '=', node.ndef, norm=False):
2210
2213
  yield pivo
2211
2214
 
2212
2215
  else:
@@ -2251,7 +2254,7 @@ class FormPivot(PivotOper):
2251
2254
 
2252
2255
  refsvalu = node.get(refsname)
2253
2256
  if refsvalu is not None:
2254
- async for pivo in runt.snap.nodesByPropValu(refsform, '=', refsvalu):
2257
+ async for pivo in runt.snap.nodesByPropValu(refsform, '=', refsvalu, norm=False):
2255
2258
  yield pivo
2256
2259
 
2257
2260
  for refsname, refsform in refs.get('array'):
@@ -2264,7 +2267,7 @@ class FormPivot(PivotOper):
2264
2267
  refsvalu = node.get(refsname)
2265
2268
  if refsvalu is not None:
2266
2269
  for refselem in refsvalu:
2267
- async for pivo in runt.snap.nodesByPropValu(destform.name, '=', refselem):
2270
+ async for pivo in runt.snap.nodesByPropValu(destform.name, '=', refselem, norm=False):
2268
2271
  yield pivo
2269
2272
 
2270
2273
  for refsname in refs.get('ndef'):
@@ -2300,7 +2303,7 @@ class FormPivot(PivotOper):
2300
2303
  found = True
2301
2304
 
2302
2305
  refsprop = destform.props.get(refsname)
2303
- async for pivo in runt.snap.nodesByPropValu(refsprop.full, '=', node.ndef[1]):
2306
+ async for pivo in runt.snap.nodesByPropValu(refsprop.full, '=', node.ndef[1], norm=False):
2304
2307
  yield pivo
2305
2308
 
2306
2309
  # "reverse" array references...
@@ -2312,7 +2315,7 @@ class FormPivot(PivotOper):
2312
2315
  found = True
2313
2316
 
2314
2317
  destprop = destform.props.get(refsname)
2315
- async for pivo in runt.snap.nodesByPropArray(destprop.full, '=', node.ndef[1]):
2318
+ async for pivo in runt.snap.nodesByPropArray(destprop.full, '=', node.ndef[1], norm=False):
2316
2319
  yield pivo
2317
2320
 
2318
2321
  # "reverse" ndef references...
@@ -2321,7 +2324,7 @@ class FormPivot(PivotOper):
2321
2324
  found = True
2322
2325
 
2323
2326
  refsprop = destform.props.get(refsname)
2324
- async for pivo in runt.snap.nodesByPropValu(refsprop.full, '=', node.ndef):
2327
+ async for pivo in runt.snap.nodesByPropValu(refsprop.full, '=', node.ndef, norm=False):
2325
2328
  yield pivo
2326
2329
 
2327
2330
  for refsname in refs.get('ndefarray'):
@@ -2329,7 +2332,7 @@ class FormPivot(PivotOper):
2329
2332
  found = True
2330
2333
 
2331
2334
  refsprop = destform.props.get(refsname)
2332
- async for pivo in runt.snap.nodesByPropArray(refsprop.full, '=', node.ndef):
2335
+ async for pivo in runt.snap.nodesByPropArray(refsprop.full, '=', node.ndef, norm=False):
2333
2336
  yield pivo
2334
2337
 
2335
2338
  if strict and not found:
@@ -2433,7 +2436,7 @@ class PropPivotOut(PivotOper):
2433
2436
  continue
2434
2437
 
2435
2438
  for item in valu:
2436
- async for pivo in runt.snap.nodesByPropValu(fname, '=', item):
2439
+ async for pivo in runt.snap.nodesByPropValu(fname, '=', item, norm=False):
2437
2440
  yield pivo, path.fork(pivo)
2438
2441
 
2439
2442
  continue
@@ -2474,8 +2477,6 @@ class PropPivot(PivotOper):
2474
2477
 
2475
2478
  async def pgenr(node, srcprop, valu, strict=True):
2476
2479
 
2477
- # TODO cache/bypass normalization in loop!
2478
-
2479
2480
  # pivoting from an array prop to a non-array prop needs an extra loop
2480
2481
  if srcprop.type.isarray and not prop.type.isarray:
2481
2482
  if isinstance(srcprop.type.arraytype, s_types.Ndef) and prop.isform:
@@ -2487,8 +2488,9 @@ class PropPivot(PivotOper):
2487
2488
  yield pivo
2488
2489
  return
2489
2490
 
2491
+ norm = srcprop.arraytypehash is not prop.typehash
2490
2492
  for arrayval in valu:
2491
- async for pivo in runt.snap.nodesByPropValu(prop.full, '=', arrayval):
2493
+ async for pivo in runt.snap.nodesByPropValu(prop.full, '=', arrayval, norm=norm):
2492
2494
  yield pivo
2493
2495
 
2494
2496
  return
@@ -2506,9 +2508,11 @@ class PropPivot(PivotOper):
2506
2508
  return
2507
2509
 
2508
2510
  if prop.type.isarray and not srcprop.type.isarray:
2509
- genr = runt.snap.nodesByPropArray(prop.full, '=', valu)
2511
+ norm = prop.arraytypehash is not srcprop.typehash
2512
+ genr = runt.snap.nodesByPropArray(prop.full, '=', valu, norm=norm)
2510
2513
  else:
2511
- genr = runt.snap.nodesByPropValu(prop.full, '=', valu)
2514
+ norm = prop.typehash is not srcprop.typehash
2515
+ genr = runt.snap.nodesByPropValu(prop.full, '=', valu, norm=norm)
2512
2516
 
2513
2517
  async for pivo in genr:
2514
2518
  yield pivo
synapse/lib/base.py CHANGED
@@ -178,7 +178,24 @@ class Base:
178
178
  def onfini(self, func):
179
179
  '''
180
180
  Add a function/coroutine/Base to be called on fini().
181
+
182
+ The rules around how to register function/coroutine/Base to be called:
183
+ - Call this method with an instance of Base (this class) if holding
184
+ a reference to a bound method of the instance (such as a fini()
185
+ method) would cause the object to be leaked. This is appropriate
186
+ for ephemeral objects that may be constructed/destroyed multiple
187
+ times over the lifetime of a process.
188
+
189
+ - Call this method with an instance method if you want the object to
190
+ have a lifetime as long as the thing being fini'd.
181
191
  '''
192
+ if self.isfini:
193
+ if isinstance(func, Base):
194
+ s_coro.create_task(func.fini())
195
+ else:
196
+ s_coro.create_task(s_coro.ornot(func))
197
+ return
198
+
182
199
  if isinstance(func, Base):
183
200
  self.tofini.add(func)
184
201
  return
@@ -408,8 +425,6 @@ class Base:
408
425
  for fini in self._fini_funcs:
409
426
  try:
410
427
  await s_coro.ornot(fini)
411
- except asyncio.CancelledError: # pragma: no cover TODO: remove once >= py 3.8 only
412
- raise
413
428
  except Exception:
414
429
  logger.exception(f'{self} - fini function failed: {fini}')
415
430
 
@@ -493,9 +508,8 @@ class Base:
493
508
  def taskDone(task):
494
509
  self._active_tasks.remove(task)
495
510
  try:
496
- if not task.done():
497
- task.result()
498
- except asyncio.CancelledError: # pragma: no cover TODO: remove once >= py 3.8 only
511
+ task.result()
512
+ except asyncio.CancelledError:
499
513
  pass
500
514
  except Exception:
501
515
  logger.exception('Task %s scheduled through Base.schedCoro raised exception', task)
@@ -579,7 +593,7 @@ class Base:
579
593
  loop.add_signal_handler(signal.SIGINT, sigint)
580
594
  loop.add_signal_handler(signal.SIGTERM, sigterm)
581
595
 
582
- async def main(self):
596
+ async def main(self): # pragma: no cover
583
597
  '''
584
598
  Helper function to setup signal handlers for this base as the main object.
585
599
  ( use base.waitfini() to block )
@@ -590,7 +604,7 @@ class Base:
590
604
  await self.addSignalHandlers()
591
605
  return await self.waitfini()
592
606
 
593
- def waiter(self, count, *names):
607
+ def waiter(self, count, *names, timeout=None):
594
608
  '''
595
609
  Construct and return a new Waiter for events on this base.
596
610
 
@@ -615,16 +629,17 @@ class Base:
615
629
  race conditions with this mechanism ;)
616
630
 
617
631
  '''
618
- return Waiter(self, count, *names)
632
+ return Waiter(self, count, *names, timeout=timeout)
619
633
 
620
634
  class Waiter:
621
635
  '''
622
636
  A helper to wait for a given number of events on a Base.
623
637
  '''
624
- def __init__(self, base, count, *names):
638
+ def __init__(self, base, count, *names, timeout=None):
625
639
  self.base = base
626
640
  self.names = names
627
641
  self.count = count
642
+ self.timeout = timeout
628
643
  self.event = asyncio.Event()
629
644
 
630
645
  self.events = []
@@ -656,6 +671,9 @@ class Waiter:
656
671
  doStuff(evnt)
657
672
 
658
673
  '''
674
+ if timeout is None:
675
+ timeout = self.timeout
676
+
659
677
  try:
660
678
 
661
679
  retn = await s_coro.event_wait(self.event, timeout)
@@ -676,6 +694,18 @@ class Waiter:
676
694
  self.base.unlink(self._onWaitEvent)
677
695
  del self.event
678
696
 
697
+ async def __aenter__(self):
698
+ return self
699
+
700
+ async def __aexit__(self, exc, cls, tb):
701
+ if exc is None:
702
+ if await self.wait() is None: # pragma: no cover
703
+ # these lines are 100% covered by the tests but
704
+ # the coverage plugin cannot seem to see them...
705
+ events = ','.join(self.names)
706
+ mesg = f'timeout waiting for {self.count} event(s): {events}'
707
+ raise s_exc.TimeOut(mesg=mesg)
708
+
679
709
  class BaseRef(Base):
680
710
  '''
681
711
  An object for managing multiple Base instances by name.
@@ -777,9 +807,6 @@ async def schedGenr(genr, maxsize=100):
777
807
 
778
808
  await q.put((False, None))
779
809
 
780
- except asyncio.CancelledError: # pragma: no cover TODO: remove once >= py 3.8 only
781
- raise
782
-
783
810
  except Exception:
784
811
  if not base.isfini:
785
812
  await q.put((False, None))