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
synapse/models/inet.py CHANGED
@@ -1530,7 +1530,8 @@ class InetModule(s_module.CoreModule):
1530
1530
  'doc': 'An object status enumeration.'}),
1531
1531
 
1532
1532
  ('inet:service:account', ('guid', {}), {
1533
- 'interfaces': ('inet:service:object',),
1533
+ 'interfaces': ('inet:service:subscriber',),
1534
+ 'template': {'service:base': 'account'},
1534
1535
  'doc': 'An account within a service platform. Accounts may be instance specific.'}),
1535
1536
 
1536
1537
  ('inet:service:relationship:type:taxonomy', ('taxonomy', {}), {
@@ -1539,6 +1540,7 @@ class InetModule(s_module.CoreModule):
1539
1540
 
1540
1541
  ('inet:service:relationship', ('guid', {}), {
1541
1542
  'interfaces': ('inet:service:object',),
1543
+ 'template': {'service:base': 'relationship'},
1542
1544
  'doc': 'A relationship between two service objects.'}),
1543
1545
 
1544
1546
  ('inet:service:permission:type:taxonomy', ('taxonomy', {}), {
@@ -1547,10 +1549,12 @@ class InetModule(s_module.CoreModule):
1547
1549
 
1548
1550
  ('inet:service:permission', ('guid', {}), {
1549
1551
  'interfaces': ('inet:service:object',),
1552
+ 'template': {'service:base': 'permission'},
1550
1553
  'doc': 'A permission which may be granted to a service account or role.'}),
1551
1554
 
1552
1555
  ('inet:service:rule', ('guid', {}), {
1553
1556
  'interfaces': ('inet:service:object',),
1557
+ 'template': {'service:base': 'rule'},
1554
1558
  'doc': 'A rule which grants or denies a permission to a service account or role.'}),
1555
1559
 
1556
1560
  ('inet:service:login', ('guid', {}), {
@@ -1563,26 +1567,32 @@ class InetModule(s_module.CoreModule):
1563
1567
 
1564
1568
  ('inet:service:session', ('guid', {}), {
1565
1569
  'interfaces': ('inet:service:object',),
1570
+ 'template': {'service:base': 'session'},
1566
1571
  'doc': 'An authenticated session.'}),
1567
1572
 
1568
1573
  ('inet:service:group', ('guid', {}), {
1569
1574
  'interfaces': ('inet:service:object',),
1575
+ 'template': {'service:base': 'group'},
1570
1576
  'doc': 'A group or role which contains member accounts.'}),
1571
1577
 
1572
1578
  ('inet:service:group:member', ('guid', {}), {
1573
1579
  'interfaces': ('inet:service:object',),
1580
+ 'template': {'service:base': 'group membership'},
1574
1581
  'doc': 'Represents a service account being a member of a group.'}),
1575
1582
 
1576
1583
  ('inet:service:channel', ('guid', {}), {
1577
1584
  'interfaces': ('inet:service:object',),
1585
+ 'template': {'service:base': 'channel'},
1578
1586
  'doc': 'A channel used to distribute messages.'}),
1579
1587
 
1580
1588
  ('inet:service:thread', ('guid', {}), {
1581
1589
  'interfaces': ('inet:service:object',),
1590
+ 'template': {'service:base': 'thread'},
1582
1591
  'doc': 'A message thread.'}),
1583
1592
 
1584
1593
  ('inet:service:channel:member', ('guid', {}), {
1585
1594
  'interfaces': ('inet:service:object',),
1595
+ 'template': {'service:base': 'channel membership'},
1586
1596
  'doc': 'Represents a service account being a member of a channel.'}),
1587
1597
 
1588
1598
  ('inet:service:message', ('guid', {}), {
@@ -1601,26 +1611,47 @@ class InetModule(s_module.CoreModule):
1601
1611
 
1602
1612
  ('inet:service:emote', ('guid', {}), {
1603
1613
  'interfaces': ('inet:service:object',),
1614
+ 'template': {'service:base': 'emote'},
1604
1615
  'doc': 'An emote or reaction by an account.'}),
1605
1616
 
1606
1617
  ('inet:service:access', ('guid', {}), {
1607
1618
  'interfaces': ('inet:service:action',),
1608
1619
  'doc': 'Represents a user access request to a service resource.'}),
1609
1620
 
1621
+ ('inet:service:tenant', ('guid', {}), {
1622
+ 'interfaces': ('inet:service:subscriber',),
1623
+ 'template': {'service:base': 'tenant'},
1624
+ 'doc': 'A tenant which groups accounts and instances.'}),
1625
+
1626
+ ('inet:service:subscription:level:taxonomy', ('taxonomy', {}), {
1627
+ 'interfaces': ('meta:taxonomy',),
1628
+ 'doc': 'A taxonomy of platform specific subscription levels.'}),
1629
+
1630
+ ('inet:service:subscription', ('guid', {}), {
1631
+ 'interfaces': ('inet:service:object',),
1632
+ 'template': {'service:base': 'subscription'},
1633
+ 'doc': 'A subscription to a service platform or instance.'}),
1634
+
1635
+ ('inet:service:subscriber', ('ndef', {'interface': 'inet:service:subscriber'}), {
1636
+ 'doc': 'A node which may subscribe to a service subscription.'}),
1637
+
1610
1638
  ('inet:service:resource:type:taxonomy', ('taxonomy', {}), {
1611
1639
  'interfaces': ('meta:taxonomy',),
1612
1640
  'doc': 'A taxonomy of inet service resource types.'}),
1613
1641
 
1614
1642
  ('inet:service:resource', ('guid', {}), {
1615
1643
  'interfaces': ('inet:service:object',),
1644
+ 'template': {'service:base': 'resource'},
1616
1645
  'doc': 'A generic resource provided by the service architecture.'}),
1617
1646
 
1618
1647
  ('inet:service:bucket', ('guid', {}), {
1619
1648
  'interfaces': ('inet:service:object',),
1649
+ 'template': {'service:base': 'bucket'},
1620
1650
  'doc': 'A file/blob storage object within a service architecture.'}),
1621
1651
 
1622
1652
  ('inet:service:bucket:item', ('guid', {}), {
1623
1653
  'interfaces': ('inet:service:object',),
1654
+ 'template': {'service:base': 'bucket item'},
1624
1655
  'doc': 'An individual file stored within a bucket.'}),
1625
1656
 
1626
1657
  ('inet:tls:handshake', ('guid', {}), {
@@ -1676,16 +1707,17 @@ class InetModule(s_module.CoreModule):
1676
1707
 
1677
1708
  ('inet:service:base', {
1678
1709
  'doc': 'Properties common to most forms within a service platform.',
1710
+ 'template': {'service:base': 'node'},
1679
1711
  'props': (
1680
1712
 
1681
1713
  ('id', ('str', {'strip': True}), {
1682
- 'doc': 'A platform specific ID.'}),
1714
+ 'doc': 'A platform specific ID which identifies the {service:base}.'}),
1683
1715
 
1684
1716
  ('platform', ('inet:service:platform', {}), {
1685
- 'doc': 'The platform which defines the node.'}),
1717
+ 'doc': 'The platform which defines the {service:base}.'}),
1686
1718
 
1687
1719
  ('instance', ('inet:service:instance', {}), {
1688
- 'doc': 'The platform instance which defines the node.'}),
1720
+ 'doc': 'The platform instance which defines the {service:base}.'}),
1689
1721
  ),
1690
1722
  }),
1691
1723
 
@@ -1693,23 +1725,34 @@ class InetModule(s_module.CoreModule):
1693
1725
 
1694
1726
  'doc': 'Properties common to objects within a service platform.',
1695
1727
  'interfaces': ('inet:service:base',),
1728
+ 'template': {'service:base': 'object'},
1696
1729
  'props': (
1697
1730
 
1698
1731
  ('status', ('inet:service:object:status', {}), {
1699
- 'doc': 'The status of this object.'}),
1732
+ 'doc': 'The status of the {service:base}.'}),
1700
1733
 
1701
1734
  ('period', ('ival', {}), {
1702
- 'doc': 'The period when the object existed.'}),
1735
+ 'doc': 'The period when the {service:base} existed.'}),
1703
1736
 
1704
1737
  ('creator', ('inet:service:account', {}), {
1705
- 'doc': 'The service account which created the object.'}),
1738
+ 'doc': 'The service account which created the {service:base}.'}),
1706
1739
 
