synapse 2.168.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 +99 -10
- synapse/datamodel.py +5 -0
- synapse/lib/agenda.py +3 -0
- synapse/lib/ast.py +70 -12
- synapse/lib/cell.py +83 -21
- synapse/lib/httpapi.py +3 -0
- synapse/lib/layer.py +75 -6
- synapse/lib/node.py +7 -0
- synapse/lib/snap.py +25 -5
- synapse/lib/storm.py +1 -1
- synapse/lib/stormlib/cortex.py +1 -1
- synapse/lib/stormlib/model.py +420 -1
- synapse/lib/stormtypes.py +68 -3
- synapse/lib/types.py +35 -0
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +94 -24
- 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_agenda.py +17 -3
- synapse/tests/test_lib_ast.py +66 -0
- synapse/tests/test_lib_cell.py +133 -52
- 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 +27 -0
- synapse/tests/test_lib_stormlib_model.py +532 -0
- synapse/tests/test_lib_stormtypes.py +161 -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.168.0.dist-info → synapse-2.170.0.dist-info}/METADATA +1 -1
- {synapse-2.168.0.dist-info → synapse-2.170.0.dist-info}/RECORD +42 -41
- {synapse-2.168.0.dist-info → synapse-2.170.0.dist-info}/LICENSE +0 -0
- {synapse-2.168.0.dist-info → synapse-2.170.0.dist-info}/WHEEL +0 -0
- {synapse-2.168.0.dist-info → synapse-2.170.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import synapse.exc as s_exc
|
|
2
|
+
import synapse.lib.time as s_time
|
|
2
3
|
import synapse.lib.layer as s_layer
|
|
3
4
|
|
|
4
5
|
import synapse.tests.utils as s_test
|
|
@@ -295,3 +296,534 @@ class StormlibModelTest(s_test.SynTest):
|
|
|
295
296
|
|
|
296
297
|
self.stormIsInWarn('.pdep is not yet locked', mesgs)
|
|
297
298
|
self.stormNotInWarn('test:dep:easy.pdep is not yet locked', mesgs)
|
|
299
|
+
|
|
300
|
+
async def test_stormlib_model_migration(self):
|
|
301
|
+
|
|
302
|
+
async with self.getTestCore() as core:
|
|
303
|
+
|
|
304
|
+
nodes = await core.nodes('[ test:str=src test:str=dst test:str=deny test:str=other ]')
|
|
305
|
+
otheriden = nodes[3].iden()
|
|
306
|
+
|
|
307
|
+
lowuser = await core.auth.addUser('lowuser')
|
|
308
|
+
aslow = {'user': lowuser.iden}
|
|
309
|
+
|
|
310
|
+
# copy node data
|
|
311
|
+
|
|
312
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=src $lib.model.migration.copyData($node, newp)'))
|
|
313
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=dst $lib.model.migration.copyData(newp, $node)'))
|
|
314
|
+
|
|
315
|
+
nodes = await core.nodes('''
|
|
316
|
+
test:str=src
|
|
317
|
+
$node.data.set(a, a-src)
|
|
318
|
+
$node.data.set(b, b-src)
|
|
319
|
+
$n=$node -> {
|
|
320
|
+
test:str=dst
|
|
321
|
+
$node.data.set(a, a-dst)
|
|
322
|
+
$lib.model.migration.copyData($n, $node)
|
|
323
|
+
}
|
|
324
|
+
''')
|
|
325
|
+
self.len(1, nodes)
|
|
326
|
+
self.sorteq(
|
|
327
|
+
[('a', 'a-dst'), ('b', 'b-src')],
|
|
328
|
+
[data async for data in nodes[0].iterData()]
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
nodes = await core.nodes('''
|
|
332
|
+
test:str=src $n=$node -> {
|
|
333
|
+
test:str=dst
|
|
334
|
+
$lib.model.migration.copyData($n, $node, overwrite=$lib.true)
|
|
335
|
+
}
|
|
336
|
+
''')
|
|
337
|
+
self.len(1, nodes)
|
|
338
|
+
self.sorteq(
|
|
339
|
+
[('a', 'a-src'), ('b', 'b-src')],
|
|
340
|
+
[data async for data in nodes[0].iterData()]
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
q = 'test:str=src $n=$node -> { test:str=deny $lib.model.migration.copyData($n, $node) }'
|
|
344
|
+
await self.asyncraises(s_exc.AuthDeny, core.nodes(q, opts=aslow))
|
|
345
|
+
|
|
346
|
+
# copy edges
|
|
347
|
+
|
|
348
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=src $lib.model.migration.copyEdges($node, newp)'))
|
|
349
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=dst $lib.model.migration.copyEdges(newp, $node)'))
|
|
350
|
+
|
|
351
|
+
nodes = await core.nodes('''
|
|
352
|
+
test:str=src
|
|
353
|
+
[ <(foo)+ { test:str=other } +(bar)> { test:str=other } ]
|
|
354
|
+
$n=$node -> {
|
|
355
|
+
test:str=dst
|
|
356
|
+
$lib.model.migration.copyEdges($n, $node)
|
|
357
|
+
}
|
|
358
|
+
''')
|
|
359
|
+
self.len(1, nodes)
|
|
360
|
+
self.eq([('bar', otheriden)], [edge async for edge in nodes[0].iterEdgesN1()])
|
|
361
|
+
self.eq([('foo', otheriden)], [edge async for edge in nodes[0].iterEdgesN2()])
|
|
362
|
+
|
|
363
|
+
q = 'test:str=src $n=$node -> { test:str=deny $lib.model.migration.copyEdges($n, $node) }'
|
|
364
|
+
await self.asyncraises(s_exc.AuthDeny, core.nodes(q, opts=aslow))
|
|
365
|
+
|
|
366
|
+
# copy tags
|
|
367
|
+
|
|
368
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=src $lib.model.migration.copyTags($node, newp)'))
|
|
369
|
+
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=dst $lib.model.migration.copyTags(newp, $node)'))
|
|
370
|
+
|
|
371
|
+
await core.nodes('$lib.model.ext.addTagProp(test, (str, ({})), ({}))')
|
|
372
|
+
|
|
373
|
+
nodes = await core.nodes('''
|
|
374
|
+
test:str=src
|
|
375
|
+
[ +#foo=(2010, 2012) +#foo.bar +#baz:test=src ]
|
|
376
|
+
$n=$node -> {
|
|
377
|
+
test:str=dst
|
|
378
|
+
[ +#foo=(2010, 2011) +#baz:test=dst ]
|
|
379
|
+
$lib.model.migration.copyTags($n, $node)
|
|
380
|
+
}
|
|
381
|
+
''')
|
|
382
|
+
self.len(1, nodes)
|
|
383
|
+
self.sorteq([
|
|
384
|
+
('baz', (None, None)),
|
|
385
|
+
('foo', (s_time.parse('2010'), s_time.parse('2012'))),
|
|
386
|
+
('foo.bar', (None, None))
|
|
387
|
+
], nodes[0].getTags())
|
|
388
|
+
self.eq([], nodes[0].getTagProps('foo'))
|
|
389
|
+
self.eq([], nodes[0].getTagProps('foo.bar'))
|
|
390
|
+
self.eq([('test', 'dst')], [(k, nodes[0].getTagProp('baz', k)) for k in nodes[0].getTagProps('baz')])
|
|
391
|
+
|
|
392
|
+
nodes = await core.nodes('''
|
|
393
|
+
test:str=src $n=$node -> {
|
|
394
|
+
test:str=dst
|
|
395
|
+
$lib.model.migration.copyTags($n, $node, overwrite=$lib.true)
|
|
396
|
+
}
|
|
397
|
+
''')
|
|
398
|
+
self.len(1, nodes)
|
|
399
|
+
self.eq([('test', 'src')], [(k, nodes[0].getTagProp('baz', k)) for k in nodes[0].getTagProps('baz')])
|
|
400
|
+
|
|
401
|
+
q = 'test:str=src $n=$node -> { test:str=deny $lib.model.migration.copyTags($n, $node) }'
|
|
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'])
|