synapse 2.190.0__py311-none-any.whl → 2.192.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 (49) hide show
  1. synapse/axon.py +54 -23
  2. synapse/common.py +9 -0
  3. synapse/cortex.py +3 -2
  4. synapse/datamodel.py +8 -1
  5. synapse/lib/ast.py +6 -2
  6. synapse/lib/cell.py +55 -7
  7. synapse/lib/msgpack.py +10 -3
  8. synapse/lib/nexus.py +2 -1
  9. synapse/lib/stormhttp.py +32 -35
  10. synapse/lib/stormlib/model.py +37 -0
  11. synapse/lib/stormtypes.py +102 -20
  12. synapse/lib/version.py +2 -2
  13. synapse/models/auth.py +2 -1
  14. synapse/models/base.py +20 -0
  15. synapse/models/crypto.py +5 -2
  16. synapse/models/economic.py +45 -11
  17. synapse/models/inet.py +78 -21
  18. synapse/models/person.py +11 -4
  19. synapse/models/risk.py +6 -0
  20. synapse/models/syn.py +22 -12
  21. synapse/models/telco.py +3 -1
  22. synapse/tests/test_axon.py +10 -0
  23. synapse/tests/test_cortex.py +60 -17
  24. synapse/tests/test_lib_agenda.py +1 -6
  25. synapse/tests/test_lib_ast.py +6 -0
  26. synapse/tests/test_lib_cell.py +63 -4
  27. synapse/tests/test_lib_httpapi.py +11 -6
  28. synapse/tests/test_lib_lmdbslab.py +1 -4
  29. synapse/tests/test_lib_stormhttp.py +57 -12
  30. synapse/tests/test_lib_stormlib_cortex.py +1 -3
  31. synapse/tests/test_lib_stormlib_log.py +1 -6
  32. synapse/tests/test_lib_stormlib_model.py +28 -0
  33. synapse/tests/test_lib_stormtypes.py +1 -2
  34. synapse/tests/test_lib_trigger.py +2 -3
  35. synapse/tests/test_model_base.py +12 -2
  36. synapse/tests/test_model_inet.py +23 -0
  37. synapse/tests/test_model_person.py +2 -0
  38. synapse/tests/test_model_risk.py +5 -0
  39. synapse/tests/test_model_syn.py +198 -0
  40. synapse/tests/test_servers_univ.py +0 -12
  41. synapse/tests/test_tools_apikey.py +227 -0
  42. synapse/tests/test_utils.py +23 -4
  43. synapse/tests/utils.py +39 -5
  44. synapse/tools/apikey.py +93 -0
  45. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/METADATA +4 -4
  46. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/RECORD +49 -47
  47. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/LICENSE +0 -0
  48. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/WHEEL +0 -0
  49. {synapse-2.190.0.dist-info → synapse-2.192.0.dist-info}/top_level.txt +0 -0
@@ -115,8 +115,20 @@ class EchoAuthApi(s_cell.CellApi):
115
115
  await self._reqUserAllowed(path)
116
116
  return True
117
117
 
118
+ @s_cell.adminapi()
119
+ async def adminOnly(self):
120
+ return True
121
+
122
+ @s_cell.adminapi(log=True)
123
+ async def adminOnlyLog(self, arg1, arg2, **kwargs):
124
+ return arg1, arg2, kwargs
125
+
118
126
  class EchoAuth(s_cell.Cell):
119
127
  cellapi = EchoAuthApi
128
+ # non-default commit / version / verstring
129
+ COMMIT = 'mycommit'
130
+ VERSION = (1, 2, 3)
131
+ VERSTRING = '1.2.3'
120
132
 
121
133
  async def answer(self):
122
134
  return 42
@@ -428,6 +440,16 @@ class CellTest(s_t_utils.SynTest):
428
440
  self.eq(info.get('user').get('name'), 'root')
429
441
  self.eq(info.get('user').get('iden'), root.iden)
430
442
 
