synapse 2.169.0__py311-none-any.whl → 2.170.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.
- synapse/cortex.py +88 -2
- synapse/datamodel.py +5 -0
- synapse/lib/ast.py +70 -12
- synapse/lib/cell.py +77 -7
- synapse/lib/layer.py +75 -6
- synapse/lib/node.py +7 -0
- synapse/lib/snap.py +22 -4
- synapse/lib/storm.py +1 -1
- synapse/lib/stormlib/cortex.py +1 -1
- synapse/lib/stormlib/model.py +339 -40
- synapse/lib/stormtypes.py +58 -1
- synapse/lib/types.py +35 -0
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +87 -14
- synapse/models/files.py +40 -0
- synapse/models/inet.py +8 -4
- synapse/models/infotech.py +355 -17
- synapse/tests/files/cpedata.json +525034 -0
- synapse/tests/test_cortex.py +99 -0
- synapse/tests/test_lib_ast.py +66 -0
- synapse/tests/test_lib_cell.py +112 -0
- synapse/tests/test_lib_layer.py +52 -1
- synapse/tests/test_lib_scrape.py +72 -71
- synapse/tests/test_lib_snap.py +16 -1
- synapse/tests/test_lib_storm.py +118 -0
- synapse/tests/test_lib_stormlib_cortex.py +15 -0
- synapse/tests/test_lib_stormlib_model.py +427 -0
- synapse/tests/test_lib_stormtypes.py +135 -14
- synapse/tests/test_lib_types.py +20 -0
- synapse/tests/test_lib_view.py +77 -0
- synapse/tests/test_model_files.py +51 -0
- synapse/tests/test_model_inet.py +63 -1
- synapse/tests/test_model_infotech.py +187 -26
- synapse/tests/utils.py +12 -0
- {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/METADATA +1 -1
- {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/RECORD +39 -38
- {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/LICENSE +0 -0
- {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/WHEEL +0 -0
- {synapse-2.169.0.dist-info → synapse-2.170.0.dist-info}/top_level.txt +0 -0
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -19,6 +19,8 @@ import synapse.lib.version as s_version
|
|
|
19
19
|
import synapse.tests.utils as s_t_utils
|
|
20
20
|
from synapse.tests.utils import alist
|
|
21
21
|
|
|
22
|
+
import synapse.tools.backup as s_tools_backup
|
|
23
|
+
|
|
22
24
|
class StormTest(s_t_utils.SynTest):
|
|
23
25
|
|
|
24
26
|
async def test_lib_storm_jsonexpr(self):
|
|
@@ -2041,6 +2043,90 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2041
2043
|
|
|
2042
2044
|
self.eq((1, 6), await core.callStorm('return($lib.queue.gen(foo).get(1))'))
|
|
2043
2045
|
|
|
2046
|
+
async def test_storm_dmon_query_state(self):
|
|
2047
|
+
with self.getTestDir() as dirn:
|
|
2048
|
+
dirn00 = s_common.gendir(dirn, 'core00')
|
|
2049
|
+
dirn01 = s_common.gendir(dirn, 'core01')
|
|
2050
|
+
dirn02 = s_common.gendir(dirn, 'core02')
|
|
2051
|
+
|
|
2052
|
+
async with self.getTestCore(dirn=dirn00) as core00:
|
|
2053
|
+
|
|
2054
|
+
msgs = await core00.stormlist('[ inet:ipv4=1.2.3.4 ]')
|
|
2055
|
+
self.stormHasNoWarnErr(msgs)
|
|
2056
|
+
|
|
2057
|
+
s_tools_backup.backup(dirn00, dirn01)
|
|
2058
|
+
s_tools_backup.backup(dirn00, dirn02)
|
|
2059
|
+
|
|
2060
|
+
async with self.getTestCore(dirn=dirn00) as core00:
|
|
2061
|
+
conf01 = {'mirror': core00.getLocalUrl()}
|
|
2062
|
+
|
|
2063
|
+
async with self.getTestCore(dirn=dirn01, conf=conf01) as core01:
|
|
2064
|
+
|
|
2065
|
+
conf02 = {'mirror': core01.getLocalUrl()}
|
|
2066
|
+
|
|
2067
|
+
async with self.getTestCore(dirn=dirn02, conf=conf02) as core02:
|
|
2068
|
+
|
|
2069
|
+
await core02.sync()
|
|
2070
|
+
|
|
2071
|
+
nodes = await core01.nodes('inet:ipv4')
|
|
2072
|
+
self.len(1, nodes)
|
|
2073
|
+
self.eq(nodes[0].ndef, ('inet:ipv4', 16909060))
|
|
2074
|
+
|
|
2075
|
+
q = '''
|
|
2076
|
+
$lib.queue.gen(dmonloop)
|
|
2077
|
+
return(
|
|
2078
|
+
$lib.dmon.add(${
|
|
2079
|
+
$queue = $lib.queue.get(dmonloop)
|
|
2080
|
+
while $lib.true {
|
|
2081
|
+
($offs, $mesg) = $queue.get()
|
|
2082
|
+
|
|
2083
|
+
switch $mesg.0 {
|
|
2084
|
+
"print": { $lib.print($mesg.1) }
|
|
2085
|
+
"warn": { $lib.warn($mesg.1) }
|
|
2086
|
+
"leave": {
|
|
2087
|
+
$lib.print(leaving)
|
|
2088
|
+
break
|
|
2089
|
+
}
|
|
2090
|
+
*: { continue }
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
$queue.cull($offs)
|
|
2094
|
+
}
|
|
2095
|
+
}, name=dmonloop)
|
|
2096
|
+
)
|
|
2097
|
+
'''
|
|
2098
|
+
ddef = await core02.callStorm(q)
|
|
2099
|
+
self.nn(ddef['iden'])
|
|
2100
|
+
|
|
2101
|
+
dmons = await core02.getStormDmons()
|
|
2102
|
+
self.len(1, dmons)
|
|
2103
|
+
self.eq(dmons[0]['iden'], ddef['iden'])
|
|
2104
|
+
|
|
2105
|
+
info = await core02.getStormDmon(ddef['iden'])
|
|
2106
|
+
self.eq(info['iden'], ddef['iden'])
|
|
2107
|
+
self.eq(info['name'], 'dmonloop')
|
|
2108
|
+
self.eq(info['status'], 'running')
|
|
2109
|
+
|
|
2110
|
+
await core02.callStorm('$lib.queue.get(dmonloop).put((print, printfoo))')
|
|
2111
|
+
await core02.callStorm('$lib.queue.get(dmonloop).put((warn, warnfoo))')
|
|
2112
|
+
|
|
2113
|
+
info = await core02.getStormDmon(ddef['iden'])
|
|
2114
|
+
self.eq(info['status'], 'running')
|
|
2115
|
+
|
|
2116
|
+
logs = await core02.getStormDmonLog(ddef['iden'])
|
|
2117
|
+
msgs = [k[1] for k in logs]
|
|
2118
|
+
self.stormIsInPrint('printfoo', msgs)
|
|
2119
|
+
self.stormIsInWarn('warnfoo', msgs)
|
|
2120
|
+
|
|
2121
|
+
await core02.callStorm('$lib.queue.get(dmonloop).put((leave,))')
|
|
2122
|
+
|
|
2123
|
+
info = await core02.getStormDmon(ddef['iden'])
|
|
2124
|
+
self.eq(info['status'], 'sleeping')
|
|
2125
|
+
|
|
2126
|
+
logs = await core02.getStormDmonLog(ddef['iden'])
|
|
2127
|
+
msgs = [k[1] for k in logs]
|
|
2128
|
+
self.stormIsInPrint('leaving', msgs)
|
|
2129
|
+
|
|
2044
2130
|
async def test_storm_pipe(self):
|
|
2045
2131
|
|
|
2046
2132
|
async with self.getTestCore() as core:
|
|
@@ -3098,6 +3184,38 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3098
3184
|
nodes = await core.nodes(q, opts={'view': fork, 'vars': {'view': view}})
|
|
3099
3185
|
self.len(1, nodes)
|
|
3100
3186
|
|
|
3187
|
+
async def test_storm_viewexec(self):
|
|
3188
|
+
|
|
3189
|
+
async with self.getTestCore() as core:
|
|
3190
|
+
|
|
3191
|
+
view = await core.callStorm('return( $lib.view.get().iden )')
|
|
3192
|
+
fork = await core.callStorm('return( $lib.view.get().fork().iden )')
|
|
3193
|
+
|
|
3194
|
+
await core.addStormPkg({
|
|
3195
|
+
'name': 'testpkg',
|
|
3196
|
+
'version': (0, 0, 1),
|
|
3197
|
+
'modules': (
|
|
3198
|
+
{'name': 'priv.exec',
|
|
3199
|
+
'asroot:perms': [['power-ups', 'testpkg']],
|
|
3200
|
+
'modconf': {'viewiden': fork},
|
|
3201
|
+
'storm': '''
|
|
3202
|
+
function asroot () {
|
|
3203
|
+
view.exec $modconf.viewiden { $foo=bar } | return($foo)
|
|
3204
|
+
}
|
|
3205
|
+
'''},
|
|
3206
|
+
),
|
|
3207
|
+
})
|
|
3208
|
+
|
|
3209
|
+
visi = await core.auth.addUser('visi')
|
|
3210
|
+
asvisi = {'user': visi.iden}
|
|
3211
|
+
|
|
3212
|
+
await core.stormlist('auth.user.addrule visi power-ups.testpkg')
|
|
3213
|
+
|
|
3214
|
+
with self.raises(s_exc.AuthDeny):
|
|
3215
|
+
await core.callStorm('return(woot)', opts={'user': visi.iden, 'view': fork})
|
|
3216
|
+
|
|
3217
|
+
self.eq('bar', await core.callStorm('return($lib.import(priv.exec).asroot())', opts=asvisi))
|
|
3218
|
+
|
|
3101
3219
|
async def test_storm_argv_parser(self):
|
|
3102
3220
|
|
|
3103
3221
|
pars = s_storm.Parser(prog='hehe')
|
|
@@ -1280,6 +1280,12 @@ for $i in $values {
|
|
|
1280
1280
|
return ( ($api.iden) )'''
|
|
1281
1281
|
iden06 = await core.callStorm(q)
|
|
1282
1282
|
|
|
1283
|
+
# attempt to JSON decode non-JSON request
|
|
1284
|
+
q = '''$api = $lib.cortex.httpapi.add(bad07)
|
|
1285
|
+
$api.methods.get = ${ $foo = $request.json() }
|
|
1286
|
+
return ( ($api.iden) )'''
|
|
1287
|
+
iden07 = await core.callStorm(q)
|
|
1288
|
+
|
|
1283
1289
|
async with self.getHttpSess(auth=('root', 'root'), port=hport) as sess:
|
|
1284
1290
|
resp = await sess.get(f'https://localhost:{hport}/api/ext/bad00')
|
|
1285
1291
|
self.eq(resp.status, 500)
|
|
@@ -1329,6 +1335,15 @@ for $i in $values {
|
|
|
1329
1335
|
self.eq(resp.status, 201)
|
|
1330
1336
|
self.eq(await resp.json(), {})
|
|
1331
1337
|
|
|
1338
|
+
with self.getAsyncLoggerStream('synapse.lib.httpapi',
|
|
1339
|
+
f'Error executing Extended HTTP API {iden07}: StormRuntimeError') as stream:
|
|
1340
|
+
resp = await sess.get(f'https://localhost:{hport}/api/ext/bad07')
|
|
1341
|
+
self.true(await stream.wait(timeout=6))
|
|
1342
|
+
self.eq(resp.status, 500)
|
|
1343
|
+
data = await resp.json()
|
|
1344
|
+
self.eq(data.get('code'), 'StormRuntimeError')
|
|
1345
|
+
self.isin('Failed to decode request body as JSON: Expecting value', data.get('mesg'))
|
|
1346
|
+
|
|
1332
1347
|
async def test_cortex_httpapi_dynamic(self):
|
|
1333
1348
|
|
|
1334
1349
|
# API endpoints can be dynamic. Use at your own risk.
|
|
@@ -400,3 +400,430 @@ class StormlibModelTest(s_test.SynTest):
|
|
|
400
400
|
|
|
401
401
|
q = 'test:str=src $n=$node -> { test:str=deny $lib.model.migration.copyTags($n, $node) }'
|
|
402
402
|
await self.asyncraises(s_exc.AuthDeny, core.nodes(q, opts=aslow))
|
|
403
|
+
|
|
404
|
+
async def test_model_migration_s_itSecCpe_2_170_0(self):
|
|
405
|
+
|
|
406
|
+
async with self.getRegrCore('itSecCpe_2_170_0') as core:
|
|
407
|
+
# Migrate it:sec:cpe nodes with a valid CPE2.3, valid CPE2.2
|
|
408
|
+
q = 'it:sec:cpe +#test.cpe.23valid +#test.cpe.22valid'
|
|
409
|
+
nodes = await core.nodes(q)
|
|
410
|
+
self.len(2, nodes)
|
|
411
|
+
self.eq(
|
|
412
|
+
[
|
|
413
|
+
('it:sec:cpe', 'cpe:2.3:a:abine:donottrackme_-_mobile_privacy:1.1.8:*:*:*:*:android:*:*'),
|
|
414
|
+
('it:sec:cpe', 'cpe:2.3:a:01generator:pireospay:-:*:*:*:*:prestashop:*:*')
|
|
415
|
+
],
|
|
416
|
+
[node.ndef for node in nodes]
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
q = '''
|
|
420
|
+
it:sec:cpe +#test.cpe.23valid +#test.cpe.22valid
|
|
421
|
+
$lib.debug=$lib.true
|
|
422
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
423
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
424
|
+
'''
|
|
425
|
+
nodes = await core.nodes(q)
|
|
426
|
+
|
|
427
|
+
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
428
|
+
self.nn(data)
|
|
429
|
+
self.eq(data['status'], 'success')
|
|
430
|
+
self.none(data.get('reason'))
|
|
431
|
+
|
|
432
|
+
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
433
|
+
self.nn(data)
|
|
434
|
+
self.eq(data['status'], 'success')
|
|
435
|
+
self.none(data.get('reason'))
|
|
436
|
+
|
|
437
|
+
async with self.getRegrCore('itSecCpe_2_170_0') as core:
|
|
438
|
+
# Migrate it:sec:cpe nodes with a valid CPE2.3, invalid CPE2.2
|
|
439
|
+
q = '''
|
|
440
|
+
it:sec:cpe +#test.cpe.23valid +#test.cpe.22invalid
|
|
441
|
+
$lib.debug=$lib.true
|
|
442
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
443
|
+
'''
|
|
444
|
+
nodes = await core.nodes(q)
|
|
445
|
+
self.len(3, nodes)
|
|
446
|
+
self.eq(
|
|
447
|
+
[
|
|
448
|
+
('it:sec:cpe', 'cpe:2.3:a:1c:1c\\:enterprise:-:*:*:*:*:*:*:*'),
|
|
449
|
+
('it:sec:cpe', 'cpe:2.3:o:zyxel:nas542_firmware:5.21\\%28aazf.15\\%29co:*:*:*:*:*:*:*'),
|
|
450
|
+
('it:sec:cpe', 'cpe:2.3:a:abinitio:control\\>center:-:*:*:*:*:*:*:*'),
|
|
451
|
+
],
|
|
452
|
+
[node.ndef for node in nodes]
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
q = '''
|
|
456
|
+
it:sec:cpe +#test.cpe.23valid +#test.cpe.22invalid
|
|
457
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
458
|
+
'''
|
|
459
|
+
nodes = await core.nodes(q)
|
|
460
|
+
self.len(3, nodes)
|
|
461
|
+
|
|
462
|
+
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
463
|
+
self.nn(data)
|
|
464
|
+
self.eq(data['status'], 'success')
|
|
465
|
+
self.eq(data['updated'], ['v2_2', 'product'])
|
|
466
|
+
self.eq(nodes[0].get('v2_2'), 'cpe:/a:1c:1c%3aenterprise:-')
|
|
467
|
+
self.eq(nodes[0].get('product'), '1c:enterprise')
|
|
468
|
+
|
|
469
|
+
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
470
|
+
self.nn(data)
|
|
471
|
+
self.eq(data['status'], 'success')
|
|
472
|
+
self.none(data.get('valu'))
|
|
473
|
+
self.eq(data['updated'], ['v2_2', 'version'])
|
|
474
|
+
self.eq(nodes[1].get('v2_2'), 'cpe:/o:zyxel:nas542_firmware:5.21%2528aazf.15%2529co')
|
|
475
|
+
self.eq(nodes[1].get('version'), '5.21%28aazf.15%29co')
|
|
476
|
+
|
|
477
|
+
data = nodes[2].nodedata['migration.s.itSecCpe_2_170_0']
|
|
478
|
+
self.nn(data)
|
|
479
|
+
self.eq(data['status'], 'success')
|
|
480
|
+
self.eq(data['updated'], ['v2_2', 'product'])
|
|
481
|
+
self.eq(nodes[2].get('v2_2'), 'cpe:/a:abinitio:control%3ecenter:-')
|
|
482
|
+
self.eq(nodes[2].get('product'), 'control>center')
|
|
483
|
+
|
|
484
|
+
# The migration of this node was not correct because the CPE2.3 string (primary property) is valid but was
|
|
485
|
+
# not created correctly due to a bad CPE2.2 input value. Now we update :v2_2 to be correct, and re-run the
|
|
486
|
+
# migration. This time, we specify `prefer_v22=True` and `force=True` so the migration will use the updated
|
|
487
|
+
# :v2_2 prop for reparsing the strings. Force will cause the migration to continue past the check where both
|
|
488
|
+
# the primary property and :v2_2 are valid.
|
|
489
|
+
q = '''
|
|
490
|
+
it:sec:cpe:product=nas542_firmware [ :v2_2="cpe:/o:zyxel:nas542_firmware:5.21%28aazf.15%29co" ]
|
|
491
|
+
$lib.debug=$lib.true
|
|
492
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node, prefer_v22=$lib.true, force=$lib.true)
|
|
493
|
+
'''
|
|
494
|
+
nodes = await core.nodes(q)
|
|
495
|
+
self.len(1, nodes)
|
|
496
|
+
|
|
497
|
+
# Lift the updated node and check the migration did what was expected.
|
|
498
|
+
q = '''
|
|
499
|
+
it:sec:cpe:product=nas542_firmware
|
|
500
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
501
|
+
'''
|
|
502
|
+
nodes = await core.nodes(q)
|
|
503
|
+
self.len(1, nodes)
|
|
504
|
+
|
|
505
|
+
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
506
|
+
self.nn(data)
|
|
507
|
+
self.eq(data['status'], 'success')
|
|
508
|
+
self.eq(data['updated'], ['version'])
|
|
509
|
+
self.eq(data['valu'], 'cpe:2.3:o:zyxel:nas542_firmware:5.21\\(aazf.15\\)co:*:*:*:*:*:*:*')
|
|
510
|
+
self.eq(nodes[0].get('v2_2'), 'cpe:/o:zyxel:nas542_firmware:5.21%28aazf.15%29co')
|
|
511
|
+
self.eq(nodes[0].get('version'), '5.21(aazf.15)co')
|
|
512
|
+
|
|
513
|
+
async with self.getRegrCore('itSecCpe_2_170_0') as core:
|
|
514
|
+
# Migrate it:sec:cpe nodes with a invalid CPE2.3, valid CPE2.2
|
|
515
|
+
q = '''
|
|
516
|
+
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22valid
|
|
517
|
+
$lib.debug=$lib.true
|
|
518
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
519
|
+
'''
|
|
520
|
+
nodes = await core.nodes(q)
|
|
521
|
+
self.len(4, nodes)
|
|
522
|
+
self.eq(
|
|
523
|
+
[
|
|
524
|
+
('it:sec:cpe', 'cpe:2.3:h:d\\-link:dir\\-850l:*:*:*:*:*:*:*:*'),
|
|
525
|
+
('it:sec:cpe', 'cpe:2.3:a:acurax:under_construction_%2f_maintenance_mode:-::~~~wordpress~~:*:*:*:*:*'),
|
|
526
|
+
('it:sec:cpe', 'cpe:2.3:a:10web:social_feed_for_instagram:1.0.0::~~premium~wordpress~~:*:*:*:*:*'),
|
|
527
|
+
('it:sec:cpe', 'cpe:2.3:o:zyxel:nas326_firmware:5.21%28aazf.14%29c0:*:*:*:*:*:*:*'),
|
|
528
|
+
],
|
|
529
|
+
[node.ndef for node in nodes]
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
q = '''
|
|
533
|
+
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22valid
|
|
534
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
535
|
+
'''
|
|
536
|
+
nodes = await core.nodes(q)
|
|
537
|
+
self.len(4, nodes)
|
|
538
|
+
|
|
539
|
+
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
540
|
+
self.nn(data)
|
|
541
|
+
self.eq(data['status'], 'success')
|
|
542
|
+
self.eq(data['updated'], ['vendor', 'product'])
|
|
543
|
+
self.eq(data['valu'], 'cpe:2.3:h:d-link:dir-850l:*:*:*:*:*:*:*:*')
|
|
544
|
+
self.eq(nodes[0].get('vendor'), 'd-link')
|
|
545
|
+
self.eq(nodes[0].get('product'), 'dir-850l')
|
|
546
|
+
|
|
547
|
+
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
548
|
+
self.nn(data)
|
|
549
|
+
self.eq(data['status'], 'success')
|
|
550
|
+
self.eq(data['updated'], ['product', 'update', 'edition', 'target_sw'])
|
|
551
|
+
self.eq(data['valu'], 'cpe:2.3:a:acurax:under_construction_\\/_maintenance_mode:-:*:*:*:*:wordpress:*:*')
|
|
552
|
+
self.eq(nodes[1].get('product'), 'under_construction_/_maintenance_mode')
|
|
553
|
+
self.eq(nodes[1].get('update'), '*')
|
|
554
|
+
self.eq(nodes[1].get('edition'), '*')
|
|
555
|
+
self.eq(nodes[1].get('target_sw'), 'wordpress')
|
|
556
|
+
|
|
557
|
+
data = nodes[2].nodedata['migration.s.itSecCpe_2_170_0']
|
|
558
|
+
self.nn(data)
|
|
559
|
+
self.eq(data['status'], 'success')
|
|
560
|
+
self.eq(data['updated'], ['update', 'edition', 'sw_edition', 'target_sw'])
|
|
561
|
+
self.eq(data['valu'], 'cpe:2.3:a:10web:social_feed_for_instagram:1.0.0:*:*:*:premium:wordpress:*:*')
|
|
562
|
+
self.eq(nodes[2].get('update'), '*')
|
|
563
|
+
self.eq(nodes[2].get('edition'), '*')
|
|
564
|
+
self.eq(nodes[2].get('sw_edition'), 'premium')
|
|
565
|
+
self.eq(nodes[2].get('target_sw'), 'wordpress')
|
|
566
|
+
|
|
567
|
+
data = nodes[3].nodedata['migration.s.itSecCpe_2_170_0']
|
|
568
|
+
self.nn(data)
|
|
569
|
+
self.eq(data['status'], 'success')
|
|
570
|
+
self.eq(data['updated'], ['version'])
|
|
571
|
+
self.eq(data['valu'], 'cpe:2.3:o:zyxel:nas326_firmware:5.21\\(aazf.14\\)c0:*:*:*:*:*:*:*')
|
|
572
|
+
self.eq(nodes[3].get('version'), '5.21(aazf.14)c0')
|
|
573
|
+
|
|
574
|
+
async with self.getRegrCore('itSecCpe_2_170_0') as core:
|
|
575
|
+
# Migrate it:sec:cpe nodes with a invalid CPE2.3, invalid CPE2.2
|
|
576
|
+
q = '''
|
|
577
|
+
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22invalid
|
|
578
|
+
$lib.debug=$lib.true
|
|
579
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
580
|
+
'''
|
|
581
|
+
msgs = await core.stormlist(q)
|
|
582
|
+
mesg = 'itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): '
|
|
583
|
+
mesg += 'Unable to migrate due to invalid data. Primary property and :v2_2 are both invalid.'
|
|
584
|
+
self.stormIsInWarn(mesg, msgs)
|
|
585
|
+
|
|
586
|
+
ndefs = [m[1][0] for m in msgs if m[0] == 'node']
|
|
587
|
+
self.eq(
|
|
588
|
+
[
|
|
589
|
+
('it:sec:cpe', 'cpe:2.3:a:openbsd:openssh:7.4\r\n:*:*:*:*:*:*:*'),
|
|
590
|
+
('it:sec:cpe', 'cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*')
|
|
591
|
+
],
|
|
592
|
+
ndefs
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
q = '''
|
|
596
|
+
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22invalid
|
|
597
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
598
|
+
'''
|
|
599
|
+
nodes = await core.nodes(q)
|
|
600
|
+
self.len(2, nodes)
|
|
601
|
+
|
|
602
|
+
for node in nodes:
|
|
603
|
+
data = node.nodedata['migration.s.itSecCpe_2_170_0']
|
|
604
|
+
self.eq(data, {
|
|
605
|
+
'status': 'failed',
|
|
606
|
+
'reason': 'Unable to migrate due to invalid data. Primary property and :v2_2 are both invalid.',
|
|
607
|
+
})
|
|
608
|
+
|
|
609
|
+
# Now update the :v2_2 on one of the nodes and migrate again
|
|
610
|
+
q = '''
|
|
611
|
+
it:sec:cpe:version^=8.2p1 [ :v2_2="cpe:/a:openbsd:openssh:8.2p1_ubuntu-4ubuntu0.2" ]
|
|
612
|
+
$lib.debug=$lib.true
|
|
613
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
614
|
+
'''
|
|
615
|
+
msgs = await core.stormlist(q)
|
|
616
|
+
self.stormHasNoWarnErr(msgs)
|
|
617
|
+
|
|
618
|
+
q = '''
|
|
619
|
+
it:sec:cpe:version^=8.2p1
|
|
620
|
+
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
621
|
+
'''
|
|
622
|
+
nodes = await core.nodes(q)
|
|
623
|
+
self.len(1, nodes)
|
|
624
|
+
|
|
625
|
+
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
626
|
+
self.nn(data)
|
|
627
|
+
self.eq(data['status'], 'success')
|
|
628
|
+
self.eq(data['updated'], ['version'])
|
|
629
|
+
self.eq(data['valu'], 'cpe:2.3:a:openbsd:openssh:8.2p1_ubuntu-4ubuntu0.2:*:*:*:*:*:*:*')
|
|
630
|
+
self.eq(nodes[0].get('version'), '8.2p1_ubuntu-4ubuntu0.2')
|
|
631
|
+
|
|
632
|
+
# Run the migration again to make sure we identify already migrated
|
|
633
|
+
# nodes correctly and bail early.
|
|
634
|
+
q = '''
|
|
635
|
+
it:sec:cpe:version^=8.2p1
|
|
636
|
+
$lib.debug=$lib.true
|
|
637
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
638
|
+
'''
|
|
639
|
+
msgs = await core.stormlist(q)
|
|
640
|
+
self.stormIsInPrint(f'DEBUG: itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): Node already migrated.', msgs)
|
|
641
|
+
|
|
642
|
+
q = '''
|
|
643
|
+
it:sec:cpe:version^=8.2p1
|
|
644
|
+
$lib.debug=$lib.true
|
|
645
|
+
$lib.model.migration.s.itSecCpe_2_170_0($node, force=$lib.true)
|
|
646
|
+
'''
|
|
647
|
+
msgs = await core.stormlist(q)
|
|
648
|
+
self.stormIsInPrint(f'DEBUG: itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): No property updates required.', msgs)
|
|
649
|
+
|
|
650
|
+
async with self.getTestCore() as core:
|
|
651
|
+
with self.raises(s_exc.BadArg):
|
|
652
|
+
await core.callStorm('$lib.model.migration.s.itSecCpe_2_170_0(newp)')
|
|
653
|
+
|
|
654
|
+
with self.raises(s_exc.BadArg):
|
|
655
|
+
await core.callStorm('[ inet:fqdn=vertex.link ] $lib.model.migration.s.itSecCpe_2_170_0($node)')
|
|
656
|
+
|
|
657
|
+
async def test_stormlib_model_migrations_risk_hasvuln_vulnerable(self):
|
|
658
|
+
|
|
659
|
+
async with self.getTestCore() as core:
|
|
660
|
+
|
|
661
|
+
await core.nodes('$lib.model.ext.addTagProp(test, (str, ({})), ({}))')
|
|
662
|
+
await core.nodes('$lib.model.ext.addFormProp(risk:hasvuln, _test, (ps:contact, ({})), ({}))')
|
|
663
|
+
|
|
664
|
+
await core.nodes('[ risk:vuln=* it:prod:softver=* +#test ]')
|
|
665
|
+
|
|
666
|
+
opts = {
|
|
667
|
+
'vars': {
|
|
668
|
+
'guid00': (guid00 := 'c6f158a4d8e267a023b06415a04bf583'),
|
|
669
|
+
'guid01': (guid01 := 'e98f7eada5f5057bc3181ab3fab1f7d5'),
|
|
670
|
+
'guid02': (guid02 := '99b27f37f5cc1681ad0617e7c97a4094'),
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
# nodes with 1 vulnerable node get matching guids
|
|
675
|
+
# all data associated with hasvuln (except ext props) are migrated
|
|
676
|
+
|
|
677
|
+
nodes = await core.nodes('''
|
|
678
|
+
[ risk:hasvuln=$guid00
|
|
679
|
+
:software={ it:prod:softver#test }
|
|
680
|
+
:vuln={ risk:vuln#test }
|
|
681
|
+
:_test={[ ps:contact=* ]}
|
|
682
|
+
.seen=(2010, 2011)
|
|
683
|
+
+#test=(2012, 2013)
|
|
684
|
+
+#test.foo:test=hi
|
|
685
|
+
<(seen)+ {[ meta:source=* :name=foo ]}
|
|
686
|
+
+(refs)> {[ ps:contact=* :name=bar ]}
|
|
687
|
+
]
|
|
688
|
+
$node.data.set(baz, bam)
|
|
689
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
690
|
+
''', opts=opts)
|
|
691
|
+
self.len(1, nodes)
|
|
692
|
+
self.eq(guid00, nodes[0].ndef[1])
|
|
693
|
+
self.eq([
|
|
694
|
+
('test', (s_time.parse('2012'), s_time.parse('2013'))),
|
|
695
|
+
('test.foo', (None, None))
|
|
696
|
+
], nodes[0].getTags())
|
|
697
|
+
self.eq('hi', nodes[0].getTagProp('test.foo', 'test'))
|
|
698
|
+
self.eq('bam', await nodes[0].getData('baz'))
|
|
699
|
+
|
|
700
|
+
self.len(1, await core.nodes('risk:vulnerable#test <(seen)- meta:source +:name=foo'))
|
|
701
|
+
self.len(1, await core.nodes('risk:vulnerable#test -(refs)> ps:contact +:name=bar'))
|
|
702
|
+
self.len(1, await core.nodes('risk:vulnerable#test :vuln -> risk:vuln +#test'))
|
|
703
|
+
self.len(1, await core.nodes('risk:vulnerable#test :node -> * +it:prod:softver +#test'))
|
|
704
|
+
|
|
705
|
+
# migrate guids - node existence not required
|
|
706
|
+
|
|
707
|
+
nodes = await core.nodes('''
|
|
708
|
+
[ risk:hasvuln=$guid01
|
|
709
|
+
:software=$lib.guid()
|
|
710
|
+
:vuln=$lib.guid()
|
|
711
|
+
]
|
|
712
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
713
|
+
''', opts=opts)
|
|
714
|
+
self.len(1, nodes)
|
|
715
|
+
self.eq(guid01, nodes[0].ndef[1])
|
|
716
|
+
self.nn(nodes[0].get('node'))
|
|
717
|
+
self.nn(nodes[0].get('vuln'))
|
|
718
|
+
|
|
719
|
+
# multi-prop - unique guids by prop
|
|
720
|
+
|
|
721
|
+
nodes = await core.nodes('''
|
|
722
|
+
[ risk:hasvuln=$guid02
|
|
723
|
+
:hardware={[ it:prod:hardware=* ]}
|
|
724
|
+
:host={[ it:host=* ]}
|
|
725
|
+
:item={[ mat:item=* ]}
|
|
726
|
+
:org={[ ou:org=* ]}
|
|
727
|
+
:person={[ ps:person=* ]}
|
|
728
|
+
:place={[ geo:place=* ]}
|
|
729
|
+
:software={ it:prod:softver#test }
|
|
730
|
+
:spec={[ mat:spec=* ]}
|
|
731
|
+
:vuln={ risk:vuln#test }
|
|
732
|
+
+#test2
|
|
733
|
+
]
|
|
734
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
735
|
+
''', opts=opts)
|
|
736
|
+
self.len(8, nodes)
|
|
737
|
+
self.false(any(n.ndef[1] == guid02 for n in nodes))
|
|
738
|
+
self.true(all(n.hasTag('test2') for n in nodes))
|
|
739
|
+
nodes.sort(key=lambda n: n.get('node'))
|
|
740
|
+
self.eq(
|
|
741
|
+
['geo:place', 'it:host', 'it:prod:hardware', 'it:prod:softver',
|
|
742
|
+
'mat:item', 'mat:spec', 'ou:org', 'ps:person'],
|
|
743
|
+
[n.get('node')[0] for n in nodes]
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
self.len(2, await core.nodes('it:prod:softver#test -> risk:vulnerable +{ :vuln -> risk:vuln +#test }'))
|
|
747
|
+
|
|
748
|
+
# nodata
|
|
749
|
+
|
|
750
|
+
self.len(1, await core.nodes('risk:vulnerable=$guid00 $node.data.pop(baz)', opts=opts))
|
|
751
|
+
|
|
752
|
+
nodes = await core.nodes('''
|
|
753
|
+
risk:hasvuln=$guid00 $n=$node
|
|
754
|
+
-> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n, nodata=$lib.true) }
|
|
755
|
+
''', opts=opts)
|
|
756
|
+
self.len(1, nodes)
|
|
757
|
+
self.none(await nodes[0].getData('baz'))
|
|
758
|
+
|
|
759
|
+
# no-ops
|
|
760
|
+
|
|
761
|
+
self.len(0, await core.nodes('''
|
|
762
|
+
[ risk:hasvuln=* ]
|
|
763
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
764
|
+
'''))
|
|
765
|
+
|
|
766
|
+
self.len(0, await core.nodes('''
|
|
767
|
+
[ risk:hasvuln=* :vuln={[ risk:vuln=* ]} ]
|
|
768
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
769
|
+
'''))
|
|
770
|
+
|
|
771
|
+
self.len(0, await core.nodes('''
|
|
772
|
+
[ risk:hasvuln=* :host={[ it:host=* ]} ]
|
|
773
|
+
$n=$node -> { yield $lib.model.migration.s.riskHasVulnToVulnerable($n) }
|
|
774
|
+
'''))
|
|
775
|
+
|
|
776
|
+
# perms
|
|
777
|
+
|
|
778
|
+
lowuser = await core.auth.addUser('low')
|
|
779
|
+
aslow = {'user': lowuser.iden}
|
|
780
|
+
|
|
781
|
+
await lowuser.addRule((True, ('node', 'tag', 'add')))
|
|
782
|
+
|
|
783
|
+
await core.nodes('''
|
|
784
|
+
[ risk:hasvuln=*
|
|
785
|
+
:vuln={[ risk:vuln=* ]}
|
|
786
|
+
:host={[ it:host=* ]}
|
|
787
|
+
.seen=2010
|
|
788
|
+
+#test.low
|
|
789
|
+
]
|
|
790
|
+
''')
|
|
791
|
+
|
|
792
|
+
scmd = '''
|
|
793
|
+
risk:hasvuln#test.low $n=$node
|
|
794
|
+
-> {
|
|
795
|
+
yield $lib.model.migration.s.riskHasVulnToVulnerable($n)
|
|
796
|
+
}
|
|
797
|
+
'''
|
|
798
|
+
|
|
799
|
+
with self.raises(s_exc.AuthDeny) as ectx:
|
|
800
|
+
await core.nodes(scmd, opts=aslow)
|
|
801
|
+
self.eq(perm := 'node.add.risk:vulnerable', ectx.exception.errinfo['perm'])
|
|
802
|
+
await lowuser.addRule((True, perm.split('.')))
|
|
803
|
+
|
|
804
|
+
with self.raises(s_exc.AuthDeny) as ectx:
|
|
805
|
+
await core.nodes(scmd, opts=aslow)
|
|
806
|
+
self.eq(perm := 'node.prop.set.risk:vulnerable.vuln', ectx.exception.errinfo['perm'])
|
|
807
|
+
await lowuser.addRule((True, perm.split('.')))
|
|
808
|
+
|
|
809
|
+
with self.raises(s_exc.AuthDeny) as ectx:
|
|
810
|
+
await core.nodes(scmd, opts=aslow)
|
|
811
|
+
self.eq(perm := 'node.prop.set.risk:vulnerable.node', ectx.exception.errinfo['perm'])
|
|
812
|
+
await lowuser.addRule((True, perm.split('.')))
|
|
813
|
+
|
|
814
|
+
with self.raises(s_exc.AuthDeny) as ectx:
|
|
815
|
+
await core.nodes(scmd, opts=aslow)
|
|
816
|
+
self.eq(perm := 'node.prop.set.risk:vulnerable..seen', ectx.exception.errinfo['perm'])
|
|
817
|
+
await lowuser.addRule((True, perm.split('.', maxsplit=4)))
|
|
818
|
+
|
|
819
|
+
self.len(1, await core.nodes(scmd, opts=aslow))
|
|
820
|
+
|
|
821
|
+
# bad inputs
|
|
822
|
+
|
|
823
|
+
with self.raises(s_exc.BadArg) as ectx:
|
|
824
|
+
await core.nodes('[ it:host=* ] $lib.model.migration.s.riskHasVulnToVulnerable($node)')
|
|
825
|
+
self.isin('only accepts risk:hasvuln nodes', ectx.exception.errinfo['mesg'])
|
|
826
|
+
|
|
827
|
+
with self.raises(s_exc.BadArg) as ectx:
|
|
828
|
+
await core.nodes('$lib.model.migration.s.riskHasVulnToVulnerable(newp)')
|
|
829
|
+
self.isin('must be a node', ectx.exception.errinfo['mesg'])
|