synapse 2.164.0__py311-none-any.whl → 2.166.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 (89) hide show
  1. synapse/axon.py +3 -3
  2. synapse/cmds/cortex.py +1 -6
  3. synapse/common.py +7 -1
  4. synapse/cortex.py +145 -192
  5. synapse/datamodel.py +36 -1
  6. synapse/lib/agenda.py +87 -97
  7. synapse/lib/aha.py +51 -0
  8. synapse/lib/ast.py +22 -23
  9. synapse/lib/base.py +0 -6
  10. synapse/lib/boss.py +3 -0
  11. synapse/lib/cell.py +70 -39
  12. synapse/lib/certdir.py +9 -0
  13. synapse/lib/hiveauth.py +65 -12
  14. synapse/lib/httpapi.py +1 -0
  15. synapse/lib/modelrev.py +121 -33
  16. synapse/lib/modules.py +1 -0
  17. synapse/lib/nexus.py +64 -26
  18. synapse/lib/parser.py +2 -0
  19. synapse/lib/schemas.py +14 -0
  20. synapse/lib/snap.py +50 -4
  21. synapse/lib/storm.lark +4 -3
  22. synapse/lib/storm.py +96 -22
  23. synapse/lib/storm_format.py +1 -0
  24. synapse/lib/stormlib/aha.py +7 -1
  25. synapse/lib/stormlib/auth.py +13 -5
  26. synapse/lib/stormlib/cache.py +202 -0
  27. synapse/lib/stormlib/cortex.py +147 -8
  28. synapse/lib/stormlib/gen.py +53 -6
  29. synapse/lib/stormlib/math.py +1 -1
  30. synapse/lib/stormlib/model.py +11 -1
  31. synapse/lib/stormlib/spooled.py +109 -0
  32. synapse/lib/stormlib/vault.py +1 -1
  33. synapse/lib/stormtypes.py +113 -17
  34. synapse/lib/trigger.py +36 -47
  35. synapse/lib/types.py +29 -2
  36. synapse/lib/version.py +2 -2
  37. synapse/lib/view.py +80 -53
  38. synapse/models/economic.py +174 -5
  39. synapse/models/files.py +2 -0
  40. synapse/models/inet.py +77 -2
  41. synapse/models/infotech.py +12 -12
  42. synapse/models/orgs.py +72 -21
  43. synapse/models/person.py +40 -11
  44. synapse/models/risk.py +78 -24
  45. synapse/models/science.py +102 -0
  46. synapse/telepath.py +117 -35
  47. synapse/tests/test_cortex.py +84 -158
  48. synapse/tests/test_datamodel.py +22 -0
  49. synapse/tests/test_lib_agenda.py +52 -96
  50. synapse/tests/test_lib_aha.py +126 -4
  51. synapse/tests/test_lib_ast.py +412 -6
  52. synapse/tests/test_lib_cell.py +24 -8
  53. synapse/tests/test_lib_certdir.py +32 -0
  54. synapse/tests/test_lib_grammar.py +9 -1
  55. synapse/tests/test_lib_httpapi.py +0 -1
  56. synapse/tests/test_lib_jupyter.py +0 -1
  57. synapse/tests/test_lib_modelrev.py +41 -0
  58. synapse/tests/test_lib_nexus.py +38 -0
  59. synapse/tests/test_lib_storm.py +95 -5
  60. synapse/tests/test_lib_stormlib_cache.py +272 -0
  61. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  62. synapse/tests/test_lib_stormlib_gen.py +37 -2
  63. synapse/tests/test_lib_stormlib_model.py +2 -0
  64. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  65. synapse/tests/test_lib_stormlib_vault.py +12 -3
  66. synapse/tests/test_lib_stormsvc.py +0 -10
  67. synapse/tests/test_lib_stormtypes.py +60 -8
  68. synapse/tests/test_lib_trigger.py +20 -2
  69. synapse/tests/test_lib_types.py +17 -1
  70. synapse/tests/test_model_economic.py +114 -0
  71. synapse/tests/test_model_files.py +2 -0
  72. synapse/tests/test_model_inet.py +73 -1
  73. synapse/tests/test_model_infotech.py +2 -2
  74. synapse/tests/test_model_orgs.py +10 -1
  75. synapse/tests/test_model_risk.py +30 -2
  76. synapse/tests/test_model_science.py +59 -0
  77. synapse/tests/test_model_syn.py +0 -1
  78. synapse/tests/test_telepath.py +30 -7
  79. synapse/tests/test_tools_modrole.py +81 -0
  80. synapse/tests/test_tools_moduser.py +105 -0
  81. synapse/tools/modrole.py +59 -7
  82. synapse/tools/moduser.py +78 -10
  83. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
  84. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/RECORD +87 -83
  85. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +1 -1
  86. synapse/lib/provenance.py +0 -111
  87. synapse/tests/test_lib_provenance.py +0 -37
  88. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
  89. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,202 @@