1707
1740
  ('remover', ('inet:service:account', {}), {
1708
- 'doc': 'The service account which removed or decommissioned the object.'}),
1741
+ 'doc': 'The service account which removed or decommissioned the {service:base}.'}),
1709
1742
 
1710
1743
  ),
1711
1744
  }),
1712
1745
 
1746
+ ('inet:service:subscriber', {
1747
+ 'doc': 'Properties common to the nodes which subscribe to services.',
1748
+ 'interfaces': ('inet:service:object',),
1749
+ 'template': {'service:base': 'subscriber'},
1750
+ 'props': (
1751
+ ('profile', ('ps:contact', {}), {
1752
+ 'doc': 'The primary contact information for the {service:base}.'}),
1753
+ ),
1754
+ }),
1755
+
1713
1756
  ('inet:service:action', {
1714
1757
 
1715
1758
  'doc': 'Properties common to events within a service platform.',
@@ -3590,21 +3633,21 @@ class InetModule(s_module.CoreModule):
3590
3633
 
3591
3634
  ('owner', ('inet:service:account', {}), {
3592
3635
  'doc': 'The service account which owns the instance.'}),
3636
+
3637
+ ('tenant', ('inet:service:tenant', {}), {
3638
+ 'doc': 'The tenant which contains the instance.'}),
3593
3639
  )),