443
+ # @adminApi methods are allowed
444
+ self.true(await proxy.adminOnly())
445
+ mesg = "Executing [EchoAuthApi.adminOnlyLog] as [root] with args [(1, 2)[{'three': 4}]"
446
+ with self.getStructuredAsyncLoggerStream('synapse.lib.cell', mesg) as stream:
447
+ self.eq(await proxy.adminOnlyLog(1, 2, three=4), (1, 2, {'three': 4}))
448
+ self.true(await stream.wait(timeout=10))
449
+ msgs = stream.jsonlines()
450
+ self.len(1, msgs)
451
+ self.eq('EchoAuthApi.adminOnlyLog', msgs[0].get('wrapped_func'))
452
+
431
453
  visi = await echo.auth.addUser('visi')
432
454
  await visi.setPasswd('foo')
433
455
  await visi.addRule((True, ('foo', 'bar')))
@@ -454,6 +476,15 @@ class CellTest(s_t_utils.SynTest):
454
476
  with self.raises(s_exc.NoSuchUser):
455
477
  await proxy.getUserInfo('newp')
456
478
 
479
+ # @adminApi methods are not allowed
480
+ with self.raises(s_exc.AuthDeny) as cm:
481
+ await proxy.adminOnly()
482
+ self.eq(cm.exception.get('mesg'), 'User is not an admin [visi]')
483
+ self.eq(cm.exception.get('user'), visi.iden)
484
+ self.eq(cm.exception.get('username'), visi.name)
485
+ with self.raises(s_exc.AuthDeny) as cm:
486
+ await proxy.adminOnlyLog(1, 2, three=4)
487
+
457
488
  # User cannot get authinfo for other items since they are
458
489
  # not an admin or do not have those roles.
459
490
  await self.asyncraises(s_exc.AuthDeny, proxy.getUserInfo('root'))
@@ -788,6 +819,37 @@ class CellTest(s_t_utils.SynTest):
788
819
  https = netw.get('https')
789
820
  self.eq(https, http_info)
790
821
 
822
+ # Mirrors & ready flags
823
+ async with self.getTestAha() as aha: # type: s_aha.AhaCell
824
+
825
+ with self.getTestDir() as dirn:
826
+ cdr0 = s_common.genpath(dirn, 'cell00')
827
+ cdr1 = s_common.genpath(dirn, 'cell01')
828
+ cell00 = await aha.enter_context(self.addSvcToAha(aha, '00.cell', EchoAuth,
829
+ dirn=cdr0)) # type: EchoAuth
830
+ # Ensure we have a nexus transaction
831
+ await cell00.sync()
832
+ cell01 = await aha.enter_context(self.addSvcToAha(aha, '01.cell', EchoAuth,
833
+ dirn=cdr1,
834
+ provinfo={'mirror': 'cell'})) # type: EchoAuth
835
+
836
+ self.true(await asyncio.wait_for(cell01.nexsroot.ready.wait(), timeout=12))
837
+ await cell01.sync()
838
+
839
+ cnfo0 = await cell00.getCellInfo()
840
+ cnfo1 = await cell01.getCellInfo()
841
+ self.true(cnfo0['cell']['ready'])
842
+ self.false(cnfo0['cell']['uplink'])
843
+ self.none(cnfo0['cell']['mirror'])
844
+ self.eq(cnfo0['cell']['version'], (1, 2, 3))
845
+
846
+ self.true(cnfo1['cell']['ready'])
847
+ self.true(cnfo1['cell']['uplink'])
848
+ self.eq(cnfo1['cell']['mirror'], 'aha://root@cell...')
849
+ self.eq(cnfo1['cell']['version'], (1, 2, 3))
850
+
851
+ self.eq(cnfo0['cell']['nexsindx'], cnfo1['cell']['nexsindx'])
852
+
791
853
  async def test_cell_dyncall(self):
792
854
 
793
855
  with self.getTestDir() as dirn:
@@ -3064,10 +3126,7 @@ class CellTest(s_t_utils.SynTest):
3064
3126
  async with self.getTestCore(conf={'health:sysctl:checks': True}):
3065
3127
  pass
3066
3128
 
3067
- stream.seek(0)
3068
- data = stream.getvalue()
3069
- raw_mesgs = [m for m in data.split('\n') if m]
3070
- msgs = [json.loads(m) for m in raw_mesgs]
3129
+ msgs = stream.jsonlines()
3071
3130
 
3072
3131
  self.len(1, msgs)
3073
3132
 