1
+ import asyncio
2
+
3
+ import synapse.exc as s_exc
4
+
5
+ import synapse.lib.ast as s_ast
6
+ import synapse.lib.cache as s_cache
7
+ import synapse.lib.stormctrl as s_stormctrl
8
+ import synapse.lib.stormtypes as s_stormtypes
9
+
10
+ CACHE_SIZE_MAX = 10_000
11
+ CACHE_SIZE_DEFAULT = 10_000
12
+
13
+ @s_stormtypes.registry.registerLib
14
+ class LibCache(s_stormtypes.Lib):
15
+ '''
16
+ A Storm Library for interacting with Cache Objects.
17
+ '''
18
+ _storm_locals = (
19
+ {'name': 'fixed', 'desc': '''
20
+ Get a new Fixed Cache object.
21
+
22
+ On a cache-miss when calling .get(), the callback Storm query is executed in a sub-runtime
23
+ in the current execution context. A special variable, $cache_key, will be set
24
+ to the key argument provided to .get().
25
+
26
+ The callback Storm query must contain a return statement, and if it does not return a value
27
+ when executed with the input, $lib.null will be set as the value.
28
+
29
+ The fixed cache uses FIFO to evict items once the maximum size is reached.
30
+
31
+ Examples:
32
+
33
+ // Use a callback query with a function that modifies the outer runtime,
34
+ // since it will run in the scope where it was defined.
35
+ $test = foo
36
+
37
+ function callback(key) {
38
+ $test = $key // this will modify $test in the outer runtime
39
+ return(`{$key}-val`)
40
+ }
41
+
42
+ $cache = $lib.cache.fixed(${ return($callback($cache_key)) })
43
+ $value = $cache.get(bar)
44
+ $lib.print($test) // this will equal "bar"
45
+
46
+ // Use a callback query that will not modify the outer runtime,
47
+ // except for variables accessible as references.
48
+ $test = foo
49
+ $tests = ([])
50
+
51
+ $cache = $lib.cache.fixed(${
52
+ $test = $cache_key // this will *not* modify $test in the outer runtime
53
+ $tests.append($cache_key) // this will modify $tests in the outer runtime
54
+ return(`{$cache_key}-val`)
55
+ })
56
+
57
+ $value = $cache.get(bar)
58
+ $lib.print($test) // this will equal "foo"
59
+ $lib.print($tests) // this will equal (foo,)
60
+ ''',
61
+ 'type': {'type': 'function', '_funcname': '_methFixedCache',
62
+ 'args': (
63
+ {'name': 'callback', 'type': ['str', 'storm:query'],
64
+ 'desc': 'A Storm query that will return a value for $cache_key on a cache miss.', },
65
+ {'name': 'size', 'type': 'int', 'default': CACHE_SIZE_DEFAULT,
66
+ 'desc': 'The maximum size of the cache.', },
67
+ ),
68
+ 'returns': {'type': 'cache:fixed', 'desc': 'A new ``cache:fixed`` object.'}}},
69
+ )
70
+ _storm_lib_path = ('cache',)
71
+
72
+ def getObjLocals(self):
73
+ return {
74
+ 'fixed': self._methFixedCache,
75
+ }
76
+
77
+ @s_stormtypes.stormfunc(readonly=True)
78
+ async def _methFixedCache(self, callback, size=CACHE_SIZE_DEFAULT):
79
+ size = await s_stormtypes.toint(size)
80
+ callback = await s_stormtypes.tostr(callback)
81
+
82
+ if size < 1 or size > CACHE_SIZE_MAX:
83
+ raise s_exc.BadArg(mesg=f'Cache size must be between 1-{CACHE_SIZE_MAX}')
84
+
85
+ try:
86
+ query = await self.runt.getStormQuery(callback)
87
+ except s_exc.BadSyntax as e:
88
+ raise s_exc.BadArg(mesg=f'Invalid callback query: {e.errinfo.get("mesg")}')
89
+
90
+ if not query.hasAstClass(s_ast.Return):
91
+ raise s_exc.BadArg(mesg='Callback query must return a value')
92
+
93
+ return FixedCache(self.runt, query, size=size)
94
+
95
+ @s_stormtypes.registry.registerType
96
+ class FixedCache(s_stormtypes.StormType):
97
+ '''
98
+ A StormLib API instance of a Storm Fixed Cache.
99
+ '''
100
+ _storm_locals = (
101
+ {'name': 'query', 'desc': 'Get the callback Storm query as string.',
102
+ 'type': {'type': 'gtor', '_gtorfunc': '_gtorQuery',
103
+ 'returns': {'type': 'str', 'desc': 'The callback Storm query text.', }}},
104
+ {'name': 'get', 'desc': 'Get an item from the cache by key.',
105
+ 'type': {'type': 'function', '_funcname': '_methGet',
106
+ 'args': (
107
+ {'name': 'key', 'type': 'any', 'desc': 'The key to lookup.'},
108
+ ),
109
+ 'returns': {'type': 'any',
110
+ 'desc': 'The value from the cache, or the callback query if it does not exist', }}},
111
+ {'name': 'pop', 'desc': 'Pop an item from the cache.',
112
+ 'type': {'type': 'function', '_funcname': '_methPop',
113
+ 'args': (
114
+ {'name': 'key', 'type': 'any', 'desc': 'The key to pop.'},
115
+ ),
116
+ 'returns': {'type': 'any',
117
+ 'desc': 'The value from the cache, or $lib.null if it does not exist', }}},
118
+ {'name': 'put', 'desc': 'Put an item into the cache.',
119
+ 'type': {'type': 'function', '_funcname': '_methPut',
120
+ 'args': (
121
+ {'name': 'key', 'type': 'any', 'desc': 'The key put in the cache.'},
122
+ {'name': 'value', 'type': 'any', 'desc': 'The value to assign to the key.'},
123
+ ),
124
+ 'returns': {'type': 'null', }}},
125
+ {'name': 'clear', 'desc': 'Clear all items from the cache.',
126
+ 'type': {'type': 'function', '_funcname': '_methClear',
127
+ 'returns': {'type': 'null', }}},
128
+ )
129
+ _storm_typename = 'cache:fixed'
130
+ _ismutable = False
131
+
132
+ def __init__(self, runt, query, size=CACHE_SIZE_DEFAULT):
133
+ s_stormtypes.StormType.__init__(self)
134
+ self.runt = runt
135
+ self.size = size
136
+ self.query = query
137
+ self.locls.update(self.getObjLocals())
138
+ self.gtors.update({
139
+ 'query': self._gtorQuery,
140
+ })
141
+
142
+ self.cache = s_cache.FixedCache(self._runCallback, size=size)
143
+
144
+ def __len__(self):
145
+ return len(self.cache)
146
+
147
+ async def stormrepr(self):
148
+ if len(qtext := self.query.text) > 100:
149
+ qtext = qtext[:100] + '...'
150
+ return f'{self._storm_typename}: size={self.size} query="{qtext}"'
151
+
152
+ def getObjLocals(self):
153
+ return {
154
+ 'pop': self._methPop,
155
+ 'put': self._methPut,
156
+ 'get': self._methGet,
157
+ 'clear': self._methClear,
158
+ }
159
+
160
+ async def _gtorQuery(self):
161
+ return self.query.text
162
+
163
+ async def _runCallback(self, key):
164
+
165
+ varz = self.runt.getScopeVars()
166
+ varz['cache_key'] = key
167
+
168
+ opts = {'vars': varz}
169
+ async with self.runt.getCmdRuntime(self.query, opts=opts) as runt:
170
+ try:
171
+ async for _ in runt.execute():
172
+ await asyncio.sleep(0)
173
+ except s_stormctrl.StormReturn as e:
174
+ return await s_stormtypes.toprim(e.item)
175
+ except s_stormctrl.StormCtrlFlow:
176
+ pass
177
+
178
+ async def _reqKey(self, key):
179
+ if s_stormtypes.ismutable(key):
180
+ mesg = 'Mutable values are not allowed as cache keys'
181
+ raise s_exc.BadArg(mesg=mesg, name=await s_stormtypes.torepr(key))
182
+ return await s_stormtypes.toprim(key)
183
+
184
+ @s_stormtypes.stormfunc(readonly=True)
185
+ async def _methPop(self, key):
186
+ key = await self._reqKey(key)
187
+ return self.cache.pop(key)
188
+
189
+ @s_stormtypes.stormfunc(readonly=True)
190
+ async def _methPut(self, key, value):
191
+ key = await self._reqKey(key)
192
+ val = await s_stormtypes.toprim(value)
193
+ self.cache.put(key, val)
194
+
195
+ @s_stormtypes.stormfunc(readonly=True)
196
+ async def _methGet(self, key):
197
+ key = await self._reqKey(key)
198
+ return await self.cache.aget(key)
199
+
200
+ @s_stormtypes.stormfunc(readonly=True)
201
+ async def _methClear(self):
202
+ self.cache.clear()
@@ -3,7 +3,9 @@ import json
3
3
  import logging