3594
3640
 
3595
3641
  ('inet:service:account', {}, (
3596
3642
 
3597
- ('id', ('str', {'strip': True}), {
3598
- 'doc': 'A platform specific ID used to identify the account.'}),
3599
-
3600
3643
  ('user', ('inet:user', {}), {
3601
3644
  'doc': 'The current user name of the account.'}),
3602
3645
 
3603
3646
  ('email', ('inet:email', {}), {
3604
3647
  'doc': 'The current email address associated with the account.'}),
3605
3648
 
3606
- ('profile', ('ps:contact', {}), {
3607
- 'doc': 'Current profile details associated with the account.'}),
3649
+ ('tenant', ('inet:service:tenant', {}), {
3650
+ 'doc': 'The tenant which contains the account.'}),
3608
3651
  )),
3609
3652
 
3610
3653
  ('inet:service:relationship:type:taxonomy', {}, ()),
@@ -3621,10 +3664,7 @@ class InetModule(s_module.CoreModule):
3621
3664
  'doc': 'The type of relationship between the source and the target.'}),
3622
3665
  )),
3623
3666
 
3624
- ('inet:service:group', {}, ( # inet:service:object
3625
-
3626
- ('id', ('str', {'strip': True}), {
3627
- 'doc': 'A platform specific ID used to identify the group.'}),
3667
+ ('inet:service:group', {}, (
3628
3668
 
3629
3669
  ('name', ('inet:group', {}), {
3630
3670
  'doc': 'The name of the group on this platform.'}),
@@ -3674,14 +3714,14 @@ class InetModule(s_module.CoreModule):
3674
3714
 
3675
3715
  ('inet:service:session', {}, (
3676
3716
 
3677
- ('id', ('str', {'strip': True}), {
3678
- 'doc': 'The service specific session id.'}),
3679
-
3680
3717
  ('creator', ('inet:service:account', {}), {
3681
3718
  'doc': 'The account which authenticated to create the session.'}),
3682
3719
 
3683
3720
  ('period', ('ival', {}), {
3684
3721
  'doc': 'The period where the session was valid.'}),
3722
+
3723
+ ('http:session', ('inet:http:session', {}), {
3724
+ 'doc': 'The HTTP session associated with the service session.'}),
3685
3725
  )),
3686
3726
 
3687
3727
  ('inet:service:login', {}, (
@@ -3742,7 +3782,8 @@ class InetModule(s_module.CoreModule):
3742
3782
  'doc': 'The name of the place that the message was sent from.'}),
3743
3783
 
3744
3784
  ('client:address', ('inet:client', {}), {
3745
- 'doc': 'The client address that the message was sent from.'}),
3785
+ 'deprecated': True,
3786
+ 'doc': 'Deprecated. Please use :client'}),
3746
3787
 
3747
3788
  ('client:software', ('it:prod:softver', {}), {
3748
3789
  'doc': 'The client software version used to send the message.'}),
@@ -3864,6 +3905,22 @@ class InetModule(s_module.CoreModule):
3864
3905
  ('type', ('int', {'enums': svcaccesstypes}), {
3865
3906
  'doc': 'The type of access requested.'}),
3866
3907
  )),
