synapse 2.166.0__py311-none-any.whl → 2.168.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 (53) hide show
  1. synapse/axon.py +4 -10
  2. synapse/cortex.py +55 -12
  3. synapse/exc.py +1 -0
  4. synapse/lib/aha.py +4 -1
  5. synapse/lib/base.py +11 -4
  6. synapse/lib/cell.py +11 -2
  7. synapse/lib/hive.py +11 -0
  8. synapse/lib/layer.py +2 -0
  9. synapse/lib/modelrev.py +6 -0
  10. synapse/lib/modules.py +1 -0
  11. synapse/lib/node.py +4 -2
  12. synapse/lib/schemas.py +1 -1
  13. synapse/lib/stormlib/aha.py +385 -20
  14. synapse/lib/stormlib/easyperm.py +8 -0
  15. synapse/lib/stormlib/macro.py +11 -18
  16. synapse/lib/stormlib/stix.py +1 -1
  17. synapse/lib/stormtypes.py +25 -2
  18. synapse/lib/types.py +2 -0
  19. synapse/lib/version.py +2 -2
  20. synapse/lib/view.py +5 -3
  21. synapse/models/base.py +8 -0
  22. synapse/models/files.py +3 -0
  23. synapse/models/planning.py +161 -0
  24. synapse/telepath.py +1 -0
  25. synapse/tests/files/stormpkg/dotstorm/dotstorm.yaml +3 -0
  26. synapse/tests/test_cortex.py +40 -3
  27. synapse/tests/test_lib_aha.py +8 -4
  28. synapse/tests/test_lib_cell.py +6 -2
  29. synapse/tests/test_lib_grammar.py +62 -64
  30. synapse/tests/test_lib_httpapi.py +1 -1
  31. synapse/tests/test_lib_rstorm.py +4 -4
  32. synapse/tests/test_lib_storm.py +3 -3
  33. synapse/tests/test_lib_stormlib_aha.py +196 -0
  34. synapse/tests/test_lib_stormlib_compression.py +12 -12
  35. synapse/tests/test_lib_stormlib_macro.py +94 -0
  36. synapse/tests/test_lib_stormlib_spooled.py +1 -1
  37. synapse/tests/test_lib_stormtypes.py +44 -33
  38. synapse/tests/test_lib_trigger.py +3 -3
  39. synapse/tests/test_lib_view.py +50 -3
  40. synapse/tests/test_model_files.py +3 -0
  41. synapse/tests/test_model_planning.py +126 -0
  42. synapse/tests/test_tools_genpkg.py +26 -0
  43. synapse/tests/test_tools_hiveload.py +1 -0
  44. synapse/tests/test_tools_hivesave.py +1 -0
  45. synapse/tests/utils.py +22 -3
  46. synapse/tools/autodoc.py +1 -1
  47. synapse/tools/hive/load.py +3 -0
  48. synapse/tools/hive/save.py +3 -0
  49. {synapse-2.166.0.dist-info → synapse-2.168.0.dist-info}/METADATA +3 -3
  50. {synapse-2.166.0.dist-info → synapse-2.168.0.dist-info}/RECORD +53 -50
  51. {synapse-2.166.0.dist-info → synapse-2.168.0.dist-info}/LICENSE +0 -0
  52. {synapse-2.166.0.dist-info → synapse-2.168.0.dist-info}/WHEEL +0 -0
  53. {synapse-2.166.0.dist-info → synapse-2.168.0.dist-info}/top_level.txt +0 -0
synapse/lib/view.py CHANGED
@@ -55,6 +55,7 @@ class ViewApi(s_cell.CellApi):
55
55
  layr = self.view.layers[0]
56
56
  async for item in layr.syncNodeEdits2(offs, wait=wait):
57
57
  yield item
58
+ await asyncio.sleep(0)
58
59
 
59
60
  @s_cell.adminapi()
60
61
  async def saveNodeEdits(self, edits, meta):