4
4
 
5
5
  import synapse.exc as s_exc
6
+ import synapse.telepath as s_telepath
6
7
 
8
+ import synapse.lib.storm as s_storm
7
9
  import synapse.lib.stormtypes as s_stormtypes
8
10
  import synapse.lib.stormlib.auth as slib_auth
9
11
 
@@ -85,6 +87,7 @@ stormcmds = [
85
87
  $lib.print(`!View: No view found ({$err.info.iden})`)
86
88
  }
87
89
  $lib.print(`Readonly: {$api.readonly}`)
90
+ $lib.print(`Pool enabled: {$api.pool}`)
88
91
  $lib.print(`Authenticated: {$api.authenticated}`)
89
92
  $lib.print(`Name: {$api.name}`)
90
93
  $lib.print(`Description: {$api.desc}`)
@@ -223,6 +226,9 @@ class HttpApi(s_stormtypes.StormType):
223
226
  ''',
224
227
  'type': {'type': ['stor', 'gtor'], '_storfunc': '_storPath', '_gtorfunc': '_gtorPath',
225
228
  'returns': {'type': 'str'}}},
229
+ {'name': 'pool', 'desc': 'Boolean value indicating if the handler responses may be executed as part of a Storm pool.',
230
+ 'type': {'type': ['stor', 'gtor'], '_storfunc': '_storPool', '_gtorfunc': '_gtorPool',
231
+ 'returns': {'type': 'boolean'}}},
226
232
  {'name': 'vars', 'desc': 'The Storm runtime variables specific for the API instance.',
227
233
  'type': {'type': ['stor', 'ctor'], '_storfunc': '_storVars', '_ctorfunc': '_ctorVars',
228
234
  'returns': {'type': 'http:api:vars'}}},
@@ -241,6 +247,8 @@ class HttpApi(s_stormtypes.StormType):
241
247
  {'name': 'authenticated', 'desc': 'Boolean value indicating if the Extended HTTP API requires an authenticated user or session.',
242
248
  'type': {'type': ['stor', 'gtor'], '_storfunc': '_storAuthenticated', '_gtorfunc': '_gtorAuthenticated',
243
249
  'returns': {'type': 'boolean'}}},
250
+ {'name': 'methods', 'desc': 'The dictionary containing the Storm code used to implement the HTTP methods.',
251
+ 'type': {'type': ['ctor'], '_ctorfunc': '_ctorMethods', 'returns': {'type': 'http:api:methods'}}}
244
252
  )
245
253
 
246
254
  def __init__(self, runt, info):
@@ -256,6 +264,7 @@ class HttpApi(s_stormtypes.StormType):
256
264
  'name': self._storName,
257
265
  'desc': self._storDesc,
258
266
  'path': self._storPath,
267
+ 'pool': self._storPool,
259
268
  'vars': self._storVars,
260
269
  'view': self._storView,
261
270
  'runas': self._storRunas,
@@ -269,6 +278,7 @@ class HttpApi(s_stormtypes.StormType):
269
278
  'name': self._gtorName,
270
279
  'desc': self._gtorDesc,
271
280
  'path': self._gtorPath,
281
+ 'pool': self._gtorPool,
272
282
  'view': self._gtorView,
273
283
  'runas': self._gtorRunas,
274
284
  'owner': self._gtorOwner,
@@ -291,6 +301,13 @@ class HttpApi(s_stormtypes.StormType):
291
301
  'created': self.info.get('created'),
292
302
  })
293
303
 
304
+ async def stormrepr(self):
305
+ name = await self._gtorName()
306
+ if not name:
307
+ name = '<no name>'
308
+ path = await self._gtorPath()
309
+ return f'{self._storm_typename}: {name} ({self.iden}), path={path}'
310
+
294
311
  def getObjLocals(self):
295
312
  return {
296
313
  'pack': self._methPack,
@@ -298,7 +315,10 @@ class HttpApi(s_stormtypes.StormType):
298
315
 
299
316
  @s_stormtypes.stormfunc(readonly=True)
300
317
  async def _methPack(self):
301
- return copy.deepcopy(self.info)
318
+ # TODO: Remove this when we've migrated the HTTPAPI data to set this value.
319
+ ret = copy.deepcopy(self.info)
320
+ ret.setdefault('pool', False)
321
+ return ret
302
322
 
303
323
  @s_stormtypes.stormfunc(readonly=True)
304
324
  def _ctorMethods(self, path=None):
@@ -315,6 +335,17 @@ class HttpApi(s_stormtypes.StormType):
315
335
  async def _gtorPath(self):
316
336
  return self.info.get('path')
317
337
 
338
+ async def _storPool(self, pool):
339
+ s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'set'))
340
+ pool = await s_stormtypes.tobool(pool)
341
+ adef = await self.runt.snap.core.modHttpExtApi(self.iden, 'pool', pool)
342
+ self.info['pool'] = pool
343
+ self.info['updated'] = adef.get('updated')
344
+
345
+ @s_stormtypes.stormfunc(readonly=True)
346
+ async def _gtorPool(self):
347
+ return self.info.get('pool')
348
+
318
349
  async def _storName(self, name):
319
350
  s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'set'))
320
351
  name = await s_stormtypes.tostr(name)
@@ -452,7 +483,7 @@ class HttpApi(s_stormtypes.StormType):
452
483
  @s_stormtypes.registry.registerType
453
484
  class HttpApiMethods(s_stormtypes.Prim):
454
485
  '''