@@ -1722,10 +1722,8 @@ class HttpApiTest(s_tests.SynTest):
1722
1722
 
1723
1723
  async def test_request_logging(self):
1724
1724
 
1725
- def get_mesg(stream):
1726
- data = stream.getvalue()
1727
- raw_mesgs = [m for m in data.split('\n') if m]
1728
- msgs = [json.loads(m) for m in raw_mesgs]
1725
+ def get_mesg(stream: s_tests.AsyncStreamEvent) -> dict:
1726
+ msgs = stream.jsonlines()
1729
1727
  self.len(1, msgs)
1730
1728
  return msgs[0]
1731
1729
 
@@ -1746,8 +1744,12 @@ class HttpApiTest(s_tests.SynTest):
1746
1744
 
1747
1745
  with self.getStructuredAsyncLoggerStream(logname, 'api/v1/auth/adduser') as stream:
1748
1746
 
1747
+ headers = {
1748
+ 'X-Forwarded-For': '1.2.3.4',
1749
+ 'User-Agent': 'test_request_logging',
1750
+ }
1749
1751
  async with sess.post(f'https://root:root@localhost:{port}/api/v1/auth/adduser',
1750
- json=info, headers={'X-Forwarded-For': '1.2.3.4'}) as resp:
1752
+ json=info, headers=headers) as resp:
1751
1753
  item = await resp.json()
1752
1754
  self.nn(item.get('result').get('iden'))
1753
1755
  visiiden = item['result']['iden']
@@ -1758,6 +1760,8 @@ class HttpApiTest(s_tests.SynTest):
1758
1760
  self.eq(mesg.get('uri'), '/api/v1/auth/adduser')
1759
1761
  self.eq(mesg.get('username'), 'root')
1760
1762
  self.eq(mesg.get('user'), core.auth.rootuser.iden)
1763
+ self.isin('headers', mesg)
1764
+ self.eq(mesg['headers'].get('user-agent'), 'test_request_logging')
1761
1765
  self.isin('remoteip', mesg)
1762
1766
  self.isin('(root)', mesg.get('message'))
1763
1767
  self.isin('200 POST /api/v1/auth/adduser', mesg.get('message'))
@@ -1765,12 +1769,13 @@ class HttpApiTest(s_tests.SynTest):
1765
1769
 
1766
1770
  # No auth provided
1767
1771
  with self.getStructuredAsyncLoggerStream(logname, 'api/v1/active') as stream:
1768
- async with sess.get(f'https://root:root@localhost:{port}/api/v1/active') as resp:
1772
+ async with sess.get(f'https://root:root@localhost:{port}/api/v1/active', skip_auto_headers=['User-Agent']) as resp:
1769
1773
  self.eq(resp.status, 200)
1770
1774
  self.true(await stream.wait(6))
1771
1775
 
1772
1776
  mesg = get_mesg(stream)
1773
1777
  self.eq(mesg.get('uri'), '/api/v1/active')
1778
+ self.notin('headers', mesg)
1774
1779
  self.notin('username', mesg)
1775
1780
  self.notin('user', mesg)
1776
1781
  self.isin('remoteip', mesg)
@@ -1,5 +1,4 @@
1
1
  import os
2
- import json
3
2
  import asyncio
4
3
  import pathlib
5
4
  import multiprocessing
@@ -15,7 +14,6 @@ import synapse.lib.lmdbslab as s_lmdbslab
15
14
  import synapse.lib.thisplat as s_thisplat
16
15
 
17
16
  import synapse.tests.utils as s_t_utils
18
- from synapse.tests.utils import alist
19
17
 
20
18
  def getFileMapCount(filename):
21
19
  filename = str(filename)
@@ -360,8 +358,7 @@ class LmdbSlabTest(s_t_utils.SynTest):
360
358
  slab.put(b'\xff\xff\xff\xff' + s_common.guid(i).encode('utf8'), byts, db=foo)
361
359
  self.true(await stream.wait(timeout=1))
362
360
 
363
- data = stream.getvalue()
364
- msgs = [json.loads(m) for m in data.split('\\n') if m]
361
+ msgs = stream.jsonlines()
365
362
  self.gt(len(msgs), 0)
366
363
  self.nn(msgs[0].get('delta'))
367
364
  self.nn(msgs[0].get('path'))