3908
+
3909
+ ('inet:service:tenant', {}, ()),
3910
+
3911
+ ('inet:service:subscription:level:taxonomy', {}, ()),
3912
+
3913
+ ('inet:service:subscription', {}, (
3914
+
3915
+ ('level', ('inet:service:subscription:level:taxonomy', {}), {
3916
+ 'doc': 'A platform specific subscription level.'}),
3917
+
3918
+ ('pay:instrument', ('econ:pay:instrument', {}), {
3919
+ 'doc': 'The primary payment instrument used to pay for the subscription.'}),
3920
+
3921
+ ('subscriber', ('inet:service:subscriber', {}), {
3922
+ 'doc': 'The subscriber who owns the subscription.'}),
3923
+ )),
3867
3924
  ),
3868
3925
  }),
3869
3926
  )
synapse/models/person.py CHANGED
@@ -377,10 +377,12 @@ class PsModule(s_module.CoreModule):
377
377
  'doc': 'The service accounts associated with this contact.'}),
378
378
 
379
379
  ('web:acct', ('inet:web:acct', {}), {
380
- 'doc': 'The social media account for this contact.',
380
+ 'deprecated': True,
381
+ 'doc': 'Deprecated. Use :service:accounts.',
381
382
  }),
382
383
  ('web:group', ('inet:web:group', {}), {
383
- 'doc': 'A web group representing this contact.',
384
+ 'deprecated': True,
385
+ 'doc': 'Deprecated. Use inet:service:group:profile to link to a group.',
384
386
  }),
385
387
  ('birth:place', ('geo:place', {}), {
386
388
  'doc': 'A fully resolved place of birth for this contact.',
@@ -463,7 +465,8 @@ class PsModule(s_module.CoreModule):
463
465
  'doc': 'An array of secondary/associated email addresses.',
464
466
  }),
465
467
  ('web:accts', ('array', {'type': 'inet:web:acct', 'uniq': True, 'sorted': True}), {
466
- 'doc': 'An array of secondary/associated web accounts.',
468
+ 'deprecated': True,
469
+ 'doc': 'Deprecated. Use :service:accounts.',
467
470
  }),
468
471
  ('id:numbers', ('array', {'type': 'ou:id:number', 'uniq': True, 'sorted': True}), {
469
472
  'doc': 'An array of secondary/associated IDs.',
@@ -511,7 +514,11 @@ class PsModule(s_module.CoreModule):
511
514
  'doc': 'The file from which the contact list was extracted.',
512
515
  }),
513
516
  ('source:acct', ('inet:web:acct', {}), {
514
- 'doc': 'The web account from which the contact list was extracted.',
517
+ 'deprecated': True,
518
+ 'doc': 'Deprecated. Use :source:account.',
519
+ }),
520
+ ('source:account', ('inet:service:account', {}), {
521
+ 'doc': 'The service account from which the contact list was extracted.',
515
522
  }),
516
523
  )),
517
524
 
synapse/models/risk.py CHANGED
@@ -279,6 +279,9 @@ class RiskModule(s_module.CoreModule):
279
279
  ('active', ('ival', {}), {
280
280
  'doc': 'An interval for when the threat cluster is assessed to have been active.'}),
281
281
 