455
- Accessor dictionary for getting and setting Extened HTTP API methods.
486
+ Accessor dictionary for getting and setting Extended HTTP API methods.
456
487
 
457
488
  Notes:
458
489
  The Storm code used to run these methods will have a $request object
@@ -1054,7 +1085,7 @@ class CortexHttpApi(s_stormtypes.Lib):
1054
1085
  {'name': 'readonly', 'type': 'boolean',
1055
1086
  'desc': 'Run the Extended HTTP Storm methods in readonly mode.', 'default': False},
1056
1087
  ),
1057
- 'returns': {'type': 'http:api', 'desc': 'A new http:api object.'}}},
1088
+ 'returns': {'type': 'http:api', 'desc': 'A new ``http:api`` object.'}}},
1058
1089
  {'name': 'del', 'desc': 'Delete an Extended HTTP API endpoint.',
1059
1090
  'type': {'type': 'function', '_funcname': 'delHttpApi',
1060
1091
  'args': (
@@ -1062,16 +1093,29 @@ class CortexHttpApi(s_stormtypes.Lib):
1062
1093
  'desc': 'The iden of the API to delete.'},
1063
1094
  ),
1064
1095
  'returns': {'type': 'null'}}},
1065
- {'name': 'get', 'desc': 'Get an Extended HTTP API object.',
1096
+ {'name': 'get', 'desc': 'Get an Extended ``http:api`` object.',
1066
1097
  'type': {'type': 'function', '_funcname': 'getHttpApi',
1067
1098
  'args': (
1068
1099
  {'name': 'iden', 'type': 'string',
1069
- 'desc': 'The iden of the API to retreive.'},
1100
+ 'desc': 'The iden of the API to retrieve.'},
1101
+ ),
1102
+ 'returns': {'type': 'http:api', 'desc': 'The ``http:api`` object.'}}},
1103
+ {'name': 'getByPath', 'desc': '''
1104
+ Get an Extended ``http:api`` object by path.
1105
+
1106
+ Notes:
1107
+ The path argument is evaluated as a regular expression input, and will be
1108
+ used to get the first HTTP API handler whose path value has a match.
1109
+ ''',
1110
+ 'type': {'type': 'function', '_funcname': 'getHttpApiByPath',
1111
+ 'args': (
1112
+ {'name': 'path', 'type': 'string',
1113
+ 'desc': 'Path to use to retrieve an object.'},
1070
1114
  ),
1071
- 'returns': {'type': 'http:api', 'desc': 'The http:api object.'}}},
1072
- {'name': 'list', 'desc': 'Get all the Extneded HTTP APIs on the Cortex',
1115
+ 'returns': {'type': ['http:api', 'null'], 'desc': 'The ``http:api`` object or ``$lib.null`` if there is no match.'}}},
1116
+ {'name': 'list', 'desc': 'Get all the Extended HTTP APIs on the Cortex',
1073
1117
  'type': {'type': 'function', '_funcname': 'listHttpApis', 'args': (),
1074
- 'returns': {'type': 'list', 'desc': 'A list of http:api objects'}}},
1118
+ 'returns': {'type': 'list', 'desc': 'A list of ``http:api`` objects'}}},
1075
1119
  {'name': 'index', 'desc': 'Set the index for a given Extended HTTP API.',
1076
1120
  'type': {'type': 'function', '_funcname': 'setHttpApiIndx',
1077
1121
  'args': (
@@ -1110,6 +1154,7 @@ class CortexHttpApi(s_stormtypes.Lib):
1110
1154
  'list': self.listHttpApis,
1111
1155
  'index': self.setHttpApiIndx,
1112
1156
  'response': self.makeHttpResponse,
1157
+ 'getByPath': self.getHttpApiByPath,
1113
1158
  }
1114
1159
 
1115
1160
  @s_stormtypes.stormfunc(readonly=True)
@@ -1124,6 +1169,15 @@ class CortexHttpApi(s_stormtypes.Lib):
1124
1169
  adef = await self.runt.snap.core.getHttpExtApi(iden)
1125
1170
  return HttpApi(self.runt, adef)
1126
1171
 
1172
+ @s_stormtypes.stormfunc(readonly=True)
1173
+ async def getHttpApiByPath(self, path):
1174
+ s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'get'))
1175
+ path = await s_stormtypes.tostr(path)
1176
+ adef, _ = await self.runt.snap.core.getHttpExtApiByPath(path)
1177
+ if adef is None:
1178
+ return None
1179
+ return HttpApi(self.runt, adef)
1180
+
1127
1181
  @s_stormtypes.stormfunc(readonly=True)