@@ -9,7 +9,7 @@ import synapse.common as s_common
9
9
  import synapse.lib.certdir as s_certdir
10
10
  import synapse.lib.httpapi as s_httpapi
11
11
  import synapse.lib.stormctrl as s_stormctrl
12
- import synapse.lib.stormhttp as s_stormhttp
12
+ import synapse.lib.stormtypes as s_stormtypes
13
13
 
14
14
  import synapse.tests.utils as s_test
15
15
 
@@ -606,11 +606,39 @@ class StormHttpTest(s_test.SynTest):
606
606
  self.false(resp.get('ok'))
607
607
  self.ne(-1, resp['mesg'].find('connect to proxy 127.0.0.1:1'))
608
608
 
609
+ msgs = await core.stormlist('$resp=$lib.axon.wget("http://vertex.link", proxy=(null)) $lib.print($resp.mesg)')
610
+ self.stormIsInWarn('HTTP proxy argument to $lib.null is deprecated', msgs)
611
+ self.stormIsInPrint('connect to proxy 127.0.0.1:1', msgs)
612
+
613
+ await self.asyncraises(s_exc.BadArg, core.nodes('$lib.axon.wget("http://vertex.link", proxy=(1.1))'))
614
+
615
+ # todo: setting the synapse version can be removed once proxy=true support is released
616
+ try:
617
+ oldv = core.axoninfo['synapse']['version']
618
+ core.axoninfo['synapse']['version'] = (oldv[0], oldv[1] + 1, oldv[2])
619
+ resp = await core.callStorm('return($lib.axon.wget("http://vertex.link", proxy=(null)))')
620
+ self.false(resp.get('ok'))
621
+ self.ne(-1, resp['mesg'].find('connect to proxy 127.0.0.1:1'))
622
+ finally:
623
+ core.axoninfo['synapse']['version'] = oldv
624
+
625
+ size, sha256 = await core.axon.put(b'asdf')
626
+ opts = {'vars': {'sha256': s_common.ehex(sha256)}}
627
+ resp = await core.callStorm(f'return($lib.axon.wput($sha256, http://vertex.link))', opts=opts)
628
+ self.false(resp.get('ok'))
629
+ self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
630
+
609
631
  q = '$resp=$lib.inet.http.get("http://vertex.link") return(($resp.code, $resp.err))'
610
632
  code, (errname, _) = await core.callStorm(q)
611
633
  self.eq(code, -1)
612
634
  self.eq('ProxyConnectionError', errname)
613
635
 
636
+ msgs = await core.stormlist('$resp=$lib.inet.http.get("http://vertex.link", proxy=(null)) $lib.print($resp.err)')
637
+ self.stormIsInWarn('HTTP proxy argument to $lib.null is deprecated', msgs)
638
+ self.stormIsInPrint('connect to proxy 127.0.0.1:1', msgs)
639
+
640
+ await self.asyncraises(s_exc.BadArg, core.nodes('$lib.inet.http.get("http://vertex.link", proxy=(1.1))'))
641
+
614
642
  async with self.getTestCore() as core:
615
643
 
616
644
  visi = await core.auth.addUser('visi')
@@ -654,6 +682,24 @@ class StormHttpTest(s_test.SynTest):
654
682
  self.false(resp.get('ok'))
655
683
  self.isin('connect to proxy 127.0.0.1:1', resp['mesg'])
656
684
 
685
+ host, port = await core.addHttpsPort(0)
686
+ opts = {
687
+ 'vars': {
688
+ 'url': f'https://loop.vertex.link:{port}',
689
+ 'proxy': 'socks5://user:pass@127.0.0.1:1',
690
+ }
691
+ }
692
+ try:
693
+ oldv = core.axoninfo['synapse']['version']
694
+ minver = s_stormtypes.AXON_MINVERS_PROXY
695
+ core.axoninfo['synapse']['version'] = minver[2], minver[1] - 1, minver[0]
696
+ q = '$resp=$lib.axon.wget($url, ssl=(false), proxy=$proxy) $lib.print(`code={$resp.code}`)'
697
+ mesgs = await core.stormlist(q, opts=opts)
698
+ self.stormIsInPrint('code=404', mesgs)
699
+ self.stormIsInWarn('Axon version does not support proxy argument', mesgs)
700
+ finally:
701
+ core.axoninfo['synapse']['version'] = oldv
702
+
657
703
  async with self.getTestCore(conf=conf) as core:
658
704
  # Proxy permission tests in this section
659
705
 
@@ -762,10 +808,15 @@ class StormHttpTest(s_test.SynTest):
762
808
  ($ok, $valu) = $sock.tx(lololol)
763
809
  return($sock.rx())
764
810
  '''
765
- opts = {'vars': {'port': port, 'proxy': None}}
811
+ opts = {'vars': {'port': port, 'proxy': True}}
766
812
  self.eq((True, ('echo', 'lololol')),
767
813
  await core.callStorm(query, opts=opts))
768
814
 
815
+ opts = {'vars': {'port': port, 'proxy': None}}
816
+ mesgs = await core.stormlist(query, opts=opts)
817
+ self.stormIsInWarn('proxy argument to $lib.null is deprecated', mesgs)
818
+ self.true(mesgs[-2][0] == 'err' and mesgs[-2][1][1]['mesg'] == "(True, ['echo', 'lololol'])")
819
+
769
820
  visi = await core.auth.addUser('visi')
770
821
 
771
822
  opts = {'user': visi.iden, 'vars': {'port': port, 'proxy': False}}
@@ -903,16 +954,10 @@ class StormHttpTest(s_test.SynTest):
903
954
  core.axoninfo['synapse']['version'] = oldv
904
955
 
905
956
  ## version check succeeds
906
- # todo: setting the synapse version can be removed once ssl_opts is released
907
- try:
908
- oldv = core.axoninfo['synapse']['version']
909
- core.axoninfo['synapse']['version'] = (oldv[0], oldv[1] + 1, oldv[2])
910
- self.eq(200, await core.callStorm(axon_queries['postfile'], opts=opts))
911
- self.eq(200, await core.callStorm(axon_queries['wget'], opts=opts))
912
- self.eq(200, await core.callStorm(axon_queries['wput'], opts=opts))
913
- self.len(1, await core.nodes(axon_queries['urlfile'], opts=opts))
914
- finally:
915
- core.axoninfo['synapse']['version'] = oldv
957
+ self.eq(200, await core.callStorm(axon_queries['postfile'], opts=opts))
958
+ self.eq(200, await core.callStorm(axon_queries['wget'], opts=opts))
959
+ self.eq(200, await core.callStorm(axon_queries['wput'], opts=opts))
960
+ self.len(1, await core.nodes(axon_queries['urlfile'], opts=opts))
916
961
 
917
962
  # verify arg precedence
918
963
 
@@ -304,9 +304,7 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
304
304
  resp = await sess.get(url)
305
305
  self.eq(resp.status, 200)
306
306
  self.true(await stream.wait(timeout=12))
307
- data = stream.getvalue()
308
- raw_mesgs = [m for m in data.split('\n') if m]
309
- msgs = [json.loads(m) for m in raw_mesgs]
307
+ msgs = stream.jsonlines()
310
308
  self.eq(msgs[0].get('httpapi'), echoiden)
311
309
  core.stormlog = False
312
310
 
@@ -1,5 +1,3 @@
1
- import json
2
-
3
1
  import synapse.exc as s_exc
4
2
 
5
3
  import synapse.tests.utils as s_test
@@ -49,10 +47,7 @@ class LogTest(s_test.SynTest):
49
47
  await core.callStorm('$lib.log.debug("struct1 message")')
50
48
  await core.callStorm('$lib.log.debug("struct2 message", extra=({"key": "valu"}))')
51
49
  self.true(await stream.wait(6))
52
-
53
- data = stream.getvalue()
54
- raw_mesgs = [m for m in data.split('\n') if m]
55
- msgs = [json.loads(m) for m in raw_mesgs]
50
+ msgs = stream.jsonlines()
56
51
  self.len(2, msgs)
57
52
  mesg = msgs[0]
58
53
  self.eq(mesg.get('logger').get('name'), 'synapse.storm.log')
@@ -704,3 +704,31 @@ class StormlibModelTest(s_test.SynTest):
704
704
  self.eq(nodes[0].get('cert'), cert3.ndef[1])
705
705
  self.isin('ssl.migration.three', nodes[0].tags)
706
706
  self.eq(nodes[0].nodedata, {'foo': None})
707
+
708
+ async def test_stormlib_model_migrations_inet_service_message_client(self):
709
+
710
+ async with self.getTestCore() as core:
711
+
712
+ await core.nodes('''[
713
+ (inet:service:message=* :client:address=1.2.3.4 :client=2.3.4.5)
714
+ (inet:service:message=* :client:address=3.4.5.6)
715
+ (inet:service:message=* :client=4.5.6.7)
716
+ ]''')
717
+
718
+ nodes = await core.nodes('''
719
+ inet:service:message
720
+ $lib.model.migration.s.inetServiceMessageClientAddress($node)
721
+ ''')
722
+
723
+ self.len(3, nodes)
724
+
725
+ for node in nodes:
726
+ self.none(node.get('client:address'))
727
+
728
+ exp = ['tcp://2.3.4.5', 'tcp://3.4.5.6', 'tcp://4.5.6.7']
729
+ self.sorteq(exp, [n.get('client') for n in nodes])
730
+
731
+ ndata = [n for n in nodes if await n.getData('migration:inet:service:message:client:address')]
732
+ self.len(1, ndata)
733
+ self.eq(ndata[0].get('client'), 'tcp://2.3.4.5')
734
+ self.eq(await ndata[0].getData('migration:inet:service:message:client:address'), 'tcp://1.2.3.4')
@@ -4920,8 +4920,7 @@ class StormTypesTest(s_test.SynTest):
4920
4920
  unixtime += 7 * MINSECS
4921
4921
  self.eq('m3', await getNextFoo())
4922
4922
  self.true(await stream.wait(6))
4923
- buf = stream.getvalue()
4924
- mesg = json.loads(buf.split('\n')[0])
4923
+ mesg = stream.jsonlines()[0]
4925
4924
  self.eq(mesg['message'], f'm3 cron {guid}')
4926
4925
  self.eq(mesg['iden'], guid)
4927
4926
 
@@ -1,5 +1,4 @@
1
1
  import os
2
- import json
3
2
  import synapse.exc as s_exc
4
3
  import synapse.common as s_common
5
4
 
@@ -253,8 +252,8 @@ class TrigTest(s_t_utils.SynTest):
253
252
  with self.getStructuredAsyncLoggerStream('synapse.storm.log', 'test trigger') as stream:
254
253
  await core.nodes('[ test:str=logit ]')
255
254
  self.true(await stream.wait(6))
256
- buf = stream.getvalue()
257
- mesg = json.loads(buf.split('\n')[-2])
255
+ msgs = stream.jsonlines()
256
+ mesg = [m for m in msgs if m.get('iden') == tdef.get('iden')][0]
258
257
  self.eq(mesg['message'], f'test trigger {tdef.get("iden")}')
259
258
  self.eq(mesg['iden'], tdef.get('iden'))
260
259
 
@@ -222,13 +222,23 @@ class BaseTest(s_t_utils.SynTest):
222
222
 
223
223
  async with self.getTestCore() as core:
224
224
 
225
- nodes = await core.nodes('[meta:source="*" :name="FOO Bar" :type=osint :url="https://foo.bar/index.html"]')
225
+ nodes = await core.nodes('''
226
+ [meta:source="*"
227
+ :name="FOO Bar"
228
+ :type=osint
229
+ :url="https://foo.bar/index.html"
230
+ :ingest:latest=20241205
231
+ :ingest:offset=17
232
+ ]
233
+ ''')
226
234
  self.len(1, nodes)
227
235
  sorc = nodes[0]
228
236
 
229
237
  self.eq(sorc.get('type'), 'osint')
230
238
  self.eq(sorc.get('name'), 'foo bar')
231
239
  self.eq(sorc.get('url'), 'https://foo.bar/index.html')
240
+ self.eq(sorc.get('ingest:offset'), 17)
241
+ self.eq(sorc.get('ingest:latest'), 1733356800000)
232
242
 
233
243
  valu = (sorc.ndef[1], ('inet:fqdn', 'woot.com'))
234
244
  nodes = await core.nodes('[meta:seen=$valu]', opts={'vars': {'valu': valu}})
@@ -330,7 +340,7 @@ class BaseTest(s_t_utils.SynTest):
330
340
  'tel:mob:telem:ipv6', 'tel:mob:telem:wifi', 'tel:mob:telem:wifi:ssid',
331
341
  'tel:mob:telem:wifi:bssid', 'tel:mob:telem:adid', 'tel:mob:telem:aaid',
332
342
  'tel:mob:telem:idfa', 'tel:mob:telem:name', 'tel:mob:telem:email',
333
- 'tel:mob:telem:acct', 'tel:mob:telem:app', 'tel:mob:telem:data',
343
+ 'tel:mob:telem:app', 'tel:mob:telem:data',
334
344
  'inet:http:request:response:time', 'inet:http:request:response:code',
335
345
  'inet:http:request:response:reason', 'inet:http:request:response:body',
336
346
  'gov:us:cage:street', 'gov:us:cage:city', 'gov:us:cage:state', 'gov:us:cage:zip',
@@ -2958,10 +2958,12 @@ class InetModelTest(s_t_utils.SynTest):
2958
2958
  :platform={ inet:service:platform=(slack,) }
2959
2959
  :url="https://v.vtx.lk/slack"
2960
2960
  :name="Synapse users slack"
2961
+ :tenant={[ inet:service:tenant=({"id": "VS-31337"}) ]}
2961
2962
  ]
2962
2963
  '''