@@ -1098,7 +1099,8 @@ class View(s_nexus.Pusher): # type: ignore
1098
1099
  '''
1099
1100
  Set a mutable view property.
1100
1101
  '''
1101
- if name not in ('name', 'desc', 'parent', 'nomerge', 'quorum'):
1102
+ if name not in ('name', 'desc', 'parent', 'nomerge', 'protected', 'quorum'):
1103
+ # TODO: Remove nomerge after Synapse 3.x.x
1102
1104
  mesg = f'{name} is not a valid view info key'
1103
1105
  raise s_exc.BadOptValu(mesg=mesg)
1104
1106
 
@@ -1346,8 +1348,8 @@ class View(s_nexus.Pusher): # type: ignore
1346
1348
  if self.parent is None:
1347
1349
  raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has not been forked.')
1348
1350
 
1349
- if self.info.get('nomerge'):
1350
- raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has nomerge set.')
1351
+ if self.info.get('protected'):
1352
+ raise s_exc.CantMergeView(mesg=f'Cannot merge view ({self.iden}) that has protected set.')
1351
1353
 
1352
1354
  if self.parent.info.get('quorum') is not None:
1353
1355
  raise s_exc.CantMergeView(mesg=f'Cannot merge view({self.iden}). Parent view requires quorum voting.')
synapse/models/base.py CHANGED
@@ -63,28 +63,36 @@ class BaseModule(s_module.CoreModule):
63
63
  'doc': 'A generic rule linked to matches with -(matches)> edges.'}),
64
64
 
65
65
  ('graph:cluster', ('guid', {}), {
66
+ 'deprecated': True,
66
67
  'doc': 'A generic node, used in conjunction with Edge types, to cluster arbitrary nodes to a '
67
68
  'single node in the model.'}),
68
69
 
69
70
  ('graph:node', ('guid', {}), {
71
+ 'deprecated': True,
70
72
  'doc': 'A generic node used to represent objects outside the model.'}),
71
73
 
72
74
  ('graph:event', ('guid', {}), {
75
+ 'deprecated': True,
73
76
  'doc': 'A generic event node to represent events outside the model.'}),
74
77
 
75
78
  ('edge:refs', ('edge', {}), {
79
+ 'deprecated': True,
76
80
  'doc': 'A digraph edge which records that N1 refers to or contains N2.'}),
77
81
 
78
82
  ('edge:has', ('edge', {}), {
83
+ 'deprecated': True,
79
84
  'doc': 'A digraph edge which records that N1 has N2.'}),
80
85
 
81
86
  ('edge:wentto', ('timeedge', {}), {
87
+ 'deprecated': True,
82
88
  'doc': 'A digraph edge which records that N1 went to N2 at a specific time.'}),
83
89
 
84
90
  ('graph:edge', ('edge', {}), {
91
+ 'deprecated': True,
85
92
  'doc': 'A generic digraph edge to show relationships outside the model.'}),
86
93
 
87
94
  ('graph:timeedge', ('timeedge', {}), {
95
+ 'deprecated': True,
88
96
  'doc': 'A generic digraph time edge to show relationships outside the model.'}),
89
97
 