1128
1182
  async def listHttpApis(self):
1129
1183
  s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'get'))
@@ -1167,3 +1221,88 @@ class CortexHttpApi(s_stormtypes.Lib):
1167
1221
  iden = await s_stormtypes.tostr(iden)
1168
1222
  index = await s_stormtypes.toint(index)
1169
1223
  return await self.runt.snap.view.core.setHttpApiIndx(iden, index)
1224
+
1225
+ class StormPoolSetCmd(s_storm.Cmd):
1226
+ '''
1227
+ Setup a Storm query offload mirror pool for the Cortex.
1228
+ '''
1229
+ name = 'cortex.storm.pool.set'
1230
+ def getArgParser(self):
1231
+ pars = s_storm.Cmd.getArgParser(self)
1232
+ pars.add_argument('--connection-timeout', type='int', default=2,
1233
+ help='The maximum amount of time to wait for a connection from the pool to become available.')
1234
+ pars.add_argument('--sync-timeout', type='int', default=2,
1235
+ help='The maximum amount of time to wait for the mirror to be in sync with the leader')
1236
+ pars.add_argument('url', type='str', required=True, help='The telepath URL for the AHA service pool.')
1237
+ return pars
1238
+
1239
+ async def execStormCmd(self, runt, genr):
1240
+
1241
+ if not self.runtsafe: # pragma: no cover
1242
+ mesg = 'cortex.storm.pool.set arguments must be runtsafe.'
1243
+ raise s_exc.StormRuntimeError(mesg=mesg)
1244
+
1245
+ mesg = 'cortex.storm.pool.set command requires global admin permissions.'
1246
+ self.runt.reqAdmin(mesg=mesg)
1247
+
1248
+ async for node, path in genr: # pragma: no cover
1249
+ yield node, path
1250
+
1251
+ try:
1252
+ s_telepath.chopurl(self.opts.url)
1253
+ except s_exc.BadUrl as e:
1254
+ raise s_exc.BadArg(mesg=f'Unable to set Storm pool URL from url={self.opts.url} : {e.get("mesg")}') from None
1255
+
1256
+ opts = {
1257
+ 'timeout:sync': self.opts.sync_timeout,
1258
+ 'timeout:connection': self.opts.connection_timeout,
1259
+ }
1260
+
1261
+ await self.runt.snap.core.setStormPool(self.opts.url, opts)
1262
+ await self.runt.printf('Storm pool configuration set.')
1263
+
1264
+ class StormPoolDelCmd(s_storm.Cmd):
1265
+ '''
1266
+ Remove a Storm query offload mirror pool configuration.
1267
+
1268
+ Notes:
1269
+ This will result in tearing down any Storm queries currently being serviced by the Storm pool.
1270
+ This may result in this command raising an exception if it was offloaded to a pool member. That would be an expected behavior.
1271
+ '''
1272
+ name = 'cortex.storm.pool.del'
1273
+
1274
+ async def execStormCmd(self, runt, genr):
1275
+
1276
+ mesg = 'cortex.storm.pool.del command requires global admin permissions.'
1277
+ self.runt.reqAdmin(mesg=mesg)
1278
+
1279
+ async for node, path in genr: # pragma: no cover
1280
+ yield node, path
1281
+
1282
+ await self.runt.snap.core.delStormPool()
1283
+ await self.runt.printf('Storm pool configuration removed.')
1284
+
1285
+ class StormPoolGetCmd(s_storm.Cmd):
1286
+ '''
1287
+ Display the current Storm query offload mirror pool configuration.
1288
+ '''
1289
+ name = 'cortex.storm.pool.get'
1290
+
1291
+ async def execStormCmd(self, runt, genr):
1292
+
1293
+ mesg = 'cortex.storm.pool.get command requires global admin permissions.'
1294
+ self.runt.reqAdmin(mesg=mesg)
1295
+
1296
+ async for node, path in genr: # pragma: no cover
1297
+ yield node, path
1298
+
1299
+ item = await self.runt.snap.core.getStormPool()
1300
+ if item is None:
1301
+ await self.runt.printf('No Storm pool configuration found.')
1302
+ return
1303
+
1304
+ url, opts = item
1305
+
1306
+ await self.runt.printf(f'Storm Pool URL: {url}')
1307
+ await self.runt.printf(f'Sync Timeout (secs): {opts.get("timeout:sync")}')
1308
+ await self.runt.printf(f'Connection Timeout (secs): {opts.get("timeout:connection")}')
@@ -46,12 +46,14 @@ class LibGen(s_stormtypes.Lib):
46
46
  {'name': 'name', 'type': 'str', 'desc': 'The name of the software.'},