2963
2964
  nodes = await core.nodes(q)
2964
2965
  self.len(1, nodes)
2966
+ self.nn(nodes[0].get('tenant'))
2965
2967
  self.eq(nodes[0].ndef, ('inet:service:instance', s_common.guid(('vertex', 'slack'))))
2966
2968
  self.eq(nodes[0].get('id'), 'T2XK1223Y')
2967
2969
  self.eq(nodes[0].get('platform'), platform.ndef[1])
@@ -2976,6 +2978,7 @@ class InetModelTest(s_t_utils.SynTest):
2976
2978
  :user=blackout
2977
2979
  :email=blackout@vertex.link
2978
2980
  :profile={ gen.ps.contact.email vertex.employee blackout@vertex.link }
2981
+ :tenant={[ inet:service:tenant=({"id": "VS-31337"}) ]}
2979
2982
  )
2980
2983
 
2981
2984
  (inet:service:account=(visi, account, vertex, slack)
@@ -2989,6 +2992,8 @@ class InetModelTest(s_t_utils.SynTest):
2989
2992
  accounts = await core.nodes(q)
2990
2993
  self.len(2, accounts)
2991
2994
 
2995
+ self.nn(accounts[0].get('tenant'))
2996
+
2992
2997
  profiles = await core.nodes('ps:contact')
2993
2998
  self.len(2, profiles)
2994
2999
  self.eq(profiles[0].get('email'), 'blackout@vertex.link')
@@ -3068,14 +3073,17 @@ class InetModelTest(s_t_utils.SynTest):
3068
3073
  [ inet:service:session=*
3069
3074
  :creator=$blckiden
3070
3075
  :period=(202405160900, 202405161055)
3076
+ :http:session=*
3071
3077
  ]
3072
3078
  '''
3073
3079
  opts = {'vars': {'blckiden': blckacct.ndef[1]}}
3074
3080
  nodes = await core.nodes(q, opts=opts)
3075
3081
  self.len(1, nodes)
3082
+ self.nn(nodes[0].get('http:session'))
3076
3083
  self.eq(nodes[0].get('creator'), blckacct.ndef[1])
3077
3084
  self.eq(nodes[0].get('period'), (1715850000000, 1715856900000))
3078
3085
  blcksess = nodes[0]
3086
+ self.len(1, await core.nodes('inet:service:session -> inet:http:session'))
3079
3087
 
3080
3088
  q = '''
3081
3089
  [ inet:service:login=*
@@ -3407,3 +3415,18 @@ class InetModelTest(s_t_utils.SynTest):
3407
3415
 
3408
3416
  with self.raises(s_exc.BadTypeValu):
3409
3417
  await core.nodes('[ inet:service:relationship=* :source={[it:dev:str=foo]} ]')
3418
+
3419
+ nodes = await core.nodes('''
3420
+ [ inet:service:subscription=*
3421
+ :level=vertex.synapse.enterprise
3422
+ :pay:instrument={[ econ:bank:account=* :contact={[ ps:contact=* :name=visi]} ]}
3423
+ :subscriber={[ inet:service:tenant=({"id": "VS-31337"}) ]}
3424
+ ]
3425
+ ''')
3426
+ self.len(1, nodes)
3427
+ self.eq('vertex.synapse.enterprise.', nodes[0].get('level'))
3428
+ self.eq('econ:bank:account', nodes[0].get('pay:instrument')[0])
3429
+ self.eq('inet:service:tenant', nodes[0].get('subscriber')[0])
3430
+ self.len(1, await core.nodes('inet:service:subscription -> inet:service:subscription:level:taxonomy'))
3431
+ self.len(1, await core.nodes('inet:service:subscription :pay:instrument -> econ:bank:account'))
3432
+ self.len(1, await core.nodes('inet:service:subscription :subscriber -> inet:service:tenant'))
@@ -278,12 +278,14 @@ class PsModelTest(s_t_utils.SynTest):
278
278
  :source:host=*
279
279
  :source:file=*
280
280
  :source:acct=(twitter.com, invisig0th)
281
+ :source:account=(twitter.com, invisig0th)
281
282
  ]''')
282
283
  self.len(1, nodes)
283
284
  self.len(1, await core.nodes('ps:contactlist -> it:host'))
284
285
  self.len(1, await core.nodes('ps:contactlist -> file:bytes'))
285
286
  self.len(2, await core.nodes('ps:contactlist -> ps:contact'))
286
287
  self.len(1, await core.nodes('ps:contactlist -> inet:web:acct'))
288
+ self.len(1, await core.nodes('ps:contactlist -> inet:service:account'))
287
289
 
288
290
  nodes = await core.nodes('''[
289
291
  ps:workhist = *
@@ -379,6 +379,7 @@ class RiskModelTest(s_t_utils.SynTest):
379
379
  :desc=VTX-APT1
380
380
  :tag=cno.threat.apt1
381
381
  :active=(2012,2023)
382
+ :activity=high
382
383
  :reporter=*
383
384
  :reporter:name=mandiant
384
385
  :reporter:discovered=202202
@@ -400,6 +401,7 @@ class RiskModelTest(s_t_utils.SynTest):
400
401
  self.len(1, nodes)
401
402
  self.eq('vtx-apt1', nodes[0].get('name'))
402
403
  self.eq('VTX-APT1', nodes[0].get('desc'))
404
+ self.eq(40, nodes[0].get('activity'))
403
405
  self.eq('apt1', nodes[0].get('org:name'))
404
406
  self.eq('ua', nodes[0].get('country:code'))
405
407
  self.eq('cn.shanghai', nodes[0].get('org:loc'))
@@ -546,11 +548,13 @@ class RiskModelTest(s_t_utils.SynTest):
546
548
  :cause=nature.earthquake
547
549
  :provider={[ ou:org=* :name="desert power" ]}
548
550
  :provider:name="desert power"
551
+ :attack={[ risk:attack=* ]}
549
552
  :reporter={ ou:org:name=vertex }
550
553
  :reporter:name=vertex
551
554
  ]
552
555
  ''')
553
556
  self.len(1, nodes)
557
+ self.nn(nodes[0].get('attack'))
554
558
  self.nn(nodes[0].get('reporter'))
555
559
  self.eq('the big one', nodes[0].get('name'))
556
560
  self.eq('vertex', nodes[0].get('reporter:name'))
@@ -559,6 +563,7 @@ class RiskModelTest(s_t_utils.SynTest):
559
563
  self.eq('nature.earthquake.', nodes[0].get('cause'))
560
564
  self.eq((1672531200000, 1704067200000), nodes[0].get('period'))
561
565
 
566
+ self.len(1, await core.nodes('risk:outage -> risk:attack'))
562
567
  self.len(1, await core.nodes('risk:outage -> risk:outage:cause:taxonomy'))
563
568
  self.len(1, await core.nodes('risk:outage :reporter -> ou:org +:name=vertex'))
564
569
  self.len(1, await core.nodes('risk:outage :provider -> ou:org +:name="desert power"'))