90
98
  ('meta:priority', ('int', {'enums': prioenums, 'enums:strict': False}), {
synapse/models/files.py CHANGED
@@ -65,6 +65,9 @@ class FilePath(s_types.Str):
65
65
 
66
66
  path.append(part)
67
67
 
68
+ if len(path) == 0:
69
+ return '', {}
70
+
68
71
  fullpath = lead + '/'.join(path)
69
72
 
70
73
  base = path[-1]
@@ -0,0 +1,161 @@
1
+ import synapse.lib.module as s_module
2
+
3
+ class PlanModule(s_module.CoreModule):
4
+
5
+ def getModelDefs(self):
6
+ return (('plan', {
7
+ 'types': (
8
+ ('plan:system', ('guid', {}), {
9
+ 'doc': 'A planning or behavioral analysis system that defines phases and procedures.'}),
10
+
11
+ ('plan:phase', ('guid', {}), {
12
+ 'doc': 'A phase within a planning system which may be used to group steps within a procedure.'}),
13
+
14
+ ('plan:procedure', ('guid', {}), {
15
+ 'doc': 'A procedure consisting of steps.'}),
16
+
17
+ ('plan:procedure:type:taxonomy', ('taxonomy', {}), {
18
+ 'interfaces': ('meta:taxonomy',),
19
+ 'doc': 'A taxonomy of procedure types.'}),
20
+
21
+ ('plan:procedure:variable', ('guid', {}), {
22
+ 'doc': 'A variable used by a procedure.'}),
23
+
24
+ ('plan:procedure:step', ('guid', {}), {
25
+ 'doc': 'A step within a procedure.'}),
26
+
27
+ ('plan:procedure:link', ('guid', {}), {
28
+ 'doc': 'A link between steps in a procedure.'}),
29
+ ),
30
+
31
+ 'forms': (
32
+ ('plan:system', {}, (
33
+
34
+ ('name', ('str', {'lower': True, 'onespace': True}), {
35
+ 'ex': 'mitre att&ck flow',
36
+ 'doc': 'The name of the planning system.'}),
37
+
38
+ ('summary', ('str', {}), {
39
+ 'disp': {'hint': 'text'},
40
+ 'doc': 'A summary of the purpose and use case for the planning system.'}),
41
+
42
+ ('author', ('ps:contact', {}), {
43
+ 'doc': 'The contact of the person or organization which authored the system.'}),
44
+
45
+ ('created', ('time', {}), {
46
+ 'doc': 'The time the planning system was first created.'}),
47
+
48
+ ('updated', ('time', {}), {
49
+ 'doc': 'The time the planning system was last updated.'}),
50
+
51
+ ('version', ('it:semver', {}), {
52
+ 'doc': 'The version of the planning system.'}),
53
+
54
+ ('url', ('inet:url', {}), {
55
+ 'doc': 'The primary URL which documents the planning system.'}),
56
+ )),
57
+ ('plan:phase', {}, (
58
+ ('title', ('str', {}), {
59
+ 'ex': 'Reconnaissance Phase',
60
+ 'doc': 'The title of the phase.'}),
61
+
62
+ ('summary', ('str', {}), {
63
+ 'disp': {'hint': 'text'},
64
+ 'doc': 'A summary of the definition of the phase.'}),
65
+
66
+ ('index', ('int', {}), {
67
+ 'doc': 'The index of this phase within the phases of the system.'}),
68
+
69
+ ('url', ('inet:url', {}), {
70
+ 'doc': 'A URL which links to the full documentation about the phase.'}),
71
+
72
+ ('system', ('plan:system', {}), {
73
+ 'doc': 'The planning system which defines this phase.'}),
74
+ )),
75
+ ('plan:procedure:type:taxonomy', {}, ()),
76
+ ('plan:procedure', {}, (
77
+
78
+ ('title', ('str', {}), {
79
+ 'ex': 'Network Reconnaissance Procedure',
80
+ 'doc': 'The name of the procedure.'}),
81
+
82
+ ('summary', ('str', {}), {
83
+ 'disp': {'hint': 'text'},
84
+ 'doc': 'A summary of the purpose and use cases for the procedure.'}),
85
+
86
+ ('author', ('ps:contact', {}), {
87
+ 'doc': 'The contact of the person or organization which authored the procedure.'}),
88
+
89
+ ('created', ('time', {}), {
90
+ 'doc': 'The time the procedure was created.'}),
91
+
92
+ ('updated', ('time', {}), {
93
+ 'doc': 'The time the procedure was last updated.'}),
94
+
95
+ ('version', ('it:semver', {}), {
96
+ 'doc': 'The version of the procedure.'}),
97
+
98
+ ('system', ('plan:system', {}), {
99
+ 'doc': 'The planning system which defines this procedure.'}),
100
+
101
+ ('type', ('plan:procedure:type:taxonomy', {}), {
102
+ 'doc': 'A type classification for the procedure.'}),
103
+
104
+ ('inputs', ('array', {'type': 'plan:procedure:variable', 'uniq': True, 'sorted': True}), {
105
+ 'doc': 'An array of inputs required to execute the procedure.'}),
106
+
107
+ ('firststep', ('plan:procedure:step', {}), {
108
+ 'doc': 'The first step in the procedure.'}),
109
+ )),
110
+ ('plan:procedure:variable', {}, (
111
+
112
+ ('name', ('str', {}), {
113
+ 'doc': 'The name of the variable.'}),
114
+
115
+ ('type', ('str', {}), {
116
+ 'doc': 'The type for the input. Types are specific to the planning system.'}),
117
+
118
+ ('default', ('data', {}), {
119
+ 'doc': 'The optional default value if the procedure is invoked without the input.'}),
120
+
121
+ ('procedure', ('plan:procedure', {}), {
122
+ 'doc': 'The procedure which defines the variable.'}),
123
+ )),
124
+ ('plan:procedure:step', {}, (
125
+
126
+ ('phase', ('plan:phase', {}), {
127
+ 'doc': 'The phase that the step belongs within.'}),
128
+
129
+ ('procedure', ('plan:procedure', {}), {
130
+ 'doc': 'The procedure which defines the step.'}),
131
+
132
+ ('title', ('str', {}), {
133
+ 'ex': 'Scan the IPv4 address range for open ports',
134
+ 'doc': 'The title of the step.'}),
135
+
136
+ ('summary', ('str', {}), {
137
+ 'doc': 'A summary of the tasks executed within the step.'}),
138
+
139
+ ('outputs', ('array', {'type': 'plan:procedure:variable', 'uniq': True, 'sorted': True}), {
140
+ 'doc': 'An array of variables defined in this step.'}),
141
+
142
+ ('techniques', ('array', {'type': 'ou:technique', 'uniq': True, 'sorted': True}), {
143
+ 'doc': 'An array of techniques used when executing this step.'}),
144
+
145
+ ('links', ('array', {'type': 'plan:procedure:link', 'uniq': True}), {
146
+ 'doc': 'An array of links to subsequent steps.'}),
147
+
148
+ )),
149
+ ('plan:procedure:link', {}, (
150
+
151
+ ('condition', ('bool', {}), {
152
+ 'doc': 'Set to true/false if this link is conditional based on a decision step.'}),
153
+
154
+ ('next', ('plan:procedure:step', {}), {
155
+ 'doc': 'The next step in the plan.'}),
156
+
157
+ ('procedure', ('plan:procedure', {}), {
158
+ 'doc': 'The procedure which defines the link.'}),
159
+ )),
160
+ ),
161
+ }),)
synapse/telepath.py CHANGED
@@ -500,6 +500,7 @@ class GenrMethod(Method):
500
500
  class Pipeline(s_base.Base):
501
501
 
502
502
  async def __anit__(self, proxy, genr, name=None):
503
+ s_common.deprecated('Telepath.Pipeline', curv='2.167.0')
503
504
 
504
505
  await s_base.Base.__anit__(self)
505
506
 
@@ -9,3 +9,6 @@ modules:
9
9
 
10
10
  commands:
11
11
  - name: dotstorm.bar
12
+
13
+ onload: |
14
+ $lib.time.sleep(0)
@@ -6337,7 +6337,7 @@ class CortexBasicTest(s_t_utils.SynTest):
6337
6337
  async def action():
6338
6338
  await asyncio.sleep(0.1)
6339
6339
  await core.callStorm('return($lib.view.get().fork())')
6340
- await core.callStorm('return($lib.cron.add(query="{graph:node=*}", hourly=30).pack())')
6340
+ await core.callStorm('return($lib.cron.add(query="{meta:note=*}", hourly=30).pack())')
6341
6341
  tdef = {'cond': 'node:add', 'storm': '[test:str="foobar"]', 'form': 'test:int'}
6342
6342
  opts = {'vars': {'tdef': tdef}}
6343
6343
  trig = await core.callStorm('return($lib.trigger.add($tdef))', opts=opts)
@@ -7007,7 +7007,7 @@ class CortexBasicTest(s_t_utils.SynTest):
7007
7007
  # clear out the #cno.cve tags and test prune behavior.
7008
7008
  await core.nodes('#cno.cve [ -#cno.cve ]')
7009
7009
 
7010
- await core.nodes('[ inet:ipv4=1.2.3.4 +#cno.cve.2021.12345.foo +#cno.cve.2021.55555 ]')
7010
+ await core.nodes('[ inet:ipv4=1.2.3.4 +#cno.cve.2021.12345.foo +#cno.cve.2021.55555.bar ]')
7011
7011
 
7012
7012
  await core.nodes('$lib.model.tags.set(cno.cve, prune, (2))')
7013
7013
 
@@ -7015,6 +7015,10 @@ class CortexBasicTest(s_t_utils.SynTest):
7015
7015
  nodes = await core.nodes('[ inet:ipv4=1.2.3.4 -#cno.cve.2021.55555 ]')
7016
7016
  self.sorteq(('cno', 'cno.cve', 'cno.cve.2021', 'cno.cve.2021.12345', 'cno.cve.2021.12345.foo'), [t[0] for t in nodes[0].getTags()])
7017
7017
 
7018
+ # double delete shouldn't prune
7019
+ nodes = await core.nodes('[ inet:ipv4=1.2.3.4 -#cno.cve.2021.55555 ]')
7020
+ self.sorteq(('cno', 'cno.cve', 'cno.cve.2021', 'cno.cve.2021.12345', 'cno.cve.2021.12345.foo'), [t[0] for t in nodes[0].getTags()])
7021
+
7018
7022
  # test that the pruning behavior stops at the correct level
7019
7023
  nodes = await core.nodes('[ inet:ipv4=1.2.3.4 -#cno.cve.2021.12345.foo ]')
7020
7024
  self.sorteq(('cno', 'cno.cve', 'cno.cve.2021', 'cno.cve.2021.12345'), [t[0] for t in nodes[0].getTags()])
@@ -7954,7 +7958,7 @@ class CortexBasicTest(s_t_utils.SynTest):
7954
7958
  waiter = core01.stormpool.waiter(1, 'svc:del')
7955
7959
  msgs = await core01.stormlist('aha.pool.svc.del pool00... 01.core...', opts={'mirror': False})
7956
7960
  self.stormHasNoWarnErr(msgs)
7957
- self.stormIsInPrint('AHA service (01.core...) removed from service pool (pool00.loop.vertex.link)', msgs)
7961
+ self.stormIsInPrint('AHA service (01.core.loop.vertex.link) removed from service pool (pool00.loop.vertex.link)', msgs)
7958
7962
 
7959
7963
  # TODO: this wait should not return None
7960
7964
  await waiter.wait(timeout=3)
@@ -8018,3 +8022,36 @@ class CortexBasicTest(s_t_utils.SynTest):
8018
8022
  buf = stream.read()
8019
8023
  self.isin('(lowuser) has a rule on the "cortex" authgate', buf)
8020
8024
  self.isin('(all) has a rule on the "cortex" authgate', buf)
8025
+
8026
+ async def test_cortex_check_nexus_init(self):
8027
+ # This test is a simple safety net for making sure no nexus events
8028
+ # happen before the nexus subsystem is initialized (initNexusSubsystem).
8029
+ # It's possible for code which calls nexus APIs to run but not do
8030
+ # anything which wouldn't be caught here. I don't think there's a good
8031
+ # way to check for that condition though.
8032
+
8033
+ class Cortex(s_cortex.Cortex):
8034
+ async def initServiceStorage(self):
8035
+ self._test_pre_service_storage_index = await self.nexsroot.index()
8036
+ ret = await super().initServiceStorage()
8037
+ self._test_post_service_storage_index = await self.nexsroot.index()
8038
+ return ret
8039
+
8040
+ async def initNexusSubsystem(self):
8041
+ self._test_pre_nexus_index = await self.nexsroot.index()
8042
+ ret = await super().initNexusSubsystem()
8043
+ self._test_post_nexus_index = await self.nexsroot.index()
8044
+ return ret
8045
+
8046
+ conf = {
8047
+ 'layer:lmdb:map_async': True,
8048
+ 'nexslog:en': True,
8049
+ 'layers:logedits': True,
8050
+ }
8051
+
8052
+ with self.getTestDir() as dirn:
8053
+ async with await Cortex.anit(dirn, conf=conf) as core:
8054
+ offs = core._test_pre_service_storage_index
8055
+ self.eq(core._test_post_service_storage_index, offs)
8056
+ self.eq(core._test_pre_nexus_index, offs)
8057
+ self.ge(core._test_post_nexus_index, core._test_pre_nexus_index)
@@ -6,6 +6,7 @@ from unittest import mock
6
6
  import synapse.exc as s_exc
7
7
  import synapse.axon as s_axon
8
8
  import synapse.common as s_common
9
+ import synapse.cortex as s_cortex
9
10
  import synapse.telepath as s_telepath
10
11
 
11
12
  import synapse.lib.aha as s_aha
@@ -1125,7 +1126,7 @@ class AhaTest(s_test.SynTest):
1125
1126
  ready = svcinfo.get('ready')
1126
1127
  online = svcinfo.get('online')
1127
1128
  self.none(online)
1128
- self.true(ready) # Ready is not cleared upon restart
1129
+ self.false(ready) # Ready is cleared upon restart / setting service down.
1129
1130
 
1130
1131
  n = 3
1131
1132
  if len(stack._exit_callbacks) > 0:
@@ -1146,8 +1147,6 @@ class AhaTest(s_test.SynTest):
1146
1147
 
1147
1148
  async with self.getTestAhaProv() as aha:
1148
1149
 
1149
- import synapse.cortex as s_cortex
1150
-
1151
1150
  async with await s_base.Base.anit() as base:
1152
1151
 
1153
1152
  with self.getTestDir() as dirn:
@@ -1246,7 +1245,12 @@ class AhaTest(s_test.SynTest):
1246
1245
 
1247
1246
  msgs = await core00.stormlist('aha.pool.svc.del pool00... 00...')
1248
1247
  self.stormHasNoWarnErr(msgs)
1249
- self.stormIsInPrint('AHA service (00...) removed from service pool (pool00.loop.vertex.link)', msgs)
1248
+ self.stormIsInPrint('AHA service (00.loop.vertex.link) removed from service pool (pool00.loop.vertex.link)',
1249
+ msgs)
1250
+
1251
+ msgs = await core00.stormlist('aha.pool.svc.del pool00... 00...')
1252
+ self.stormHasNoWarnErr(msgs)
1253
+ self.stormIsInPrint('Did not remove (00...) from the service pool.', msgs)
1250
1254
 
1251
1255
  await waiter.wait(timeout=3)
1252
1256
  run00 = await (await pool.proxy(timeout=3)).getCellRunId()
@@ -7,6 +7,7 @@ import signal
7
7
  import socket
8
8
  import asyncio
9
9
  import tarfile
10
+ import warnings
10
11
  import collections
11
12
  import multiprocessing
12
13
 
@@ -509,8 +510,11 @@ class CellTest(s_t_utils.SynTest):
509
510
 
510
511
  s_common.yamlsave(tree, bootpath)
511
512
 
512
- async with self.getTestCell(s_cell.Cell, dirn=dirn) as cell:
513
- self.eq('haha', await cell.hive.get(('hehe',)))
513
+ with warnings.catch_warnings(record=True) as warns:
514
+ async with self.getTestCell(s_cell.Cell, dirn=dirn) as cell:
515
+ self.eq('haha', await cell.hive.get(('hehe',)))
516
+
517
+ self.isin('Initial hive config from hiveboot.yaml', str(warns[0].message))
514
518
 
515
519
  # test that the file does not load again
516
520
  tree['kids']['redballoons'] = {'value': 99}