synapse 2.220.0__py311-none-any.whl → 2.222.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 (52) hide show
  1. synapse/cortex.py +34 -14
  2. synapse/data/lark/storm.lark +9 -6
  3. synapse/lib/ast.py +8 -2
  4. synapse/lib/layer.py +149 -8
  5. synapse/lib/parser.py +1 -0
  6. synapse/lib/rstorm.py +83 -2
  7. synapse/lib/schemas.py +4 -0
  8. synapse/lib/snap.py +21 -13
  9. synapse/lib/stormhttp.py +10 -10
  10. synapse/lib/stormlib/aha.py +3 -3
  11. synapse/lib/stormlib/auth.py +11 -11
  12. synapse/lib/stormlib/cell.py +1 -1
  13. synapse/lib/stormlib/cortex.py +10 -10
  14. synapse/lib/stormlib/env.py +4 -5
  15. synapse/lib/stormlib/ethereum.py +1 -1
  16. synapse/lib/stormlib/gen.py +3 -3
  17. synapse/lib/stormlib/hex.py +2 -2
  18. synapse/lib/stormlib/imap.py +2 -2
  19. synapse/lib/stormlib/infosec.py +2 -2
  20. synapse/lib/stormlib/iters.py +2 -2
  21. synapse/lib/stormlib/model.py +5 -5
  22. synapse/lib/stormlib/notifications.py +1 -1
  23. synapse/lib/stormlib/oauth.py +2 -2
  24. synapse/lib/stormlib/project.py +3 -3
  25. synapse/lib/stormlib/scrape.py +2 -1
  26. synapse/lib/stormlib/smtp.py +3 -3
  27. synapse/lib/stormlib/stats.py +2 -2
  28. synapse/lib/stormlib/stix.py +2 -2
  29. synapse/lib/stormlib/utils.py +19 -0
  30. synapse/lib/stormlib/vault.py +1 -1
  31. synapse/lib/stormlib/xml.py +2 -2
  32. synapse/lib/stormlib/yaml.py +1 -1
  33. synapse/lib/stormtypes.py +182 -64
  34. synapse/lib/version.py +2 -2
  35. synapse/models/orgs.py +3 -0
  36. synapse/tests/test_lib_grammar.py +4 -4
  37. synapse/tests/test_lib_layer.py +86 -67
  38. synapse/tests/test_lib_rstorm.py +180 -0
  39. synapse/tests/test_lib_storm.py +80 -1
  40. synapse/tests/test_lib_stormlib_auth.py +84 -0
  41. synapse/tests/test_lib_stormlib_cortex.py +1 -0
  42. synapse/tests/test_lib_stormlib_env.py +3 -1
  43. synapse/tests/test_lib_stormlib_utils.py +10 -0
  44. synapse/tests/test_lib_stormtypes.py +576 -2
  45. synapse/tests/test_model_orgs.py +6 -1
  46. synapse/tools/aha/list.py +9 -9
  47. synapse/tools/aha/provision/service.py +2 -2
  48. {synapse-2.220.0.dist-info → synapse-2.222.0.dist-info}/METADATA +1 -1
  49. {synapse-2.220.0.dist-info → synapse-2.222.0.dist-info}/RECORD +52 -52
  50. {synapse-2.220.0.dist-info → synapse-2.222.0.dist-info}/WHEEL +0 -0
  51. {synapse-2.220.0.dist-info → synapse-2.222.0.dist-info}/licenses/LICENSE +0 -0
  52. {synapse-2.220.0.dist-info → synapse-2.222.0.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,7 @@ import synapse.axon as s_axon
17
17
  import synapse.common as s_common
18
18
 
19
19
  import synapse.lib.json as s_json
20
+ import synapse.lib.node as s_node
20
21
  import synapse.lib.time as s_time
21
22
  import synapse.lib.storm as s_storm
22
23
  import synapse.lib.hashset as s_hashset
@@ -884,13 +885,32 @@ class StormTypesTest(s_test.SynTest):
884
885
  self.eq(2, await core.callStorm('return($lib.len($lib.layer.get().getStorNodes()))', opts=opts))
885
886
 
886
887
  await core.nodes('[ media:news=c0dc5dc1f7c3d27b725ef3015422f8e2 +(refs)> { inet:ipv4=1.2.3.4 } ]')
888
+ expN1 = [('refs', '20153b758f9d5eaaa38e4f4a65c36da797c3e59e549620fa7c4895e1a920991f')]
889
+ expN2 = [('refs', 'ddf7f87c0164d760e8e1e5cd2cae2fee96868a3cf184f6dab9154e31ad689528')]
890
+
887
891
  edges = await core.callStorm('''
888
892
  $edges = ([])
889
893
  media:news=c0dc5dc1f7c3d27b725ef3015422f8e2
890
894
  for $i in $lib.layer.get().getEdgesByN1($node.iden()) { $edges.append($i) }
891
895
  fini { return($edges) }
892
896
  ''')
893
- self.eq([('refs', '20153b758f9d5eaaa38e4f4a65c36da797c3e59e549620fa7c4895e1a920991f')], edges)
897
+ self.eq(expN1, edges)
898
+
899
+ edges = await core.callStorm('''
900
+ $edges = ([])
901
+ media:news=c0dc5dc1f7c3d27b725ef3015422f8e2
902
+ for $i in $lib.layer.get().getEdgesByN1($node.iden(), verb=refs) { $edges.append($i) }
903
+ fini { return($edges) }
904
+ ''')
905
+ self.eq(expN1, edges)
906
+
907
+ edges = await core.callStorm('''
908
+ $edges = ([])
909
+ media:news=c0dc5dc1f7c3d27b725ef3015422f8e2
910
+ for $i in $lib.layer.get().getEdgesByN1($node.iden(), verb=newp) { $edges.append($i) }
911
+ fini { return($edges) }
912
+ ''')
913
+ self.eq([], edges)
894
914
 
895
915
  edges = await core.callStorm('''
896
916
  $edges = ([])
@@ -898,7 +918,37 @@ class StormTypesTest(s_test.SynTest):
898
918
  for $i in $lib.layer.get().getEdgesByN2($node.iden()) { $edges.append($i) }
899
919
  fini { return($edges) }
900
920
  ''')
901
- self.eq([('refs', 'ddf7f87c0164d760e8e1e5cd2cae2fee96868a3cf184f6dab9154e31ad689528')], edges)
921
+ self.eq(expN2, edges)
922
+
923
+ edges = await core.callStorm('''
924
+ $edges = ([])
925
+ inet:ipv4=1.2.3.4
926
+ for $i in $lib.layer.get().getEdgesByN2($node.iden(), verb=refs) { $edges.append($i) }
927
+ fini { return($edges) }
928
+ ''')
929
+ self.eq(expN2, edges)
930
+
931
+ edges = await core.callStorm('''
932
+ $edges = ([])
933
+ inet:ipv4=1.2.3.4
934
+ for $i in $lib.layer.get().getEdgesByN2($node.iden(), verb=newp) { $edges.append($i) }
935
+ fini { return($edges) }
936
+ ''')
937
+ self.eq([], edges)
938
+
939
+ ret = await core.callStorm('''
940
+ $n1 = { media:news=c0dc5dc1f7c3d27b725ef3015422f8e2 return($node.iden()) }
941
+ $n2 = { inet:ipv4=1.2.3.4 return($node.iden()) }
942
+ return($lib.layer.get().hasEdge($n1, refs, $n2))
943
+ ''')
944
+ self.true(ret)
945
+
946
+ ret = await core.callStorm('''
947
+ $n1 = { media:news=c0dc5dc1f7c3d27b725ef3015422f8e2 return($node.iden()) }
948
+ $n2 = { inet:ipv4=1.2.3.4 return($node.iden()) }
949
+ return($lib.layer.get().hasEdge($n1, newp, $n2))
950
+ ''')
951
+ self.false(ret)
902
952
 
903
953
  edges = await core.callStorm('''
904
954
  $edges = ([])
@@ -1767,6 +1817,460 @@ class StormTypesTest(s_test.SynTest):
1767
1817
  await visi.addRule((True, ('layer', 'read')), gateiden=layriden)
1768
1818
  await core.callStorm('return($lib.layer.get($layriden).getStorNode($iden))', opts=opts)
1769
1819
 
1820
+ async def test_storm_layer_getstornodesbyprop(self):
1821
+ async with self.getTestCore() as core:
1822
+ nodes = await core.nodes('[ test:str=foobar :hehe=foobaz ]')
1823
+ self.len(1, nodes)
1824
+
1825
+ buid00 = nodes[0].iden()
1826
+ sode00 = {
1827
+ 'form': 'test:str',
1828
+ 'props': {
1829
+ '.created': (nodes[0].get('.created'), 21),
1830
+ 'hehe': ('foobaz', 1)
1831
+ },
1832
+ 'valu': ('foobar', 1),
1833
+ }
1834
+ expval00 = (buid00, sode00)
1835
+
1836
+ nodes = await core.nodes('[ test:str=boobar :hehe=boobaz ]')
1837
+ self.len(1, nodes)
1838
+
1839
+ buid01 = nodes[0].iden()
1840
+ sode01 = {
1841
+ 'form': 'test:str',
1842
+ 'props': {
1843
+ '.created': (nodes[0].get('.created'), 21),
1844
+ 'hehe': ('boobaz', 1)
1845
+ },
1846
+ 'valu': ('boobar', 1),
1847
+ }
1848
+ expval01 = (buid01, sode01)
1849
+
1850
+ # just prop
1851
+ q = '''
1852
+ $sodes = ([])
1853
+ for ($buid, $sode) in $lib.layer.get().getStorNodesByProp(test:str:hehe) {
1854
+ $sodes.append(($buid, $sode))
1855
+ }
1856
+ return($sodes)
1857
+ '''
1858
+ sodes = await core.callStorm(q)
1859
+ self.len(2, sodes)
1860
+ self.sorteq(sodes, (expval00, expval01))
1861
+
1862
+ # prop with propvalu
1863
+ q = '''
1864
+ $sodes = ([])
1865
+ for ($buid, $sode) in $lib.layer.get().getStorNodesByProp(test:str:hehe, propvalu=foobaz) {
1866
+ $sodes.append(($buid, $sode))
1867
+ }
1868
+ return($sodes)
1869
+ '''
1870
+ sodes = await core.callStorm(q)
1871
+ self.len(1, sodes)
1872
+ self.eq(sodes[0], expval00)
1873
+
1874
+ # just form
1875
+ q = '''
1876
+ $sodes = ([])
1877
+ for ($buid, $sode) in $lib.layer.get().getStorNodesByProp(test:str) {
1878
+ $sodes.append(($buid, $sode))
1879
+ }
1880
+ return($sodes)
1881
+ '''
1882
+ sodes = await core.callStorm(q)
1883
+ self.len(2, sodes)
1884
+ self.sorteq(sodes, (expval00, expval01))
1885
+
1886
+ # form with valu
1887
+ q = '''
1888
+ $sodes = ([])
1889
+ for ($buid, $sode) in $lib.layer.get().getStorNodesByProp(test:str, propvalu=boobar) {
1890
+ $sodes.append(($buid, $sode))
1891
+ }
1892
+ return($sodes)
1893
+ '''
1894
+ sodes = await core.callStorm(q)
1895
+ self.len(1, sodes)
1896
+ self.eq(sodes[0], expval01)
1897
+
1898
+ # Non-existent prop
1899
+ msgs = await core.stormlist('for $item in $lib.layer.get().getStorNodesByProp(test:str:_custom) {}')
1900
+ self.stormIsInErr('The property test:str:_custom does not exist.', msgs)
1901
+
1902
+ async def test_storm_layer_setstornodeprop(self):
1903
+ async with self.getTestCore() as core:
1904
+
1905
+ nodes = await core.nodes('[ test:str=foo :hehe=bar ]')
1906
+ self.len(1, nodes)
1907
+ self.eq(nodes[0].repr(), 'foo')
1908
+ self.eq(nodes[0].get('hehe'), 'bar')
1909
+
1910
+ msgs = await core.stormlist('test:str $lib.layer.get().setStorNodeProp($node.iden(), test:str:hehe, baz)')
1911
+ self.stormHasNoWarnErr(msgs)
1912
+
1913
+ nodes = await core.nodes('test:str')
1914
+ self.len(1, nodes)
1915
+ self.eq(nodes[0].repr(), 'foo')
1916
+ self.eq(nodes[0].get('hehe'), 'baz')
1917
+
1918
+ # no test:str:newp prop
1919
+ q = '''
1920
+ [ test:str=foobar00 ]
1921
+ $lib.layer.get().setStorNodeProp($node.iden(), test:str:newp, bar00)
1922
+ '''
1923
+ msgs = await core.stormlist(q)
1924
+ self.stormIsInErr('No property named test:str:newp.', msgs)
1925
+
1926
+ # Bad type
1927
+ msgs = await core.stormlist('[ test:str=foobar01 ] $lib.layer.get().setStorNodeProp($node.iden(), test:str:tick, newp)')
1928
+ self.stormIsInErr('Unknown time format for newp', msgs)
1929
+
1930
+ # insufficient perms
1931
+ lowuser = await core.auth.addUser('lowuser')
1932
+ await lowuser.addRule((True, ('node', 'add', 'test:str')))
1933
+
1934
+ q = '''
1935
+ [ test:str=foobar02 ]
1936
+ $lib.layer.get().setStorNodeProp($node.iden(), test:str:hehe, baz02)
1937
+ '''
1938
+ msgs = await core.stormlist(q, opts={'user': lowuser.iden})
1939
+ self.stormIsInErr('setStorNodeProp() requires admin privileges.', msgs)
1940
+
1941
+ # readonly layer
1942
+ layer = core.view.layers[0]
1943
+ await layer.setLayerInfo('readonly', True)
1944
+ msgs = await core.stormlist('test:str $lib.layer.get().setStorNodeProp($node.iden(), test:str:hehe, baz)')
1945
+ self.stormIsInErr(f'Layer {layer.iden} is read only!', msgs)
1946
+
1947
+ async def test_storm_layer_delstornode(self):
1948
+ async with self.getTestCore() as core:
1949
+ await core.addTagProp('score00', ('int', {}), {})
1950
+ await core.addTagProp('score01', ('int', {}), {})
1951
+ q = '''
1952
+ [ test:str=foo
1953
+ :hehe=bar
1954
+ +#foo
1955
+ +#foo.bar=now
1956
+ +#foo.baz:score00=10
1957
+ +#foo.baz:score01=20
1958
+
1959
+ <(seen)+ {[ meta:source=* :name=seen]}
1960
+ +(refs)> {[ meta:source=* :name=refs]}
1961
+ ]
1962
+
1963
+ $node.data.set(foo, foo)
1964
+ $node.data.set(bar, bar)
1965
+ $node.data.set(baz, baz)
1966
+ '''
1967
+ nodes = await core.nodes(q)
1968
+ self.len(1, nodes)
1969
+ opts = {'vars': {'iden': nodes[0].iden()}}
1970
+ created = nodes[0].get('.created')
1971
+ foobar = nodes[0].get('#foo.bar')
1972
+
1973
+ sode = await core.callStorm('return($lib.layer.get().getStorNode($iden))', opts=opts)
1974
+ self.eq(sode, {
1975
+ 'form': 'test:str',
1976
+ 'props': {'.created': (created, 21), 'hehe': ('bar', 1)},
1977
+ 'tagprops': {
1978
+ 'foo.baz': {
1979
+ 'score00': (10, 9),
1980
+ 'score01': (20, 9)
1981
+ }
1982
+ },
1983
+ 'tags': {
1984
+ 'foo': (None, None),
1985
+ 'foo.bar': foobar,
1986
+ 'foo.baz': (None, None)
1987
+ },
1988
+ 'valu': ('foo', 1)
1989
+ })
1990
+
1991
+ msgs = await core.stormlist('$lib.layer.get().delStorNode($iden)', opts=opts)
1992
+ self.stormHasNoWarnErr(msgs)
1993
+
1994
+ sode = await core.callStorm('return($lib.layer.get().getStorNode($iden))', opts=opts)
1995
+ self.eq(sode, {})
1996
+
1997
+ q = '''
1998
+ $data = ([])
1999
+ for $item in $lib.layer.get().getNodeData($iden) {
2000
+ $data.append($item)
2001
+ }
2002
+ return($data)
2003
+ '''
2004
+ nodedata = await core.callStorm(q, opts=opts)
2005
+ self.len(0, nodedata)
2006
+
2007
+ q = '''
2008
+ $edges = ([])
2009
+ for $edge in $lib.layer.get().getEdgesByN1($iden) {
2010
+ $edges.append($edge)
2011
+ }
2012
+ for $edge in $lib.layer.get().getEdgesByN2($iden) {
2013
+ $edges.append($edge)
2014
+ }
2015
+ return($edges)
2016
+ '''
2017
+ edges = await core.callStorm(q, opts=opts)
2018
+ self.len(0, edges)
2019
+
2020
+ self.false(await core.callStorm('return($lib.layer.get().delStorNode($iden))', opts=opts))
2021
+
2022
+ # insufficient perms
2023
+ lowuser = await core.auth.addUser('lowuser')
2024
+ await lowuser.addRule((True, ('node', 'add', 'test:str')))
2025
+
2026
+ q = '''
2027
+ [ test:str=foobar02 ]
2028
+ $lib.layer.get().delStorNode($node.iden())
2029
+ '''
2030
+ msgs = await core.stormlist(q, opts={'user': lowuser.iden})
2031
+ self.stormIsInErr('delStorNode() requires admin privileges.', msgs)
2032
+
2033
+ # Readonly layer
2034
+ nodes = await core.nodes('[ test:str=foobar ]')
2035
+ self.len(1, nodes)
2036
+ self.eq(nodes[0].repr(), 'foobar')
2037
+ layer = core.view.layers[0]
2038
+ await layer.setLayerInfo('readonly', True)
2039
+ msgs = await core.stormlist('test:str $lib.layer.get().delStorNode($node.iden())')
2040
+ self.stormIsInErr(f'Layer {layer.iden} is read only!', msgs)
2041
+
2042
+ async def test_storm_layer_delstornodeprop(self):
2043
+ async with self.getTestCore() as core:
2044
+ nodes = await core.nodes('[ test:str=foo :hehe=bar ]')
2045
+ self.len(1, nodes)
2046
+ self.eq(nodes[0].repr(), 'foo')
2047
+ self.eq(nodes[0].get('hehe'), 'bar')
2048
+
2049
+ msgs = await core.stormlist('test:str $lib.layer.get().delStorNodeProp($node.iden(), test:str:hehe)')
2050
+ self.stormHasNoWarnErr(msgs)
2051
+
2052
+ nodes = await core.nodes('test:str')
2053
+ self.len(1, nodes)
2054
+ self.eq(nodes[0].repr(), 'foo')
2055
+ self.none(nodes[0].get('hehe'))
2056
+
2057
+ async with self.getTestCore() as core2:
2058
+ url = core.getLocalUrl('*/layer')
2059
+
2060
+ layers = set(core2.layers.keys())
2061
+ q = f'layer.add --mirror {url}'
2062
+ await core2.stormlist(q)
2063
+
2064
+ uplayr = list(set(core2.layers.keys()) - layers)[0]
2065
+ vdef = {'layers': [uplayr]}
2066
+
2067
+ view00 = await core2.addView(vdef)
2068
+ opts = {'view': view00.get('iden')}
2069
+
2070
+ nodes = await core.nodes('[ test:str=foo :hehe=bar ]')
2071
+
2072
+ layr = core2.getLayer(uplayr)
2073
+ offs = await core.view.layers[0].getEditOffs()
2074
+ self.true(await layr.waitEditOffs(offs, timeout=10))
2075
+
2076
+ q = 'test:str return($lib.layer.get().delStorNodeProp($node.iden(), test:str:hehe))'
2077
+ self.true(await core2.callStorm(q, opts=opts))
2078
+
2079
+ # attempting to delete a second time should not blow up
2080
+ self.false(await core2.callStorm(q, opts=opts))
2081
+
2082
+ # no test:str:newp prop
2083
+ q = '''
2084
+ [ test:str=foobar00 ]
2085
+ $lib.layer.get().delStorNodeProp($node.iden(), test:str:newp)
2086
+ '''
2087
+ msgs = await core.stormlist(q)
2088
+ self.stormIsInErr('No property named test:str:newp.', msgs)
2089
+
2090
+ # insufficient perms
2091
+ lowuser = await core.auth.addUser('lowuser')
2092
+ await lowuser.addRule((True, ('node', 'add', 'test:str')))
2093
+
2094
+ q = '''
2095
+ [ test:str=foobar02 ]
2096
+ $lib.layer.get().delStorNodeProp($node.iden(), test:str:hehe)
2097
+ '''
2098
+ msgs = await core.stormlist(q, opts={'user': lowuser.iden})
2099
+ self.stormIsInErr('delStorNodeProp() requires admin privileges.', msgs)
2100
+
2101
+ # Readonly layer
2102
+ layer = core.view.layers[0]
2103
+ await layer.setLayerInfo('readonly', True)
2104
+ msgs = await core.stormlist('test:str $lib.layer.get().delStorNodeProp($node.iden(), test:str:hehe)')
2105
+ self.stormIsInErr(f'Layer {layer.iden} is read only!', msgs)
2106
+
2107
+ async def test_storm_layer_delnodedata(self):
2108
+ async with self.getTestCore() as core:
2109
+ q = '''
2110
+ $_ = { [test:str=foo] $node.data.set(foo, woot) }
2111
+ $_ = { [test:str=bar] $node.data.set(bar00, woot00) $node.data.set(bar01, woot01)}
2112
+ $_ = { [test:str=baz] $node.data.set(baz, woot) }
2113
+ '''
2114
+ msgs = await core.stormlist(q)
2115
+ self.stormHasNoWarnErr(msgs)
2116
+
2117
+ nodes = await core.nodes('test:str=foo')
2118
+ self.len(1, nodes)
2119
+ self.eq(nodes[0].repr(), 'foo')
2120
+ self.eq(await s_test.alist(nodes[0].iterData()), [('foo', 'woot')])
2121
+
2122
+ # Delete specific nodedata key
2123
+ msgs = await core.stormlist('test:str $lib.layer.get().delNodeData($node, foo)')
2124
+ self.stormHasNoWarnErr(msgs)
2125
+
2126
+ nodes = await core.nodes('test:str=foo')
2127
+ self.len(1, nodes)
2128
+ self.len(0, await s_test.alist(nodes[0].iterData()))
2129
+
2130
+ nodes = await core.nodes('test:str=bar')
2131
+ self.len(1, nodes)
2132
+ self.eq(nodes[0].repr(), 'bar')
2133
+ self.eq(await s_test.alist(nodes[0].iterData()), [('bar00', 'woot00'), ('bar01', 'woot01')])
2134
+
2135
+ # Delete all nodedata
2136
+ msgs = await core.stormlist('test:str=bar $lib.layer.get().delNodeData($node)')
2137
+ self.stormHasNoWarnErr(msgs)
2138
+
2139
+ nodes = await core.nodes('test:str=bar')
2140
+ self.len(1, nodes)
2141
+ self.len(0, await s_test.alist(nodes[0].iterData()))
2142
+
2143
+ # No edits to make
2144
+ self.false(await core.callStorm('test:str=bar return($lib.layer.get().delNodeData($node))'))
2145
+
2146
+ # insufficient perms
2147
+ lowuser = await core.auth.addUser('lowuser')
2148
+ await lowuser.addRule((True, ('node', 'add', 'test:str')))
2149
+
2150
+ q = '''
2151
+ test:str
2152
+ $lib.layer.get().delNodeData($node)
2153
+ '''
2154
+ msgs = await core.stormlist(q, opts={'user': lowuser.iden})
2155
+ self.stormIsInErr('delNodeData() requires admin privileges.', msgs)
2156
+
2157
+ # Readonly layer
2158
+ layer = core.view.layers[0]
2159
+ await layer.setLayerInfo('readonly', True)
2160
+ msgs = await core.stormlist('test:str=baz $lib.layer.get().delNodeData($node)')
2161
+ self.stormIsInErr(f'Layer {layer.iden} is read only!', msgs)
2162
+
2163
+ async def test_storm_layer_delnodeedge(self):
2164
+ async with self.getTestCore() as core:
2165
+ q = '''
2166
+ $seen00 = { [ meta:source=* :name=delnodeedge00 ] }
2167
+ $seen01 = { [ meta:source=* :name=delnodeedge01 ] }
2168
+ $refs = { [ it:dev:str=foobar ] }
2169
+ $_ = { [test:str=foo <(seen)+ $seen00 <(seen)+ $seen01]}
2170
+ $_ = { [test:str=bar <(seen)+ $seen00 +(refs)> $refs] }
2171
+ $_ = { [test:str=baz] }
2172
+ $_ = { [test:str=woot <(seen)+ $seen00 +(refs)> $refs] }
2173
+ '''
2174
+ msgs = await core.stormlist(q)
2175
+ self.stormHasNoWarnErr(msgs)
2176
+
2177
+ nodes = await core.nodes('meta:source:name=delnodeedge00')
2178
+ self.len(1, nodes)
2179
+ seen00 = nodes[0]
2180
+
2181
+ nodes = await core.nodes('meta:source:name=delnodeedge01')
2182
+ self.len(1, nodes)
2183
+ seen01 = nodes[0]
2184
+
2185
+ nodes = await core.nodes('it:dev:str=foobar')
2186
+ self.len(1, nodes)
2187
+ refs = nodes[0]
2188
+
2189
+ # Delete n2 edge
2190
+ nodes = await core.nodes('test:str=foo')
2191
+ self.len(1, nodes)
2192
+ self.len(0, await s_test.alist(nodes[0].iterEdgesN1()))
2193
+ self.sorteq(await s_test.alist(nodes[0].iterEdgesN2()), [('seen', seen00.iden()), ('seen', seen01.iden())])
2194
+
2195
+ q = '''
2196
+ $seen00 = { meta:source:name=delnodeedge00 }
2197
+ test:str=foo
2198
+ $lib.layer.get().delEdge($seen00, seen, $node)
2199
+ '''
2200
+ msgs = await core.stormlist(q)
2201
+ self.stormHasNoWarnErr(msgs)
2202
+
2203
+ nodes = await core.nodes('test:str=foo')
2204
+ self.len(1, nodes)
2205
+ self.len(0, await s_test.alist(nodes[0].iterEdgesN1()))
2206
+ self.eq(await s_test.alist(nodes[0].iterEdgesN2()), [('seen', seen01.iden())])
2207
+
2208
+ # Delete n1 edge
2209
+ nodes = await core.nodes('test:str=bar')
2210
+ self.len(1, nodes)
2211
+ self.sorteq(await s_test.alist(nodes[0].iterEdgesN1()), [('refs', refs.iden())])
2212
+ self.sorteq(await s_test.alist(nodes[0].iterEdgesN2()), [('seen', seen00.iden())])
2213
+
2214
+ q = '''
2215
+ $refs = { it:dev:str=foobar }
2216
+ test:str=bar
2217
+ $lib.layer.get().delEdge($node, refs, $refs)
2218
+ '''
2219
+ msgs = await core.stormlist(q)
2220
+ self.stormHasNoWarnErr(msgs)
2221
+
2222
+ nodes = await core.nodes('test:str=bar')
2223
+ self.len(1, nodes)
2224
+ self.len(0, await s_test.alist(nodes[0].iterEdgesN1()))
2225
+ self.eq(await s_test.alist(nodes[0].iterEdgesN2()), [('seen', seen00.iden())])
2226
+
2227
+ # No edits to make
2228
+ nodes = await core.nodes('test:str=baz')
2229
+ self.len(1, nodes)
2230
+ self.len(0, await s_test.alist(nodes[0].iterEdgesN1()))
2231
+ self.len(0, await s_test.alist(nodes[0].iterEdgesN2()))
2232
+
2233
+ q = '''
2234
+ $refs = { it:dev:str=foobar }
2235
+ test:str=baz
2236
+ $lib.layer.get().delEdge($node, refs, $refs)
2237
+ '''
2238
+ msgs = await core.stormlist(q)
2239
+ self.stormHasNoWarnErr(msgs)
2240
+
2241
+ # insufficient perms
2242
+ lowuser = await core.auth.addUser('lowuser')
2243
+ await lowuser.addRule((True, ('node', 'add', 'test:str')))
2244
+
2245
+ nodes = await core.nodes('test:str=woot')
2246
+ self.len(1, nodes)
2247
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN1()))
2248
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN2()))
2249
+
2250
+ q = '''
2251
+ $seen = { meta:source:name=delnodeedge00 }
2252
+ test:str=woot
2253
+ $lib.layer.get().delEdge($seen, seen, $node)
2254
+ '''
2255
+ msgs = await core.stormlist(q, opts={'user': lowuser.iden})
2256
+ self.stormIsInErr('delEdge() requires admin privileges.', msgs)
2257
+
2258
+ nodes = await core.nodes('test:str=woot')
2259
+ self.len(1, nodes)
2260
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN1()))
2261
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN2()))
2262
+
2263
+ # Readonly layer
2264
+ layer = core.view.layers[0]
2265
+ await layer.setLayerInfo('readonly', True)
2266
+ msgs = await core.stormlist(q)
2267
+ self.stormIsInErr(f'Layer {layer.iden} is read only!', msgs)
2268
+
2269
+ nodes = await core.nodes('test:str=woot')
2270
+ self.len(1, nodes)
2271
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN1()))
2272
+ self.len(1, await s_test.alist(nodes[0].iterEdgesN2()))
2273
+
1770
2274
  async def test_storm_lib_fire(self):
1771
2275
  async with self.getTestCore() as core:
1772
2276
  text = '$lib.fire(foo:bar, baz=faz)'
@@ -5671,6 +6175,76 @@ class StormTypesTest(s_test.SynTest):
5671
6175
  q = '$tally = $lib.stats.tally() $tally.inc(foo) $tally.inc(foo) return($tally)'
5672
6176
  self.eq({'foo': 2}, await core.callStorm(q))
5673
6177
 
6178
+ async def test_stormtypes_tobuid(self):
6179
+ async with self.getTestCore() as core:
6180
+
6181
+ buid = s_common.buid()
6182
+ sode = (
6183
+ buid,
6184
+ {
6185
+ 'ndef': ('it:dev:str', 'foobar'),
6186
+ }
6187
+ )
6188
+
6189
+ async with await core.snap() as snap:
6190
+ node = s_node.Node(snap, sode)
6191
+ snode = s_stormtypes.Node(node)
6192
+
6193
+ self.eq(await s_stormtypes.tobuid(node), buid)
6194
+ self.eq(await s_stormtypes.tobuid(snode), buid)
6195
+
6196
+ self.eq(await s_stormtypes.tobuid(buid.hex()), buid)
6197
+ self.eq(await s_stormtypes.tobuid(buid), buid)
6198
+
6199
+ with self.raises(s_exc.BadCast) as exc:
6200
+ await s_stormtypes.tobuid('newp')
6201
+ self.eq(exc.exception.get('mesg'), 'Invalid buid string: newp')
6202
+
6203
+ with self.raises(s_exc.BadCast) as exc:
6204
+ await s_stormtypes.tobuid([])
6205
+ self.eq(exc.exception.get('mesg'), 'Invalid buid valu: ()')
6206
+
6207
+ with self.raises(s_exc.BadCast) as exc:
6208
+ await s_stormtypes.tobuid(b'newp')
6209
+ self.eq(exc.exception.get('mesg'), "Invalid buid valu: b'newp'")
6210
+
6211
+ async def test_stormtypes_tobuidhex(self):
6212
+ async with self.getTestCore() as core:
6213
+
6214
+ self.none(await s_stormtypes.tobuidhex(None, noneok=True))
6215
+
6216
+ buid = s_common.buid()
6217
+ buidhex = s_common.ehex(buid)
6218
+ sode = (
6219
+ buid,
6220
+ {
6221
+ 'ndef': ('it:dev:str', 'foobar'),
6222
+ }
6223
+ )
6224
+
6225
+ async with await core.snap() as snap:
6226
+ node = s_node.Node(snap, sode)
6227
+ snode = s_stormtypes.Node(node)
6228
+
6229
+ self.eq(await s_stormtypes.tobuidhex(node), buidhex)
6230
+ self.eq(await s_stormtypes.tobuidhex(snode), buidhex)
6231
+
6232
+ self.eq(await s_stormtypes.tobuidhex(buidhex), buidhex)
6233
+ self.eq(await s_stormtypes.tobuidhex(buid), buidhex)
6234
+
6235
+ with self.raises(s_exc.BadCast) as exc:
6236
+ await s_stormtypes.tobuidhex('newp')
6237
+ self.eq(exc.exception.get('mesg'), 'Invalid buid string: newp')
6238
+
6239
+ with self.raises(s_exc.BadCast) as exc:
6240
+ await s_stormtypes.tobuidhex([])
6241
+ self.eq(exc.exception.get('mesg'), 'Invalid buid valu: ()')
6242
+
6243
+ newp = b'newp'
6244
+ with self.raises(s_exc.BadCast) as exc:
6245
+ await s_stormtypes.tobuidhex(newp)
6246
+ self.eq(exc.exception.get('mesg'), "Invalid buid valu: b'newp'")
6247
+
5674
6248
  async def test_print_warn(self):
5675
6249
  async with self.getTestCore() as core:
5676
6250
  q = '$lib.print(hello)'
@@ -25,6 +25,7 @@ class OuModelTest(s_t_utils.SynTest):
25
25
  :reporter=$lib.gen.orgByName(vertex)
26
26
  :reporter:name=vertex
27
27
  :ext:id=Foo
28
+ :parent={[ ou:technique=* :name=metawoot ]}
28
29
  ]
29
30
  ''')
30
31
  self.len(1, nodes)
@@ -37,10 +38,14 @@ class OuModelTest(s_t_utils.SynTest):
37
38
  self.eq('T0001', nodes[0].get('mitre:attack:technique'))
38
39
  self.eq(40, nodes[0].get('sophistication'))
39
40
  self.eq('vertex', nodes[0].get('reporter:name'))
41
+ self.nn(nodes[0].get('parent'))
40
42
  self.len(1, await core.nodes('ou:technique -> syn:tag'))
41
43
  self.len(1, await core.nodes('ou:technique -> ou:technique:taxonomy'))
42
44
  self.len(1, await core.nodes('ou:technique -> it:mitre:attack:technique'))
43
- self.len(1, await core.nodes('ou:technique :reporter -> ou:org'))
45
+
46
+ nodes = await core.nodes('ou:technique :parent -> *')
47
+ self.len(1, nodes)
48
+ self.eq('metawoot', nodes[0].get('name'))
44
49
 
45
50
  props = {
46
51
  'name': 'MyGoal',
synapse/tools/aha/list.py CHANGED
@@ -7,14 +7,17 @@ import synapse.lib.version as s_version
7
7
 
8
8
  reqver = '>=2.11.0,<3.0.0'
9
9
 
10
+ descr = 'List AHA services.'
11
+
10
12
  async def main(argv, outp=s_output.stdout):
11
13
 
12
- if len(argv) not in (1, 2):
13
- outp.printf('usage: python -m synapse.tools.aha.list <url> [network name]')
14
- return 1
14
+ pars = s_cmd.Parser(prog='synapse.tools.aha.list', outp=outp, description=descr)
15
+ pars.add_argument('url', help='The telepath URL to connect to the AHA service.')
16
+ pars.add_argument('network', nargs='?', default=None, help='The AHA network name.')
17
+ opts = pars.parse_args(argv)
15
18
 
16
19
  async with s_telepath.withTeleEnv():
17
- async with await s_telepath.openurl(argv[0]) as prox:
20
+ async with await s_telepath.openurl(opts.url) as prox:
18
21
  try:
19
22
  s_version.reqVersion(prox._getSynVers(), reqver)
20
23
  except s_exc.BadVersion as e: # pragma: no cover
@@ -23,13 +26,10 @@ async def main(argv, outp=s_output.stdout):
23
26
  return 1
24
27
  classes = prox._getClasses()
25
28
  if 'synapse.lib.aha.AhaApi' not in classes:
26
- outp.printf(f'Service at {argv[0]} is not an Aha server')
29
+ outp.printf(f'Service at {opts.url} is not an Aha server')
27
30
  return 1
28
31
 
29
- try:
30
- network = argv[1]
31
- except IndexError:
32
- network = None
32
+ network = opts.network
33
33
 
34
34
  mesg = f"{'Service':<20s} {'network':<30s} {'leader':<6} {'online':<6} {'scheme':<6} {'host':<20} {'port':<5} connection opts"
35
35
  outp.printf(mesg)