47
47
  ),
48
48
  'returns': {'type': 'node', 'desc': 'An it:prod:soft node with the given name.'}}},
49
- {'name': 'vulnByCve', 'desc': 'Returns risk:vuln node by CVE, adding the node if it does not exist.',
49
+ {'name': 'vulnByCve', 'desc': 'Returns risk:vuln node by CVE and reporter, adding the node if it does not exist.',
50
50
  'type': {'type': 'function', '_funcname': '_storm_query',
51
51
  'args': (
52
52
  {'name': 'cve', 'type': 'str', 'desc': 'The CVE id.'},
53
53
  {'name': 'try', 'type': 'boolean', 'default': False,
54
54
  'desc': 'Type normalization will fail silently instead of raising an exception.'},
55
+ {'name': 'reporter', 'type': 'str', 'default': None,
56
+ 'desc': 'The name of the organization which reported the vulnerability.'},
55
57
  ),
56
58
  'returns': {'type': 'node', 'desc': 'A risk:vuln node with the given CVE.'}}},
57
59
 
@@ -128,6 +130,12 @@ class LibGen(s_stormtypes.Lib):
128
130
  'desc': 'Type normalization will fail silently instead of raising an exception.'},
129
131
  ),
130
132
  'returns': {'type': 'node', 'desc': 'An it:av:scan:result node.'}}},
133
+ {'name': 'geoPlaceByName', 'desc': 'Returns a geo:place node by name, adding the node if it does not exist.',
134
+ 'type': {'type': 'function', '_funcname': '_storm_query',
135
+ 'args': (
136
+ {'name': 'name', 'type': 'str', 'desc': 'The name of the place.'},
137
+ ),
138
+ 'returns': {'type': 'node', 'desc': 'A geo:place node with the given name.'}}},
131
139
  )
132
140
  _storm_lib_path = ('gen',)
133
141
 
@@ -222,14 +230,27 @@ class LibGen(s_stormtypes.Lib):
222
230
  return($node)
223
231
  }
224
232
 
225
- function vulnByCve(cve, try=$lib.false) {
233
+ function vulnByCve(cve, try=$lib.false, reporter=$lib.null) {
226
234
  ($ok, $cve) = $__maybeCast($try, it:sec:cve, $cve)
227
235
  if (not $ok) { return() }
228
236
 
229
237
  risk:vuln:cve=$cve
238
+ if $reporter {
239
+ +:reporter:name=$reporter
240
+ { -:reporter [ :reporter=$orgByName($reporter) ] }
241
+ }
230
242
  return($node)
231
243
 
232
- [ risk:vuln=(gen, cve, $cve) :cve=$cve ]
244
+ $guid = (gen, cve, $cve)
245
+ if $reporter {
246
+ $reporter = $lib.cast(ou:name, $reporter)
247
+ $guid.append($reporter)
248
+ }
249
+
250
+ [ risk:vuln=$guid :cve=$cve ]
251
+ if $reporter {
252
+ [ :reporter:name=$reporter :reporter=$orgByName($reporter) ]
253
+ }
233
254
  return($node)
234
255
  }
235
256
 
@@ -394,6 +415,16 @@ class LibGen(s_stormtypes.Lib):
394
415
 
395
416
  return($node)
396
417
  }
418
+
419
+ function geoPlaceByName(name) {
420
+ $geoname = $lib.cast(geo:name, $name)
421
+
422
+ geo:name=$geoname -> geo:place
423
+ return($node)
424
+
425
+ [ geo:place=(gen, name, $geoname) :name=$geoname ]
426
+ return($node)
427
+ }
397
428
  '''
398
429
 
399
430
  stormcmds = (
@@ -483,14 +514,20 @@ stormcmds = (
483
514
  {
484
515
  'name': 'gen.risk.vuln',
485
516
  'descr': '''
486
- Lift (or create) a risk:vuln node based on the CVE.
517
+ Lift (or create) a risk:vuln node based on the CVE and reporter name.
518
+
519
+ Examples:
520
+
521
+ // Yield a risk:vuln node for CVE-2012-0157 reported by Mandiant.
522
+ gen.risk.vuln CVE-2012-0157 Mandiant
487
523
  ''',
488
524
  'cmdargs': (
489
525
  ('cve', {'help': 'The CVE identifier.'}),
526
+ ('reporter', {'help': 'The name of the reporting organization.', 'nargs': '?'}),
490
527
  ('--try', {'help': 'Type normalization will fail silently instead of raising an exception.',
491
528
  'action': 'store_true'}),
492
529
  ),
493
- 'storm': 'yield $lib.gen.vulnByCve($cmdopts.cve, try=$cmdopts.try)',
530
+ 'storm': 'yield $lib.gen.vulnByCve($cmdopts.cve, try=$cmdopts.try, reporter=$cmdopts.reporter)',
494
531
  },
495
532
  {
496
533
  'name': 'gen.ou.industry',
@@ -594,5 +631,15 @@ stormcmds = (
594
631
  yield $lib.gen.itAvScanResultByTarget($cmdopts.form, $cmdopts.value, $cmdopts.signame,
595
632
  scanner=$cmdopts.scanner_name, time=$cmdopts.time, try=$cmdopts.try)
596
633
  ''',
597
- }
634
+ },
635
+ {
636
+ 'name': 'gen.geo.place',
637
+ 'descr': '''
638
+ Lift (or create) a geo:place node based on the name.
639
+ ''',
640
+ 'cmdargs': (
641
+ ('name', {'help': 'The name of the place.'}),
642
+ ),
643
+ 'storm': 'yield $lib.gen.geoPlaceByName($cmdopts.name)',
644
+ },
598
645
  )