282
+ ('activity', ('meta:activity', {}), {
283
+ 'doc': 'The most recently assessed activity level of the threat cluster.'}),
284
+
282
285
  ('reporter', ('ou:org', {}), {
283
286
  'doc': 'The organization reporting on the threat cluster.'}),
284
287
 
@@ -1078,6 +1081,9 @@ class RiskModule(s_module.CoreModule):
1078
1081
  'ex': 'nature.earthquake',
1079
1082
  'doc': 'The outage cause type.'}),
1080
1083
 
1084
+ ('attack', ('risk:attack', {}), {
1085
+ 'doc': 'An attack which caused the outage.'}),
1086
+
1081
1087
  ('provider', ('ou:org', {}), {
1082
1088
  'doc': 'The organization which experienced the outage event.'}),
1083
1089
 
synapse/models/syn.py CHANGED
@@ -83,23 +83,28 @@ class SynModule(s_module.CoreModule):
83
83
 
84
84
  async def _liftRuntSynCmd(self, full, valu=None, cmpr=None, view=None):
85
85
 
86
- genr = self.core.stormcmds.values
86
+ def iterStormCmds():
87
+ for item in self.core.getStormCmds():
88
+ yield item[1]
87
89
 
88
- async for node in self._doRuntLift(genr, full, valu, cmpr):
90
+ async for node in self._doRuntLift(iterStormCmds, full, valu, cmpr):
89
91
  yield node
90
92
 
91
93
  async def _liftRuntSynCron(self, full, valu=None, cmpr=None, view=None):
92
94
 
93
- genr = self.core.agenda.appts.values
95
+ def iterAppts():
96
+ for item in self.core.agenda.list():
97
+ yield item[1]
94
98
 
95
- async for node in self._doRuntLift(genr, full, valu, cmpr):
99
+ async for node in self._doRuntLift(iterAppts, full, valu, cmpr):
96
100
  yield node
97
101
 
98
102
  async def _liftRuntSynForm(self, full, valu=None, cmpr=None, view=None):
99
103
 
100
- genr = self.model.forms.values
104
+ def getForms():
105
+ return list(self.model.forms.values())
101
106
 
102
- async for node in self._doRuntLift(genr, full, valu, cmpr):
107
+ async for node in self._doRuntLift(getForms, full, valu, cmpr):
103
108
  yield node
104
109
 
105
110
  async def _liftRuntSynProp(self, full, valu=None, cmpr=None, view=None):
@@ -111,24 +116,29 @@ class SynModule(s_module.CoreModule):
111
116
 
112
117
  async def _liftRuntSynType(self, full, valu=None, cmpr=None, view=None):
113
118
 
114
- genr = self.model.types.values
119
+ def getTypes():
120
+ return list(self.model.types.values())
115
121
 
116
- async for node in self._doRuntLift(genr, full, valu, cmpr):
122
+ async for node in self._doRuntLift(getTypes, full, valu, cmpr):
117
123
  yield node
118
124
 
119
125
  async def _liftRuntSynTagProp(self, full, valu=None, cmpr=None, view=None):
120
126
 
121
- genr = self.model.tagprops.values
127
+ def getTagProps():
128
+ return list(self.model.tagprops.values())
122
129
 
123
- async for node in self._doRuntLift(genr, full, valu, cmpr):
130
+ async for node in self._doRuntLift(getTagProps, full, valu, cmpr):
124
131
  yield node
125
132
 
126
133
  async def _liftRuntSynTrigger(self, full, valu=None, cmpr=None, view=None):
127
134
 
128
135
  view = self.core.getView(iden=view)
129
- genr = view.triggers.triggers.values
130
136
 
131
- async for node in self._doRuntLift(genr, full, valu, cmpr):
137
+ def iterTriggers():
138
+ for item in view.triggers.list():
139
+ yield item[1]
140
+
141
+ async for node in self._doRuntLift(iterTriggers, full, valu, cmpr):
132
142
  yield node
133
143
 
134
144
  async def _doRuntLift(self, genr, full, valu=None, cmpr=None):
