synapse 2.191.0__py311-none-any.whl → 2.193.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 (46) hide show
  1. synapse/axon.py +54 -23
  2. synapse/common.py +15 -0
  3. synapse/cortex.py +18 -20
  4. synapse/exc.py +6 -1
  5. synapse/lib/agenda.py +0 -2
  6. synapse/lib/ast.py +30 -12
  7. synapse/lib/cell.py +79 -85
  8. synapse/lib/cli.py +20 -11
  9. synapse/lib/nexus.py +2 -1
  10. synapse/lib/parser.py +1 -1
  11. synapse/lib/snap.py +4 -4
  12. synapse/lib/storm.py +34 -17
  13. synapse/lib/stormhttp.py +32 -35
  14. synapse/lib/stormlib/json.py +5 -2
  15. synapse/lib/stormtypes.py +121 -20
  16. synapse/lib/version.py +2 -2
  17. synapse/models/inet.py +17 -1
  18. synapse/models/infotech.py +14 -4
  19. synapse/models/risk.py +16 -2
  20. synapse/tests/test_axon.py +10 -0
  21. synapse/tests/test_cortex.py +55 -3
  22. synapse/tests/test_exc.py +3 -0
  23. synapse/tests/test_lib_agenda.py +157 -1
  24. synapse/tests/test_lib_ast.py +49 -1
  25. synapse/tests/test_lib_cell.py +106 -1
  26. synapse/tests/test_lib_httpapi.py +9 -2
  27. synapse/tests/test_lib_storm.py +72 -30
  28. synapse/tests/test_lib_stormhttp.py +57 -12
  29. synapse/tests/test_lib_stormlib_json.py +20 -0
  30. synapse/tests/test_lib_stormlib_scrape.py +2 -2
  31. synapse/tests/test_model_inet.py +40 -5
  32. synapse/tests/test_model_risk.py +2 -0
  33. synapse/tests/test_servers_univ.py +0 -12
  34. synapse/tests/test_tools_apikey.py +227 -0
  35. synapse/tests/test_tools_storm.py +95 -0
  36. synapse/tests/test_utils_getrefs.py +1 -1
  37. synapse/tools/apikey.py +93 -0
  38. synapse/utils/getrefs.py +14 -3
  39. synapse/vendor/cpython/lib/http/__init__.py +0 -0
  40. synapse/vendor/cpython/lib/http/cookies.py +59 -0
  41. synapse/vendor/cpython/lib/test/test_http_cookies.py +49 -0
  42. {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/METADATA +2 -2
  43. {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/RECORD +46 -41
  44. {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/WHEEL +1 -1
  45. {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/LICENSE +0 -0
  46. {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/top_level.txt +0 -0
synapse/lib/stormtypes.py CHANGED
@@ -3,6 +3,7 @@ import copy
3
3
  import gzip
4
4
  import json
5
5
  import time
6
+
6
7
  import regex
7
8
  import types
8
9
  import base64
@@ -39,6 +40,7 @@ import synapse.lib.stormctrl as s_stormctrl
39
40
  logger = logging.getLogger(__name__)
40
41
 
41
42
  AXON_MINVERS_PROXY = (2, 97, 0)
43
+ AXON_MINVERS_PROXYTRUE = (2, 192, 0)
42
44
  AXON_MINVERS_SSLOPTS = '>=2.162.0'
43
45
 
44
46
  class Undef:
@@ -73,6 +75,79 @@ def strifyHttpArg(item, multi=False):
73
75
  return retn
74
76
  return item
75
77
 
78
+ async def resolveCoreProxyUrl(valu):
79
+ '''
80
+ Resolve a proxy value to a proxy URL.
81
+
82
+ Args:
83
+ valu (str|None|bool): The proxy value.
84
+
85
+ Returns:
86
+ (str|None): A proxy URL string or None.
87
+ '''
88
+ runt = s_scope.get('runt')
89
+
90
+ match valu:
91
+ case None:
92
+ s_common.deprecated('Setting the HTTP proxy argument $lib.null', curv='2.192.0')
93
+ await runt.snap.warnonce('Setting the HTTP proxy argument to $lib.null is deprecated. Use $lib.true instead.')
94
+ return await runt.snap.core.getConfOpt('http:proxy')
95
+
96
+ case True:
97
+ return await runt.snap.core.getConfOpt('http:proxy')
98
+
99
+ case False:
100
+ runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
101
+ return None
102
+
103
+ case str():
104
+ runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
105
+ return valu
106
+
107
+ case _:
108
+ raise s_exc.BadArg(mesg='HTTP proxy argument must be a string or bool.')
109
+
110
+ async def resolveAxonProxyArg(valu):
111
+ '''
112
+ Resolve a proxy value to the kwarg to set for an Axon HTTP call.
113
+
114
+ Args:
115
+ valu (str|null|bool): The proxy value.
116
+
117
+ Returns:
118
+ tuple: A retn tuple where the proxy kwarg should not be set if ok=False, otherwise a proxy URL or None.
119
+ '''
120
+ runt = s_scope.get('runt')
121
+
122
+ axonvers = runt.snap.core.axoninfo['synapse']['version']
123
+ if axonvers < AXON_MINVERS_PROXY:
124
+ await runt.snap.warnonce(f'Axon version does not support proxy argument: {axonvers} < {AXON_MINVERS_PROXY}')
125
+ return False, None
126
+
127
+ match valu:
128
+ case None:
129
+ s_common.deprecated('Setting the Storm HTTP proxy argument $lib.null', curv='2.192.0')
130
+ await runt.snap.warnonce('Setting the Storm HTTP proxy argument to $lib.null is deprecated. Use $lib.true instead.')
131
+ if axonvers >= AXON_MINVERS_PROXYTRUE:
132
+ return True, True
133
+ return True, None
134
+
135
+ case True:
136
+ if axonvers < AXON_MINVERS_PROXYTRUE:
137
+ return True, None
138
+ return True, True
139
+
140
+ case False:
141
+ runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
142
+ return True, False
143
+
144
+ case str():
145
+ runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
146
+ return True, valu
147
+
148
+ case _:
149
+ raise s_exc.BadArg(mesg='HTTP proxy argument must be a string or bool.')
150
+
76
151
  class StormTypesRegistry:
77
152
  # The following types are currently undefined.
78
153
  base_undefined_types = (
@@ -126,11 +201,29 @@ class StormTypesRegistry:
126
201
  raise Exception('no key!')
127
202
  self.addStormLib(path, ctor)
128
203
 
204
+ for info in ctor._storm_locals:
205
+ rtype = info.get('type')
206
+ if isinstance(rtype, dict) and rtype.get('type') == 'function':
207
+ if (fname := rtype.get('_funcname')) == '_storm_query':
208
+ continue
209
+
210
+ if (func := getattr(ctor, fname, None)) is not None:
211
+ funcpath = '.'.join(('lib',) + ctor._storm_lib_path + (info['name'],))
212
+ func._storm_funcpath = f"${funcpath}"
213
+
129
214
  return ctor
130
215
 
131
216
  def registerType(self, ctor):
132
217
  '''Decorator to register a StormPrim'''
133
218
  self.addStormType(ctor.__name__, ctor)
219
+
220
+ for info in ctor._storm_locals:
221
+ rtype = info.get('type')
222
+ if isinstance(rtype, dict) and rtype.get('type') == 'function':
223
+ fname = rtype.get('_funcname')
224
+ if (func := getattr(ctor, fname, None)) is not None:
225
+ func._storm_funcpath = f"{ctor._storm_typename}.{info['name']}"
226
+
134
227
  return ctor
135
228
 
136
229
  def iterLibs(self):
@@ -553,6 +646,7 @@ class Lib(StormType):
553
646
  if callable(v) and v.__name__ == 'realfunc':
554
647
  v._storm_runtime_lib = self
555
648
  v._storm_runtime_lib_func = k
649
+ v._storm_funcpath = f'${".".join(("lib",) + self.name + (k,))}'
556
650
 
557
651
  self.locls[k] = v
558
652
 
@@ -1993,11 +2087,18 @@ class LibAxon(Lib):
1993
2087
 
1994
2088
  For APIs that accept an ssl_opts argument, the dictionary may contain the following values::
1995
2089
 
1996
- {
2090
+ ({
1997
2091
  'verify': <bool> - Perform SSL/TLS verification. Is overridden by the ssl argument.
1998
2092
  'client_cert': <str> - PEM encoded full chain certificate for use in mTLS.
1999
2093
  'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
2000
- }
2094
+ })
2095
+
2096
+ For APIs that accept a proxy argument, the following values are supported::
2097
+
2098
+ $lib.null: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
2099
+ $lib.true: Use the proxy defined by the http:proxy configuration option if set.
2100
+ $lib.false: Do not use the proxy defined by the http:proxy configuration option if set.
2101
+ <str>: A proxy URL string.
2001
2102
  '''
2002
2103
  _storm_locals = (
2003
2104
  {'name': 'wget', 'desc': """
@@ -2031,8 +2132,8 @@ class LibAxon(Lib):
2031
2132
  'desc': 'Set to False to disable SSL/TLS certificate verification.', 'default': True},
2032
2133
  {'name': 'timeout', 'type': 'int', 'desc': 'Timeout for the download operation.',
2033
2134
  'default': None},
2034
- {'name': 'proxy', 'type': ['boolean', 'null', 'str'],
2035
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
2135
+ {'name': 'proxy', 'type': ['bool', 'str'],
2136
+ 'desc': 'Configure proxy usage. See $lib.axon help for additional details.', 'default': True},
2036
2137
  {'name': 'ssl_opts', 'type': 'dict',
2037
2138
  'desc': 'Optional SSL/TLS options. See $lib.axon help for additional details.',
2038
2139
  'default': None},
@@ -2054,8 +2155,8 @@ class LibAxon(Lib):
2054
2155
  'desc': 'Set to False to disable SSL/TLS certificate verification.', 'default': True},
2055
2156
  {'name': 'timeout', 'type': 'int', 'desc': 'Timeout for the download operation.',
2056
2157
  'default': None},
2057
- {'name': 'proxy', 'type': ['boolean', 'null', 'str'],
2058
- 'desc': 'Set to a proxy URL string or $lib.false to disable proxy use.', 'default': None},
2158
+ {'name': 'proxy', 'type': ['bool', 'str'],
2159
+ 'desc': 'Configure proxy usage. See $lib.axon help for additional details.', 'default': True},
2059
2160
  {'name': 'ssl_opts', 'type': 'dict',
2060
2161
  'desc': 'Optional SSL/TLS options. See $lib.axon help for additional details.',
2061
2162
  'default': None},
@@ -2370,7 +2471,7 @@ class LibAxon(Lib):
2370
2471
  return await axon.del_(sha256b)
2371
2472
 
2372
2473
  async def wget(self, url, headers=None, params=None, method='GET', json=None, body=None,
2373
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
2474
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
2374
2475
 
2375
2476
  if not self.runt.allowed(('axon', 'wget')):
2376
2477
  self.runt.confirm(('storm', 'lib', 'axon', 'wget'))
@@ -2387,20 +2488,19 @@ class LibAxon(Lib):
2387
2488
  proxy = await toprim(proxy)
2388
2489
  ssl_opts = await toprim(ssl_opts)
2389
2490
 
2390
- if proxy is not None:
2391
- self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
2392
-
2393
2491
  params = strifyHttpArg(params, multi=True)
2394
2492
  headers = strifyHttpArg(headers)
2395
2493
 
2396
2494
  await self.runt.snap.core.getAxon()
2397
2495
 
2398
2496
  kwargs = {}
2399
- axonvers = self.runt.snap.core.axoninfo['synapse']['version']
2400
- if axonvers >= AXON_MINVERS_PROXY:
2497
+
2498
+ ok, proxy = await resolveAxonProxyArg(proxy)
2499
+ if ok:
2401
2500
  kwargs['proxy'] = proxy
2402
2501
 
2403
2502
  if ssl_opts is not None:
2503
+ axonvers = self.runt.snap.core.axoninfo['synapse']['version']
2404
2504
  mesg = f'The ssl_opts argument requires an Axon Synapse version {AXON_MINVERS_SSLOPTS}, ' \
2405
2505
  f'but the Axon is running {axonvers}'
2406
2506
  s_version.reqVersion(axonvers, AXON_MINVERS_SSLOPTS, mesg=mesg)
@@ -2413,7 +2513,7 @@ class LibAxon(Lib):
2413
2513
  return resp
2414
2514
 
2415
2515
  async def wput(self, sha256, url, headers=None, params=None, method='PUT',
2416
- ssl=True, timeout=None, proxy=None, ssl_opts=None):
2516
+ ssl=True, timeout=None, proxy=True, ssl_opts=None):
2417
2517
 
2418
2518
  if not self.runt.allowed(('axon', 'wput')):
2419
2519
  self.runt.confirm(('storm', 'lib', 'axon', 'wput'))
@@ -2432,23 +2532,24 @@ class LibAxon(Lib):
2432
2532
  params = strifyHttpArg(params, multi=True)
2433
2533
  headers = strifyHttpArg(headers)
2434
2534
 
2435
- if proxy is not None:
2436
- self.runt.confirm(('storm', 'lib', 'inet', 'http', 'proxy'))
2437
-
2438
- axon = self.runt.snap.core.axon
2439
- sha256byts = s_common.uhex(sha256)
2535
+ await self.runt.snap.core.getAxon()
2440
2536
 
2441
2537
  kwargs = {}
2442
- axonvers = self.runt.snap.core.axoninfo['synapse']['version']
2443
- if axonvers >= AXON_MINVERS_PROXY:
2538
+
2539
+ ok, proxy = await resolveAxonProxyArg(proxy)
2540
+ if ok:
2444
2541
  kwargs['proxy'] = proxy
2445
2542
 
2446
2543
  if ssl_opts is not None:
2544
+ axonvers = self.runt.snap.core.axoninfo['synapse']['version']
2447
2545
  mesg = f'The ssl_opts argument requires an Axon Synapse version {AXON_MINVERS_SSLOPTS}, ' \
2448
2546
  f'but the Axon is running {axonvers}'
2449
2547
  s_version.reqVersion(axonvers, AXON_MINVERS_SSLOPTS, mesg=mesg)
2450
2548
  kwargs['ssl_opts'] = ssl_opts
2451
2549
 
2550
+ axon = self.runt.snap.core.axon
2551
+ sha256byts = s_common.uhex(sha256)
2552
+
2452
2553
  return await axon.wput(sha256byts, url, headers=headers, params=params, method=method,
2453
2554
  ssl=ssl, timeout=timeout, **kwargs)
2454
2555
 
synapse/lib/version.py CHANGED
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
223
223
  ##############################################################################
224
224
  # The following are touched during the release process by bumpversion.
225
225
  # Do not modify these directly.
226
- version = (2, 191, 0)
226
+ version = (2, 193, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'f6b07ada7cb68701e769e155735c9c004a404454'
228
+ commit = 'ad17bf2e740ba11453b7827ce70c140f969a1430'
synapse/models/inet.py CHANGED
@@ -1442,7 +1442,11 @@ class InetModule(s_module.CoreModule):
1442
1442
  'doc': 'A channel within a web service or instance such as slack or discord.'
1443
1443
  }),
1444
1444
 
1445
- ('inet:web:hashtag', ('str', {'lower': True, 'regex': r'^#\w[\w·]*(?<!·)$'}), {
1445
+ ('inet:web:hashtag', ('str', {'lower': True, 'strip': True, 'regex': r'^#[^\p{Z}#]+$'}), {
1446
+ # regex explanation:
1447
+ # - starts with pound
1448
+ # - one or more non-whitespace/non-pound character
1449
+ # The minimum hashtag is a pound with a single non-whitespace character
1446
1450
  'doc': 'A hashtag used in a web post.',
1447
1451
  }),
1448
1452
 
@@ -1728,6 +1732,9 @@ class InetModule(s_module.CoreModule):
1728
1732
  'template': {'service:base': 'object'},
1729
1733
  'props': (
1730
1734
 
1735
+ ('url', ('inet:url', {}), {
1736
+ 'doc': 'The primary URL associated with the {service:base}.'}),
1737
+
1731
1738
  ('status', ('inet:service:object:status', {}), {
1732
1739
  'doc': 'The status of the {service:base}.'}),
1733
1740
 
@@ -1811,6 +1818,9 @@ class InetModule(s_module.CoreModule):
1811
1818
 
1812
1819
  ('inet:email:message', {}, (
1813
1820
 
1821
+ ('id', ('str', {'strip': True}), {
1822
+ 'doc': 'The ID parsed from the "message-id" header.'}),
1823
+
1814
1824
  ('to', ('inet:email', {}), {
1815
1825
  'doc': 'The email address of the recipient.'}),
1816
1826
 
@@ -2171,6 +2181,9 @@ class InetModule(s_module.CoreModule):
2171
2181
  ('dst:ssh:key', ('crypto:key', {}), {
2172
2182
  'doc': 'The key sent by the server as part of an SSH session setup.'}),
2173
2183
 
2184
+ ('capture:host', ('it:host', {}), {
2185
+ 'doc': 'The host which captured the flow.'}),
2186
+
2174
2187
  ('raw', ('data', {}), {
2175
2188
  'doc': 'A raw record used to create the flow which may contain additional protocol details.'}),
2176
2189
  )),
@@ -2194,6 +2207,9 @@ class InetModule(s_module.CoreModule):
2194
2207
  ('host', ('it:host', {}), {
2195
2208
  'doc': 'The host that used the network egress.'}),
2196
2209
 
2210
+ ('host:iface', ('inet:iface', {}), {
2211
+ 'doc': 'The interface which the host used to connect out via the egress.'}),
2212
+
2197
2213
  ('account', ('inet:service:account', {}), {
2198
2214
  'doc': 'The service account which used the client address to egress.'}),
2199
2215
 
@@ -655,6 +655,7 @@ class ItModule(s_module.CoreModule):
655
655
 
656
656
  ('it:host', ('guid', {}), {
657
657
  'interfaces': ('inet:service:object',),
658
+ 'template': {'service:base': 'host'},
658
659
  'doc': 'A GUID that represents a host or system.'}),
659
660
 
660
661
  ('it:log:event:type:taxonomy', ('taxonomy', {}), {
@@ -784,6 +785,7 @@ class ItModule(s_module.CoreModule):
784
785
  }),
785
786
  ('it:dev:repo', ('guid', {}), {
786
787
  'interfaces': ('inet:service:object',),
788
+ 'template': {'service:base': 'repository'},
787
789
  'doc': 'A version control system instance.',
788
790
  }),
789
791
  ('it:dev:repo:remote', ('guid', {}), {
@@ -791,10 +793,12 @@ class ItModule(s_module.CoreModule):
791
793
  }),
792
794
  ('it:dev:repo:branch', ('guid', {}), {
793
795
  'interfaces': ('inet:service:object',),
796
+ 'template': {'service:base': 'repository branch'},
794
797
  'doc': 'A branch in a version control system instance.',
795
798
  }),
796
799
  ('it:dev:repo:commit', ('guid', {}), {
797
800
  'interfaces': ('inet:service:object',),
801
+ 'template': {'service:base': 'repository commit'},
798
802
  'doc': 'A commit to a repository.',
799
803
  }),
800
804
  ('it:dev:repo:diff', ('guid', {}), {
@@ -802,18 +806,22 @@ class ItModule(s_module.CoreModule):
802
806
  }),
803
807
  ('it:dev:repo:issue:label', ('guid', {}), {
804
808
  'interfaces': ('inet:service:object',),
809
+ 'template': {'service:base': 'repository issue label'},
805
810
  'doc': 'A label applied to a repository issue.',
806
811
  }),
807
812
  ('it:dev:repo:issue', ('guid', {}), {
808
813
  'interfaces': ('inet:service:object',),
814
+ 'template': {'service:base': 'repository issue'},
809
815
  'doc': 'An issue raised in a repository.',
810
816
  }),
811
817
  ('it:dev:repo:issue:comment', ('guid', {}), {
812
818
  'interfaces': ('inet:service:object',),
819
+ 'template': {'service:base': 'repository issue comment'},
813
820
  'doc': 'A comment on an issue in a repository.',
814
821
  }),
815
822
  ('it:dev:repo:diff:comment', ('guid', {}), {
816
823
  'interfaces': ('inet:service:object',),
824
+ 'template': {'service:base': 'repository diff comment'},
817
825
  'doc': 'A comment on a diff in a repository.',
818
826
  }),
819
827
  ('it:prod:soft', ('guid', {}), {
@@ -963,12 +971,12 @@ class ItModule(s_module.CoreModule):
963
971
  }),
964
972
  ('it:exec:pipe', ('guid', {}), {
965
973
  'interfaces': ('it:host:activity',),
966
- 'doc': 'A named pipe created by a process at runtime.',
967
- }),
974
+ 'doc': 'A named pipe created by a process at runtime.'}),
975
+
968
976
  ('it:exec:url', ('guid', {}), {
969
977
  'interfaces': ('it:host:activity',),
970
- 'doc': 'An instance of a host requesting a URL.',
971
- }),
978
+ 'doc': 'An instance of a host requesting a URL using any protocol scheme.'}),
979
+
972
980
  ('it:exec:bind', ('guid', {}), {
973
981
  'interfaces': ('it:host:activity',),
974
982
  'doc': 'An instance of a host binding a listening port.',
@@ -1046,6 +1054,7 @@ class ItModule(s_module.CoreModule):
1046
1054
 
1047
1055
  ('it:host:tenancy', ('guid', {}), {
1048
1056
  'interfaces': ('inet:service:object',),
1057
+ 'template': {'service:base': 'host tenancy'},
1049
1058
  'doc': 'A time window where a host was a tenant run by another host.'}),
1050
1059
 
1051
1060
  ('it:software:image:type:taxonomy', ('taxonomy', {}), {
@@ -1054,6 +1063,7 @@ class ItModule(s_module.CoreModule):
1054
1063
 
1055
1064
  ('it:software:image', ('guid', {}), {
1056
1065
  'interfaces': ('inet:service:object',),
1066
+ 'template': {'service:base': 'software image'},
1057
1067
  'doc': 'The base image used to create a container or OS.'}),
1058
1068
 
1059
1069
  ('it:storage:mount', ('guid', {}), {
synapse/models/risk.py CHANGED
@@ -242,9 +242,18 @@ class RiskModule(s_module.CoreModule):
242
242
  (('risk:mitigation', 'uses', 'inet:service:rule'), {
243
243
  'doc': 'The mitigation uses the service rule.'}),
244
244
 
245
+ (('risk:mitigation', 'uses', 'it:prod:softver'), {
246
+ 'doc': 'The mitigation uses the software version.'}),
247
+
248
+ (('risk:mitigation', 'uses', 'it:prod:hardware'), {
249
+ 'doc': 'The mitigation uses the hardware.'}),
250
+
245
251
  (('risk:leak', 'leaked', None), {
246
252
  'doc': 'The leak included the disclosure of the target node.'}),
247
253
 
254
+ (('risk:leak', 'enabled', 'risk:leak'), {
255
+ 'doc': 'The source leak enabled the target leak to occur.'}),
256
+
248
257
  (('risk:extortion', 'leveraged', None), {
249
258
  'doc': 'The extortion event was based on attacker access to the target node.'}),
250
259
 
@@ -407,10 +416,12 @@ class RiskModule(s_module.CoreModule):
407
416
  'doc': 'A description of the mitigation approach for the vulnerability.'}),
408
417
 
409
418
  ('software', ('it:prod:softver', {}), {
410
- 'doc': 'A software version which implements a fix for the vulnerability.'}),
419
+ 'deprecated': True,
420
+ 'doc': 'Deprecated. Please use risk:mitigation -(uses)> it:prod:softver.'}),
411
421
 
412
422
  ('hardware', ('it:prod:hardware', {}), {
413
- 'doc': 'A hardware version which implements a fix for the vulnerability.'}),
423
+ 'deprecated': True,
424
+ 'doc': 'Deprecated. Please use risk:mitigation -(uses)> it:prod:hardware.'}),
414
425
 
415
426
  ('reporter', ('ou:org', {}), {
416
427
  'doc': 'The organization reporting on the mitigation.'}),
@@ -1034,6 +1045,9 @@ class RiskModule(s_module.CoreModule):
1034
1045
  ('leaker', ('ps:contact', {}), {
1035
1046
  'doc': 'The identity which leaked the information.'}),
1036
1047
 
1048
+ ('recipient', ('ps:contact', {}), {
1049
+ 'doc': 'The identity which received the leaked information.'}),
1050
+
1037
1051
  ('type', ('risk:leak:type:taxonomy', {}), {
1038
1052
  'doc': 'A type taxonomy for the leak.'}),
1039
1053
 
@@ -945,10 +945,16 @@ bar baz",vv
945
945
  self.false(resp.get('ok'))
946
946
  self.isin('connect to proxy 127.0.0.1:1', resp.get('mesg', ''))
947
947
 
948
+ resp = await proxy.wget('http://vertex.link/', proxy=None)
949
+ self.false(resp.get('ok'))
950
+ self.isin('connect to proxy 127.0.0.1:1', resp.get('mesg', ''))
951
+
948
952
  resp = await proxy.wget('vertex.link')
949
953
  self.false(resp.get('ok'))
950
954
  self.isin('InvalidUrlClientError: vertex.link', resp.get('mesg', ''))
951
955
 
956
+ await self.asyncraises(s_exc.BadArg, proxy.wget('http://vertex.link', proxy=1.1))
957
+
952
958
  async def test_axon_wput(self):
953
959
 
954
960
  async with self.getTestCore() as core:
@@ -1025,6 +1031,10 @@ bar baz",vv
1025
1031
  self.false(resp.get('ok'))
1026
1032
  self.isin('connect to proxy 127.0.0.1:1', resp.get('reason'))
1027
1033
 
1034
+ resp = await proxy.postfiles(fields, f'https://127.0.0.1:{port}/api/v1/pushfile', ssl=False, proxy=None)
1035
+ self.false(resp.get('ok'))
1036
+ self.isin('connect to proxy 127.0.0.1:1', resp.get('reason'))
1037
+
1028
1038
  resp = await proxy.wput(sha256, 'vertex.link')
1029
1039
  self.false(resp.get('ok'))
1030
1040
  self.isin('InvalidUrlClientError: vertex.link', resp.get('mesg', ''))
@@ -484,7 +484,7 @@ class CortexTest(s_t_utils.SynTest):
484
484
  self.len(0, mods)
485
485
  self.len(0, core.modsbyiface.get('lookup'))
486
486
 
487
- await core.loadStormPkg(pkgdef)
487
+ core.loadStormPkg(pkgdef)
488
488
 
489
489
  mods = await core.getStormIfaces('lookup')
490
490
  self.len(1, mods)
@@ -513,7 +513,7 @@ class CortexTest(s_t_utils.SynTest):
513
513
  vals = [r async for r in core.view.callStormIface('boom', todo)]
514
514
  self.eq((), vals)
515
515
 
516
- await core._dropStormPkg(pkgdef)
516
+ core._dropStormPkg(pkgdef)
517
517
  self.none(core.modsbyiface.get('lookup'))
518
518
 
519
519
  mods = await core.getStormIfaces('lookup')
@@ -558,7 +558,7 @@ class CortexTest(s_t_utils.SynTest):
558
558
  nodes = await core.nodes('foo@bar.com foo@bar.com', opts={'mode': 'lookup'})
559
559
  self.eq(['inet:email', 'inet:email'], [n.ndef[0] for n in nodes])
560
560
 
561
- await core.loadStormPkg(pkgdef)
561
+ core.loadStormPkg(pkgdef)
562
562
  self.len(1, await core.getStormIfaces('search'))
563
563
 
564
564
  todo = s_common.todo('search', ('foo@bar.com',))
@@ -4023,6 +4023,58 @@ class CortexBasicTest(s_t_utils.SynTest):
4023
4023
  gdef = await core.callStorm('return($lib.graph.add(({"name": "def", "permissions": {"default": 0}})))')
4024
4024
  self.eq(0, gdef['permissions']['default'])
4025
4025
 
4026
+ async def test_graph_projection_query_validation(self):
4027
+ async with self.getTestCore() as core:
4028
+ valid = {
4029
+ 'name': 'valid',
4030
+ 'forms': {
4031
+ 'inet:fqdn': {
4032
+ 'pivots': ['<- *'],
4033
+ 'filters': []
4034
+ }
4035
+ }
4036
+ }
4037
+
4038
+ self.nn(await core.addStormGraph(valid))
4039
+
4040
+ bad_form_pivot = {
4041
+ 'name': 'bad form pivot',
4042
+ 'forms': {
4043
+ 'inet:fqdn': {
4044
+ 'pivots': ['<- * |||'],
4045
+ 'filters': []
4046
+ }
4047
+ }
4048
+ }
4049
+
4050
+ await self.asyncraises(s_exc.BadSyntax, core.addStormGraph(bad_form_pivot))
4051
+
4052
+ bad_form_filter = {
4053
+ 'name': 'bad form filter',
4054
+ 'forms': {
4055
+ 'inet:fqdn': {
4056
+ 'pivots': [],
4057
+ 'filters': ['+++:wat']
4058
+ }
4059
+ }
4060
+ }
4061
+
4062
+ await self.asyncraises(s_exc.BadSyntax, core.addStormGraph(bad_form_filter))
4063
+
4064
+ bad_global_filter = {
4065
+ 'name': 'bad global filter',
4066
+ 'filters': ['+++:wat']
4067
+ }
4068
+
4069
+ await self.asyncraises(s_exc.BadSyntax, core.addStormGraph(bad_global_filter))
4070
+
4071
+ bad_global_pivot = {
4072
+ 'name': 'bad global pivot',
4073
+ 'pivots': ['-> * |||']
4074
+ }
4075
+
4076
+ await self.asyncraises(s_exc.BadSyntax, core.addStormGraph(bad_global_pivot))
4077
+
4026
4078
  async def test_storm_two_level_assignment(self):
4027
4079
  async with self.getTestCore() as core:
4028
4080
  q = '$foo=baz $bar=$foo [test:str=$bar]'
synapse/tests/test_exc.py CHANGED
@@ -27,6 +27,9 @@ class ExcTest(s_t_utils.SynTest):
27
27
  e.setdefault('defv', 2)
28
28
  self.eq("SynErr: defv=1 foo='words' hehe=1234 mesg='words'", str(e))
29
29
 
30
+ e.update({'foo': 'newwords', 'bar': 'baz'})
31
+ self.eq("SynErr: bar='baz' defv=1 foo='newwords' hehe=1234 mesg='words'", str(e))
32
+
30
33
  self.eq(e.errname, 'SynErr')
31
34
 
32
35
  e2 = s_exc.BadTypeValu(mesg='haha')