@@ -10,7 +10,7 @@ class MathLib(s_stormtypes.Lib):
10
10
  'desc': '''
11
11
  Convert a value to a Storm Number object.
12
12
 
13
- Storm Numbers are high precision fixed point decimals corresponding to the
13
+ Storm Numbers are high precision fixed point decimals corresponding to
14
14
  the hugenum storage type.
15
15
 
16
16
  This is not to be used for converting a string to an integer.
@@ -329,6 +329,7 @@ class LibModel(s_stormtypes.Lib):
329
329
  @s_cache.memoizemethod(size=100)
330
330
  @s_stormtypes.stormfunc(readonly=True)
331
331
  async def _methType(self, name):
332
+ name = await s_stormtypes.tostr(name)
332
333
  type_ = self.model.type(name)
333
334
  if type_ is not None:
334
335
  return ModelType(type_)
@@ -336,6 +337,7 @@ class LibModel(s_stormtypes.Lib):
336
337
  @s_cache.memoizemethod(size=100)
337
338
  @s_stormtypes.stormfunc(readonly=True)
338
339
  async def _methProp(self, name):
340
+ name = await s_stormtypes.tostr(name)
339
341
  prop = self.model.prop(name)
340
342
  if prop is not None:
341
343
  return ModelProp(prop)
@@ -343,6 +345,7 @@ class LibModel(s_stormtypes.Lib):
343
345
  @s_cache.memoizemethod(size=100)
344
346
  @s_stormtypes.stormfunc(readonly=True)
345
347
  async def _methForm(self, name):
348
+ name = await s_stormtypes.tostr(name)
346
349
  form = self.model.form(name)
347
350
  if form is not None:
348
351
  return ModelForm(form)
@@ -350,6 +353,7 @@ class LibModel(s_stormtypes.Lib):
350
353
  @s_cache.memoize(size=100)
351
354
  @s_stormtypes.stormfunc(readonly=True)
352
355
  async def _methTagProp(self, name):
356
+ name = await s_stormtypes.tostr(name)
353
357
  tagprop = self.model.getTagProp(name)
354
358
  if tagprop is not None:
355
359
  return ModelTagProp(tagprop)
@@ -394,7 +398,8 @@ class ModelForm(s_stormtypes.Prim):
394
398
  return ModelType(self.valu.type, path=path)
395
399
 
396
400
  @s_stormtypes.stormfunc(readonly=True)
397
- def _getFormProp(self, name):
401
+ async def _getFormProp(self, name):
402
+ name = await s_stormtypes.tostr(name)
398
403
  prop = self.valu.prop(name)
399
404
  if prop is not None:
400
405
  return ModelProp(prop)
@@ -593,10 +598,12 @@ class LibModelEdge(s_stormtypes.Lib):
593
598
 
594
599
  @s_stormtypes.stormfunc(readonly=True)
595
600
  def _methValidKeys(self):
601
+ s_common.deprecated('model.edge.validkeys', curv='2.165.0')
596
602
  return self.validedgekeys
597
603
 
598
604
  @s_stormtypes.stormfunc(readonly=True)
599
605
  async def _methEdgeGet(self, verb):
606
+ s_common.deprecated('model.edge.get', curv='2.165.0')
600
607
  verb = await s_stormtypes.tostr(verb)
601
608
  await self._chkEdgeVerbInView(verb)
602
609
 
@@ -604,6 +611,7 @@ class LibModelEdge(s_stormtypes.Lib):
604
611
  return await self.runt.snap.core.getHiveKey(path) or {}
605
612
 
606
613
  async def _methEdgeSet(self, verb, key, valu):
614
+ s_common.deprecated('model.edge.set', curv='2.165.0')
607
615
  verb = await s_stormtypes.tostr(verb)
608
616
  await self._chkEdgeVerbInView(verb)
609
617
 
@@ -619,6 +627,7 @@ class LibModelEdge(s_stormtypes.Lib):
619
627
  await self.runt.snap.core.setHiveKey(path, kvdict)
620
628
 
621
629
  async def _methEdgeDel(self, verb, key):
630
+ s_common.deprecated('model.edge.del', curv='2.165.0')
622
631
  verb = await s_stormtypes.tostr(verb)
623
632
  await self._chkEdgeVerbInView(verb)
624
633
 
@@ -637,6 +646,7 @@ class LibModelEdge(s_stormtypes.Lib):
637
646
 
638
647
  @s_stormtypes.stormfunc(readonly=True)
639
648
  async def _methEdgeList(self):
649
+ s_common.deprecated('model.edge.list', curv='2.165.0')
640
650
  retn = []
641
651
  async for verb in self.runt.snap.view.getEdgeVerbs():
642
652
  path = self.hivepath + (verb, 'extprops')