synapse/models/telco.py CHANGED
@@ -376,7 +376,9 @@ class TelcoModule(s_module.CoreModule):
376
376
  # User related data
377
377
  ('name', ('ps:name', {}), {}),
378
378
  ('email', ('inet:email', {}), {}),
379
- ('acct', ('inet:web:acct', {}), {}),
379
+ ('acct', ('inet:web:acct', {}), {
380
+ 'doc': 'Deprecated, use :account.',
381
+ 'deprecated': True}),
380
382
 
381
383
  ('account', ('inet:service:account', {}), {
382
384
  'doc': 'The service account which is associated with the tracked device.'}),
@@ -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', ''))
@@ -1,6 +1,5 @@
1
1
  import os
2
2
  import copy
3
- import json
4
3
  import time
5
4
  import asyncio
6
5
  import hashlib
@@ -36,10 +35,6 @@ from synapse.tests.utils import alist
36
35
 
37
36
  logger = logging.getLogger(__name__)
38
37
 
39
- def jsonlines(text):
40
- lines = [k for k in text.split('\n') if k]
41
- return [json.loads(line) for line in lines]
42
-
43
38
  class CortexTest(s_t_utils.SynTest):
44
39
  '''
45
40
  The tests that should be run with different types of layers
@@ -1117,8 +1112,7 @@ class CortexTest(s_t_utils.SynTest):
1117
1112
  ''')
1118
1113
  self.true(await stream.wait(6))
1119
1114
 
1120
- buf = stream.getvalue()
1121
- mesg = json.loads(buf.split('\n')[0])
1115
+ mesg = stream.jsonlines()[0]
1122
1116
  self.eq(mesg.get('message'), f'Running dmon {iden}')
1123
1117
  self.eq(mesg.get('iden'), iden)
1124
1118
 
@@ -3368,8 +3362,7 @@ class CortexBasicTest(s_t_utils.SynTest):
3368
3362
  await alist(core.storm('help foo', opts={'show': ('init', 'fini', 'print',)}))
3369
3363
  self.true(await stream.wait(4))
3370
3364
 
3371
- buf = stream.getvalue()
3372
- mesg = json.loads(buf.split('\n')[0])
3365
+ mesg = stream.jsonlines()[0]
3373
3366
  self.eq(mesg.get('view'), view)
3374
3367
 
3375
3368
  async def test_strict(self):
@@ -4030,6 +4023,58 @@ class CortexBasicTest(s_t_utils.SynTest):
4030
4023
  gdef = await core.callStorm('return($lib.graph.add(({"name": "def", "permissions": {"default": 0}})))')
4031
4024
  self.eq(0, gdef['permissions']['default'])
4032
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
+
4033
4078
  async def test_storm_two_level_assignment(self):
4034
4079
  async with self.getTestCore() as core:
4035
4080
  q = '$foo=baz $bar=$foo [test:str=$bar]'
@@ -7904,8 +7949,7 @@ class CortexBasicTest(s_t_utils.SynTest):
7904
7949
  self.eq('admin', whoami)
7905
7950
  self.eq('lowuser', udef.get('name'))
7906
7951
 
7907
- raw_mesgs = [m for m in stream.getvalue().split('\n') if m]
7908
- msgs = [json.loads(m) for m in raw_mesgs]
7952
+ msgs = stream.jsonlines()
7909
7953
  mesg = [m for m in msgs if 'Added user' in m.get('message')][0]
7910
7954
  self.eq('Added user=lowuser', mesg.get('message'))
7911
7955
  self.eq('admin', mesg.get('username'))
@@ -7919,8 +7963,7 @@ class CortexBasicTest(s_t_utils.SynTest):
7919
7963
  msgs.append(mesg)
7920
7964
  self.stormHasNoWarnErr(msgs)
7921
7965
 
7922
- raw_mesgs = [m for m in stream.getvalue().split('\n') if m]
7923
- msgs = [json.loads(m) for m in raw_mesgs]
7966
+ msgs = stream.jsonlines()
7924
7967
  mesg = [m for m in msgs if 'Set admin' in m.get('message')][0]
7925
7968
  self.isin('Set admin=True for lowuser', mesg.get('message'))
7926
7969
  self.eq('admin', mesg.get('username'))
@@ -8128,7 +8171,7 @@ class CortexBasicTest(s_t_utils.SynTest):
8128
8171
 
8129
8172
  data = stream.getvalue()
8130
8173
  self.notin('Timeout', data)
8131
- msgs = jsonlines(data)
8174
+ msgs = stream.jsonlines()
8132
8175
  self.len(2, msgs)
8133
8176
 
8134
8177
  self.eq(msgs[0].get('message'), f'Offloading Storm query to mirror 01.core.{ahanet}.')
@@ -8147,7 +8190,7 @@ class CortexBasicTest(s_t_utils.SynTest):
8147
8190
 
8148
8191
  data = stream.getvalue()
8149
8192
  self.notin('Timeout', data)
8150
- msgs = jsonlines(data)
8193
+ msgs = stream.jsonlines()
8151
8194
  self.len(2, msgs)
8152
8195
 
8153
8196
  self.eq(msgs[0].get('message'), f'Offloading Storm query to mirror 01.core.{ahanet}.')
@@ -8166,7 +8209,7 @@ class CortexBasicTest(s_t_utils.SynTest):
8166
8209
 
8167
8210
  data = stream.getvalue()
8168
8211
  self.notin('Timeout', data)
8169
- msgs = jsonlines(data)
8212
+ msgs = stream.jsonlines()
8170
8213
  self.len(2, msgs)
8171
8214
 
8172
8215
  self.eq(msgs[0].get('message'), f'Offloading Storm query to mirror 01.core.{ahanet}.')
@@ -8185,7 +8228,7 @@ class CortexBasicTest(s_t_utils.SynTest):
8185
8228
 
8186
8229
  data = stream.getvalue()
8187
8230
  self.notin('Timeout', data)
8188
- msgs = jsonlines(data)
8231
+ msgs = stream.jsonlines()
8189
8232
  self.len(2, msgs)
8190
8233
 
8191
8234
  self.eq(msgs[0].get('message'), f'Offloading Storm query to mirror 01.core.{ahanet}.')
@@ -1,4 +1,3 @@
1
- import json
2
1
  import asyncio
3
2
  import hashlib
4
3
  import datetime
@@ -9,8 +8,6 @@ import synapse.exc as s_exc
9
8
  import synapse.common as s_common
10
9
  import synapse.tests.utils as s_t_utils
11
10
 
12
- import synapse.lib.hive as s_hive
13
- import synapse.lib.lmdbslab as s_lmdbslab
14
11
  import synapse.tools.backup as s_tools_backup
15
12
 
16
13
  import synapse.lib.agenda as s_agenda
@@ -401,9 +398,7 @@ class AgendaTest(s_t_utils.SynTest):
401
398
  self.eq((12, 'bar'), await asyncio.wait_for(core.callStorm('return($lib.queue.gen(visi).pop(wait=$lib.true))'), timeout=5))
402
399
  core.stormlog = False
403
400
 
404
- data = stream.getvalue()
405
- raw_mesgs = [m for m in data.split('\n') if m]
406
- msgs = [json.loads(m) for m in raw_mesgs]
401
+ msgs = stream.jsonlines()
407
402
  msgs = [m for m in msgs if m['text'] == '$lib.queue.gen(visi).put(bar)']
408
403
  self.gt(len(msgs), 0)
409
404
  for m in msgs:
@@ -3113,6 +3113,12 @@ class AstTest(s_test.SynTest):
3113
3113
  off, end = errm[1][1]['highlight']['offsets']
3114
3114
  self.eq('haha', text[off:end])
3115
3115
 
3116
+ text = '$lib.newp'
3117
+ msgs = await core.stormlist(text)
3118
+ errm = [m for m in msgs if m[0] == 'err'][0]
3119
+ off, end = errm[1][1]['highlight']['offsets']
3120
+ self.eq('newp', text[off:end])
3121
+
3116
3122
  async def test_ast_bulkedges(self):
3117
3123
 
3118
3124
  async with self.getTestCore() as core: