synapse 2.186.0__py311-none-any.whl → 2.187.1__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 +2 -2
- synapse/lib/hive.py +1 -1
- synapse/lib/lmdbslab.py +2 -0
- synapse/lib/modelrev.py +794 -11
- synapse/lib/spooled.py +28 -4
- synapse/lib/storm.py +7 -0
- synapse/lib/stormlib/model.py +320 -250
- synapse/lib/stormtypes.py +36 -10
- synapse/lib/version.py +2 -2
- synapse/models/infotech.py +49 -22
- synapse/tests/test_lib_cell.py +1 -0
- synapse/tests/test_lib_lmdbslab.py +30 -0
- synapse/tests/test_lib_modelrev.py +918 -379
- synapse/tests/test_lib_spooled.py +36 -0
- synapse/tests/test_lib_stormlib_model.py +0 -270
- synapse/tests/test_lib_stormtypes.py +11 -0
- synapse/tests/test_model_infotech.py +14 -11
- synapse/tests/test_utils_getrefs.py +36 -29
- synapse/tools/changelog.py +11 -3
- synapse/utils/getrefs.py +18 -5
- {synapse-2.186.0.dist-info → synapse-2.187.1.dist-info}/METADATA +4 -3
- {synapse-2.186.0.dist-info → synapse-2.187.1.dist-info}/RECORD +25 -28
- {synapse-2.186.0.dist-info → synapse-2.187.1.dist-info}/WHEEL +1 -1
- synapse/assets/__init__.py +0 -35
- synapse/assets/storm/migrations/model-0.2.28.storm +0 -355
- synapse/tests/test_assets.py +0 -25
- {synapse-2.186.0.dist-info → synapse-2.187.1.dist-info/licenses}/LICENSE +0 -0
- {synapse-2.186.0.dist-info → synapse-2.187.1.dist-info}/top_level.txt +0 -0
|
@@ -28,11 +28,34 @@ class SpooledTest(s_test.SynTest):
|
|
|
28
28
|
|
|
29
29
|
await sset.add(10)
|
|
30
30
|
|
|
31
|
+
newset = await sset.copy()
|
|
32
|
+
self.len(1, newset)
|
|
33
|
+
self.true(10 in newset)
|
|
34
|
+
self.false(newset.fallback)
|
|
35
|
+
|
|
31
36
|
# Trigger fallback
|
|
32
37
|
await sset.add(20)
|
|
33
38
|
await sset.add(30)
|
|
34
39
|
await sset.add(None)
|
|
35
40
|
|
|
41
|
+
newset = await sset.copy()
|
|
42
|
+
self.true(10 in newset)
|
|
43
|
+
self.true(20 in newset)
|
|
44
|
+
self.true(30 in newset)
|
|
45
|
+
self.true(None in newset)
|
|
46
|
+
self.len(4, newset)
|
|
47
|
+
|
|
48
|
+
await newset.clear()
|
|
49
|
+
self.false(10 in newset)
|
|
50
|
+
self.false(20 in newset)
|
|
51
|
+
self.false(30 in newset)
|
|
52
|
+
self.false(None in newset)
|
|
53
|
+
self.len(0, newset)
|
|
54
|
+
|
|
55
|
+
self.true(os.path.isdir(newset.slab.path))
|
|
56
|
+
await newset.fini()
|
|
57
|
+
self.false(os.path.isdir(newset.slab.path))
|
|
58
|
+
|
|
36
59
|
self.len(4, sset)
|
|
37
60
|
|
|
38
61
|
await sset.add(20)
|
|
@@ -68,6 +91,17 @@ class SpooledTest(s_test.SynTest):
|
|
|
68
91
|
self.true(os.path.isdir(sset.slab.path))
|
|
69
92
|
self.true(os.path.abspath(sset.slab.path).startswith(dirn))
|
|
70
93
|
|
|
94
|
+
newset = await sset.copy()
|
|
95
|
+
self.true(os.path.isdir(newset.slab.path))
|
|
96
|
+
self.true(os.path.abspath(newset.slab.path).startswith(dirn))
|
|
97
|
+
|
|
98
|
+
# Slabs should get removed on fini
|
|
99
|
+
self.false(os.path.isdir(sset.slab.path))
|
|
100
|
+
|
|
101
|
+
self.true(os.path.isdir(newset.slab.path))
|
|
102
|
+
await newset.fini()
|
|
103
|
+
self.false(os.path.isdir(newset.slab.path))
|
|
104
|
+
|
|
71
105
|
async def test_spooled_dict(self):
|
|
72
106
|
|
|
73
107
|
async def runtest(x):
|
|
@@ -91,6 +125,8 @@ class SpooledTest(s_test.SynTest):
|
|
|
91
125
|
|
|
92
126
|
async with await s_spooled.Dict.anit(size=2) as sd0:
|
|
93
127
|
await runtest(sd0)
|
|
128
|
+
self.true(sd0.fallback)
|
|
94
129
|
|
|
95
130
|
async with await s_spooled.Dict.anit(size=1000) as sd1:
|
|
96
131
|
await runtest(sd1)
|
|
132
|
+
self.false(sd1.fallback)
|
|
@@ -403,24 +403,7 @@ class StormlibModelTest(s_test.SynTest):
|
|
|
403
403
|
q = 'test:str=src $n=$node -> { test:str=deny $lib.model.migration.copyTags($n, $node) }'
|
|
404
404
|
await self.asyncraises(s_exc.AuthDeny, core.nodes(q, opts=aslow))
|
|
405
405
|
|
|
406
|
-
with self.raises(s_exc.NoSuchProp) as exc:
|
|
407
|
-
await core.callStorm('$lib.model.migration.liftByPropValuNoNorm(formname, propname, valu)')
|
|
408
|
-
self.eq(exc.exception.get('mesg'), 'Could not find prop: formname:propname')
|
|
409
|
-
|
|
410
|
-
with self.raises(s_exc.AuthDeny) as exc:
|
|
411
|
-
await core.callStorm('$lib.model.migration.liftByPropValuNoNorm(it:prod:soft, cpe, valu)')
|
|
412
|
-
self.eq(exc.exception.get('mesg'), '$lib.model.migration.liftByPropValuNoNorm() is restricted to model migrations only.')
|
|
413
|
-
|
|
414
|
-
with self.raises(s_exc.BadArg) as exc:
|
|
415
|
-
await core.callStorm('$lib.model.migration.setNodePropValuNoNorm(notanode, propname, valu)')
|
|
416
|
-
self.eq(exc.exception.get('mesg'), '$lib.model.migration.setNodePropValuNoNorm() argument must be a node.')
|
|
417
|
-
|
|
418
|
-
with self.raises(s_exc.AuthDeny) as exc:
|
|
419
|
-
await core.callStorm('test:str $lib.model.migration.setNodePropValuNoNorm($node, propname, valu)')
|
|
420
|
-
self.eq(exc.exception.get('mesg'), '$lib.model.migration.setNodePropValuNoNorm() is restricted to model migrations only.')
|
|
421
|
-
|
|
422
406
|
# copy extended properties
|
|
423
|
-
|
|
424
407
|
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=src $lib.model.migration.copyExtProps($node, newp)'))
|
|
425
408
|
await self.asyncraises(s_exc.BadArg, core.nodes('test:str=dst $lib.model.migration.copyExtProps(newp, $node)'))
|
|
426
409
|
|
|
@@ -442,259 +425,6 @@ class StormlibModelTest(s_test.SynTest):
|
|
|
442
425
|
self.len(1, nodes)
|
|
443
426
|
self.eq(nodes[0].get('_foo'), 'foobarbaz')
|
|
444
427
|
|
|
445
|
-
async def test_model_migration_s_itSecCpe_2_170_0(self):
|
|
446
|
-
|
|
447
|
-
async with self.getRegrCore('itSecCpe_2_170_0', maxvers=(0, 2, 27)) as core:
|
|
448
|
-
# Migrate it:sec:cpe nodes with a valid CPE2.3, valid CPE2.2
|
|
449
|
-
q = 'it:sec:cpe +#test.cpe.23valid +#test.cpe.22valid'
|
|
450
|
-
nodes = await core.nodes(q)
|
|
451
|
-
self.len(2, nodes)
|
|
452
|
-
self.eq(
|
|
453
|
-
[
|
|
454
|
-
('it:sec:cpe', 'cpe:2.3:a:abine:donottrackme_-_mobile_privacy:1.1.8:*:*:*:*:android:*:*'),
|
|
455
|
-
('it:sec:cpe', 'cpe:2.3:a:01generator:pireospay:-:*:*:*:*:prestashop:*:*')
|
|
456
|
-
],
|
|
457
|
-
[node.ndef for node in nodes]
|
|
458
|
-
)
|
|
459
|
-
|
|
460
|
-
q = '''
|
|
461
|
-
it:sec:cpe +#test.cpe.23valid +#test.cpe.22valid
|
|
462
|
-
$lib.debug=$lib.true
|
|
463
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
464
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
465
|
-
'''
|
|
466
|
-
nodes = await core.nodes(q)
|
|
467
|
-
|
|
468
|
-
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
469
|
-
self.nn(data)
|
|
470
|
-
self.eq(data['status'], 'success')
|
|
471
|
-
self.none(data.get('reason'))
|
|
472
|
-
|
|
473
|
-
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
474
|
-
self.nn(data)
|
|
475
|
-
self.eq(data['status'], 'success')
|
|
476
|
-
self.none(data.get('reason'))
|
|
477
|
-
|
|
478
|
-
async with self.getRegrCore('itSecCpe_2_170_0', maxvers=(0, 2, 27)) as core:
|
|
479
|
-
# Migrate it:sec:cpe nodes with a valid CPE2.3, invalid CPE2.2
|
|
480
|
-
q = '''
|
|
481
|
-
it:sec:cpe +#test.cpe.23valid +#test.cpe.22invalid
|
|
482
|
-
$lib.debug=$lib.true
|
|
483
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
484
|
-
'''
|
|
485
|
-
nodes = await core.nodes(q)
|
|
486
|
-
self.len(3, nodes)
|
|
487
|
-
self.eq(
|
|
488
|
-
[
|
|
489
|
-
('it:sec:cpe', 'cpe:2.3:a:1c:1c\\:enterprise:-:*:*:*:*:*:*:*'),
|
|
490
|
-
('it:sec:cpe', 'cpe:2.3:o:zyxel:nas542_firmware:5.21\\%28aazf.15\\%29co:*:*:*:*:*:*:*'),
|
|
491
|
-
('it:sec:cpe', 'cpe:2.3:a:abinitio:control\\>center:-:*:*:*:*:*:*:*'),
|
|
492
|
-
],
|
|
493
|
-
[node.ndef for node in nodes]
|
|
494
|
-
)
|
|
495
|
-
|
|
496
|
-
q = '''
|
|
497
|
-
it:sec:cpe +#test.cpe.23valid +#test.cpe.22invalid
|
|
498
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
499
|
-
'''
|
|
500
|
-
nodes = await core.nodes(q)
|
|
501
|
-
self.len(3, nodes)
|
|
502
|
-
|
|
503
|
-
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
504
|
-
self.nn(data)
|
|
505
|
-
self.eq(data['status'], 'success')
|
|
506
|
-
self.eq(data['updated'], ['v2_2', 'product'])
|
|
507
|
-
self.eq(nodes[0].get('v2_2'), 'cpe:/a:1c:1c%3aenterprise:-')
|
|
508
|
-
self.eq(nodes[0].get('product'), '1c:enterprise')
|
|
509
|
-
|
|
510
|
-
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
511
|
-
self.nn(data)
|
|
512
|
-
self.eq(data['status'], 'success')
|
|
513
|
-
self.none(data.get('valu'))
|
|
514
|
-
self.eq(data['updated'], ['v2_2', 'version'])
|
|
515
|
-
self.eq(nodes[1].get('v2_2'), 'cpe:/o:zyxel:nas542_firmware:5.21%2528aazf.15%2529co')
|
|
516
|
-
self.eq(nodes[1].get('version'), '5.21%28aazf.15%29co')
|
|
517
|
-
|
|
518
|
-
data = nodes[2].nodedata['migration.s.itSecCpe_2_170_0']
|
|
519
|
-
self.nn(data)
|
|
520
|
-
self.eq(data['status'], 'success')
|
|
521
|
-
self.eq(data['updated'], ['v2_2', 'product'])
|
|
522
|
-
self.eq(nodes[2].get('v2_2'), 'cpe:/a:abinitio:control%3ecenter:-')
|
|
523
|
-
self.eq(nodes[2].get('product'), 'control>center')
|
|
524
|
-
|
|
525
|
-
# The migration of this node was not correct because the CPE2.3 string (primary property) is valid but was
|
|
526
|
-
# not created correctly due to a bad CPE2.2 input value. Now we update :v2_2 to be correct, and re-run the
|
|
527
|
-
# migration. This time, we specify `prefer_v22=True` and `force=True` so the migration will use the updated
|
|
528
|
-
# :v2_2 prop for reparsing the strings. Force will cause the migration to continue past the check where both
|
|
529
|
-
# the primary property and :v2_2 are valid.
|
|
530
|
-
q = '''
|
|
531
|
-
it:sec:cpe:product=nas542_firmware [ :v2_2="cpe:/o:zyxel:nas542_firmware:5.21%28aazf.15%29co" ]
|
|
532
|
-
$lib.debug=$lib.true
|
|
533
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node, prefer_v22=$lib.true, force=$lib.true)
|
|
534
|
-
'''
|
|
535
|
-
nodes = await core.nodes(q)
|
|
536
|
-
self.len(1, nodes)
|
|
537
|
-
|
|
538
|
-
# Lift the updated node and check the migration did what was expected.
|
|
539
|
-
q = '''
|
|
540
|
-
it:sec:cpe:product=nas542_firmware
|
|
541
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
542
|
-
'''
|
|
543
|
-
nodes = await core.nodes(q)
|
|
544
|
-
self.len(1, nodes)
|
|
545
|
-
|
|
546
|
-
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
547
|
-
self.nn(data)
|
|
548
|
-
self.eq(data['status'], 'success')
|
|
549
|
-
self.eq(data['updated'], ['version'])
|
|
550
|
-
self.eq(data['valu'], 'cpe:2.3:o:zyxel:nas542_firmware:5.21\\(aazf.15\\)co:*:*:*:*:*:*:*')
|
|
551
|
-
self.eq(nodes[0].get('v2_2'), 'cpe:/o:zyxel:nas542_firmware:5.21%28aazf.15%29co')
|
|
552
|
-
self.eq(nodes[0].get('version'), '5.21(aazf.15)co')
|
|
553
|
-
|
|
554
|
-
async with self.getRegrCore('itSecCpe_2_170_0', maxvers=(0, 2, 27)) as core:
|
|
555
|
-
# Migrate it:sec:cpe nodes with a invalid CPE2.3, valid CPE2.2
|
|
556
|
-
q = '''
|
|
557
|
-
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22valid
|
|
558
|
-
$lib.debug=$lib.true
|
|
559
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
560
|
-
'''
|
|
561
|
-
nodes = await core.nodes(q)
|
|
562
|
-
self.len(4, nodes)
|
|
563
|
-
self.eq(
|
|
564
|
-
[
|
|
565
|
-
('it:sec:cpe', 'cpe:2.3:h:d\\-link:dir\\-850l:*:*:*:*:*:*:*:*'),
|
|
566
|
-
('it:sec:cpe', 'cpe:2.3:a:acurax:under_construction_%2f_maintenance_mode:-::~~~wordpress~~:*:*:*:*:*'),
|
|
567
|
-
('it:sec:cpe', 'cpe:2.3:a:10web:social_feed_for_instagram:1.0.0::~~premium~wordpress~~:*:*:*:*:*'),
|
|
568
|
-
('it:sec:cpe', 'cpe:2.3:o:zyxel:nas326_firmware:5.21%28aazf.14%29c0:*:*:*:*:*:*:*'),
|
|
569
|
-
],
|
|
570
|
-
[node.ndef for node in nodes]
|
|
571
|
-
)
|
|
572
|
-
|
|
573
|
-
q = '''
|
|
574
|
-
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22valid
|
|
575
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
576
|
-
'''
|
|
577
|
-
nodes = await core.nodes(q)
|
|
578
|
-
self.len(4, nodes)
|
|
579
|
-
|
|
580
|
-
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
581
|
-
self.nn(data)
|
|
582
|
-
self.eq(data['status'], 'success')
|
|
583
|
-
self.eq(data['updated'], ['vendor', 'product'])
|
|
584
|
-
self.eq(data['valu'], 'cpe:2.3:h:d-link:dir-850l:*:*:*:*:*:*:*:*')
|
|
585
|
-
self.eq(nodes[0].get('vendor'), 'd-link')
|
|
586
|
-
self.eq(nodes[0].get('product'), 'dir-850l')
|
|
587
|
-
|
|
588
|
-
data = nodes[1].nodedata['migration.s.itSecCpe_2_170_0']
|
|
589
|
-
self.nn(data)
|
|
590
|
-
self.eq(data['status'], 'success')
|
|
591
|
-
self.eq(data['updated'], ['product', 'update', 'edition', 'target_sw'])
|
|
592
|
-
self.eq(data['valu'], 'cpe:2.3:a:acurax:under_construction_\\/_maintenance_mode:-:*:*:*:*:wordpress:*:*')
|
|
593
|
-
self.eq(nodes[1].get('product'), 'under_construction_/_maintenance_mode')
|
|
594
|
-
self.eq(nodes[1].get('update'), '*')
|
|
595
|
-
self.eq(nodes[1].get('edition'), '*')
|
|
596
|
-
self.eq(nodes[1].get('target_sw'), 'wordpress')
|
|
597
|
-
|
|
598
|
-
data = nodes[2].nodedata['migration.s.itSecCpe_2_170_0']
|
|
599
|
-
self.nn(data)
|
|
600
|
-
self.eq(data['status'], 'success')
|
|
601
|
-
self.eq(data['updated'], ['update', 'edition', 'sw_edition', 'target_sw'])
|
|
602
|
-
self.eq(data['valu'], 'cpe:2.3:a:10web:social_feed_for_instagram:1.0.0:*:*:*:premium:wordpress:*:*')
|
|
603
|
-
self.eq(nodes[2].get('update'), '*')
|
|
604
|
-
self.eq(nodes[2].get('edition'), '*')
|
|
605
|
-
self.eq(nodes[2].get('sw_edition'), 'premium')
|
|
606
|
-
self.eq(nodes[2].get('target_sw'), 'wordpress')
|
|
607
|
-
|
|
608
|
-
data = nodes[3].nodedata['migration.s.itSecCpe_2_170_0']
|
|
609
|
-
self.nn(data)
|
|
610
|
-
self.eq(data['status'], 'success')
|
|
611
|
-
self.eq(data['updated'], ['version'])
|
|
612
|
-
self.eq(data['valu'], 'cpe:2.3:o:zyxel:nas326_firmware:5.21\\(aazf.14\\)c0:*:*:*:*:*:*:*')
|
|
613
|
-
self.eq(nodes[3].get('version'), '5.21(aazf.14)c0')
|
|
614
|
-
|
|
615
|
-
async with self.getRegrCore('itSecCpe_2_170_0', maxvers=(0, 2, 27)) as core:
|
|
616
|
-
# Migrate it:sec:cpe nodes with a invalid CPE2.3, invalid CPE2.2
|
|
617
|
-
q = '''
|
|
618
|
-
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22invalid
|
|
619
|
-
$lib.debug=$lib.true
|
|
620
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
621
|
-
'''
|
|
622
|
-
msgs = await core.stormlist(q)
|
|
623
|
-
mesg = 'itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): '
|
|
624
|
-
mesg += 'Unable to migrate due to invalid data. Primary property and :v2_2 are both invalid.'
|
|
625
|
-
self.stormIsInWarn(mesg, msgs)
|
|
626
|
-
|
|
627
|
-
ndefs = [m[1][0] for m in msgs if m[0] == 'node']
|
|
628
|
-
self.eq(
|
|
629
|
-
[
|
|
630
|
-
('it:sec:cpe', 'cpe:2.3:a:openbsd:openssh:7.4\r\n:*:*:*:*:*:*:*'),
|
|
631
|
-
('it:sec:cpe', 'cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*')
|
|
632
|
-
],
|
|
633
|
-
ndefs
|
|
634
|
-
)
|
|
635
|
-
|
|
636
|
-
q = '''
|
|
637
|
-
it:sec:cpe +#test.cpe.23invalid +#test.cpe.22invalid
|
|
638
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
639
|
-
'''
|
|
640
|
-
nodes = await core.nodes(q)
|
|
641
|
-
self.len(2, nodes)
|
|
642
|
-
|
|
643
|
-
for node in nodes:
|
|
644
|
-
data = node.nodedata['migration.s.itSecCpe_2_170_0']
|
|
645
|
-
self.eq(data, {
|
|
646
|
-
'status': 'failed',
|
|
647
|
-
'reason': 'Unable to migrate due to invalid data. Primary property and :v2_2 are both invalid.',
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
# Now update the :v2_2 on one of the nodes and migrate again
|
|
651
|
-
q = '''
|
|
652
|
-
it:sec:cpe:version^=8.2p1 [ :v2_2="cpe:/a:openbsd:openssh:8.2p1_ubuntu-4ubuntu0.2" ]
|
|
653
|
-
$lib.debug=$lib.true
|
|
654
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
655
|
-
'''
|
|
656
|
-
msgs = await core.stormlist(q)
|
|
657
|
-
self.stormHasNoWarnErr(msgs)
|
|
658
|
-
|
|
659
|
-
q = '''
|
|
660
|
-
it:sec:cpe:version^=8.2p1
|
|
661
|
-
$node.data.load(migration.s.itSecCpe_2_170_0)
|
|
662
|
-
'''
|
|
663
|
-
nodes = await core.nodes(q)
|
|
664
|
-
self.len(1, nodes)
|
|
665
|
-
|
|
666
|
-
data = nodes[0].nodedata['migration.s.itSecCpe_2_170_0']
|
|
667
|
-
self.nn(data)
|
|
668
|
-
self.eq(data['status'], 'success')
|
|
669
|
-
self.eq(data['updated'], ['version'])
|
|
670
|
-
self.eq(data['valu'], 'cpe:2.3:a:openbsd:openssh:8.2p1_ubuntu-4ubuntu0.2:*:*:*:*:*:*:*')
|
|
671
|
-
self.eq(nodes[0].get('version'), '8.2p1_ubuntu-4ubuntu0.2')
|
|
672
|
-
|
|
673
|
-
# Run the migration again to make sure we identify already migrated
|
|
674
|
-
# nodes correctly and bail early.
|
|
675
|
-
q = '''
|
|
676
|
-
it:sec:cpe:version^=8.2p1
|
|
677
|
-
$lib.debug=$lib.true
|
|
678
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node)
|
|
679
|
-
'''
|
|
680
|
-
msgs = await core.stormlist(q)
|
|
681
|
-
self.stormIsInPrint('DEBUG: itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): Node already migrated.', msgs)
|
|
682
|
-
|
|
683
|
-
q = '''
|
|
684
|
-
it:sec:cpe:version^=8.2p1
|
|
685
|
-
$lib.debug=$lib.true
|
|
686
|
-
$lib.model.migration.s.itSecCpe_2_170_0($node, force=$lib.true)
|
|
687
|
-
'''
|
|
688
|
-
msgs = await core.stormlist(q)
|
|
689
|
-
self.stormIsInPrint('DEBUG: itSecCpe_2_170_0(it:sec:cpe=cpe:2.3:a:openbsd:openssh:8.2p1 ubuntu-4ubuntu0.2:*:*:*:*:*:*:*): No property updates required.', msgs)
|
|
690
|
-
|
|
691
|
-
async with self.getTestCore() as core:
|
|
692
|
-
with self.raises(s_exc.BadArg):
|
|
693
|
-
await core.callStorm('$lib.model.migration.s.itSecCpe_2_170_0(newp)')
|
|
694
|
-
|
|
695
|
-
with self.raises(s_exc.BadArg):
|
|
696
|
-
await core.callStorm('[ inet:fqdn=vertex.link ] $lib.model.migration.s.itSecCpe_2_170_0($node)')
|
|
697
|
-
|
|
698
428
|
async def test_stormlib_model_migrations_risk_hasvuln_vulnerable(self):
|
|
699
429
|
|
|
700
430
|
async with self.getTestCore() as core:
|
|
@@ -907,6 +907,17 @@ class StormTypesTest(s_test.SynTest):
|
|
|
907
907
|
'refs',
|
|
908
908
|
'20153b758f9d5eaaa38e4f4a65c36da797c3e59e549620fa7c4895e1a920991f'), edges)
|
|
909
909
|
|
|
910
|
+
data = await core.callStorm('''
|
|
911
|
+
$data = ({})
|
|
912
|
+
inet:user=visi
|
|
913
|
+
for ($name, $valu) in $lib.layer.get().getNodeData($node.iden()) { $data.$name = $valu }
|
|
914
|
+
return($data)
|
|
915
|
+
''')
|
|
916
|
+
foo = data.get('foo')
|
|
917
|
+
self.nn(foo)
|
|
918
|
+
self.nn(foo.get('asof'))
|
|
919
|
+
self.eq('bar', foo.get('data'))
|
|
920
|
+
|
|
910
921
|
msgs = await core.stormlist('$lib.print($lib.null)')
|
|
911
922
|
self.stormIsInPrint('$lib.null', msgs)
|
|
912
923
|
self.stormNotInPrint('None', msgs)
|
|
@@ -1778,8 +1778,17 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
1778
1778
|
with self.raises(s_exc.BadTypeValu):
|
|
1779
1779
|
nodes = await core.nodes('[it:sec:cpe=cpe:2.3:1:2:3:4:5:6:7:8:9:10:11:12]')
|
|
1780
1780
|
|
|
1781
|
-
|
|
1782
|
-
|
|
1781
|
+
with self.raises(s_exc.BadTypeValu):
|
|
1782
|
+
await core.nodes('[ it:sec:cpe=cpe:2.3:a:vertex:synapse ]')
|
|
1783
|
+
|
|
1784
|
+
with self.raises(s_exc.BadTypeValu):
|
|
1785
|
+
await core.callStorm(r'$lib.cast(it:sec:cpe, "cpe:2.3:a:openbsd:openssh:7.4\r\n:*:*:*:*:*:*:*")')
|
|
1786
|
+
|
|
1787
|
+
with self.raises(s_exc.BadTypeValu):
|
|
1788
|
+
await core.callStorm(r'$lib.cast(it:sec:cpe:v2_2, "cpe:/a:01generator:pireospay\r\n:-::~~~prestashop~~")')
|
|
1789
|
+
|
|
1790
|
+
with self.raises(s_exc.BadTypeValu):
|
|
1791
|
+
await core.callStorm('$lib.cast(it:sec:cpe:v2_2, "cpe:2.3:*")')
|
|
1783
1792
|
|
|
1784
1793
|
nodes = await core.nodes('''[
|
|
1785
1794
|
it:sec:cpe=cpe:2.3:a:microsoft:internet_explorer:8.0.6001:beta:*:*:*:*:*:*
|
|
@@ -1792,14 +1801,8 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
1792
1801
|
self.eq(nodes[0].get('version'), '8.0.6001')
|
|
1793
1802
|
self.eq(nodes[0].get('update'), 'beta')
|
|
1794
1803
|
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
self.eq(nodes[0].ndef, ('it:sec:cpe', 'cpe:2.3:a:openbsd:openssh:7.4:*:*:*:*:*:*:*'))
|
|
1798
|
-
self.eq(nodes[0].get('part'), 'a')
|
|
1799
|
-
self.eq(nodes[0].get('product'), 'openssh')
|
|
1800
|
-
self.eq(nodes[0].get('vendor'), 'openbsd')
|
|
1801
|
-
self.eq(nodes[0].get('version'), '7.4')
|
|
1802
|
-
self.eq(nodes[0].get('v2_2'), 'cpe:/a:openbsd:openssh:7.4')
|
|
1804
|
+
with self.raises(s_exc.BadTypeValu):
|
|
1805
|
+
await core.nodes("[ it:sec:cpe='cpe:2.3:a:openbsd:openssh:7.4\r\n:*:*:*:*:*:*:*' ]")
|
|
1803
1806
|
|
|
1804
1807
|
nodes = await core.nodes(r'[ it:sec:cpe="cpe:2.3:o:cisco:ios:12.1\(22\)ea1a:*:*:*:*:*:*:*" ]')
|
|
1805
1808
|
self.len(1, nodes)
|
|
@@ -1923,7 +1926,7 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
1923
1926
|
nodes = await core.nodes(q, opts={'vars': {'valu': valu}})
|
|
1924
1927
|
self.len(1, nodes)
|
|
1925
1928
|
node = nodes[0]
|
|
1926
|
-
self.eq(node.ndef[1], valu.lower())
|
|
1929
|
+
self.eq(node.ndef[1], valu.lower(), msg=valu.lower())
|
|
1927
1930
|
|
|
1928
1931
|
async def test_infotech_c2config(self):
|
|
1929
1932
|
async with self.getTestCore() as core:
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import os
|
|
1
|
+
import os
|
|
2
2
|
import pathlib
|
|
3
3
|
|
|
4
4
|
import vcr
|
|
5
5
|
|
|
6
|
+
from unittest import mock
|
|
7
|
+
|
|
6
8
|
import synapse.exc as s_exc
|
|
7
9
|
import synapse.data as s_data
|
|
10
|
+
import synapse.common as s_common
|
|
8
11
|
|
|
9
12
|
import synapse.lib.config as s_config
|
|
10
13
|
|
|
@@ -24,7 +27,7 @@ class TestUtilsGetrefs(s_utils.SynTest):
|
|
|
24
27
|
cm = myvcr.use_cassette(fp)
|
|
25
28
|
return cm
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
def test_basics(self):
|
|
28
31
|
|
|
29
32
|
args = s_getrefs.parse_args([
|
|
30
33
|
s_data.path('attack-flow', 'attack-flow-schema-2.0.0.json')
|
|
@@ -45,30 +48,34 @@ class TestUtilsGetrefs(s_utils.SynTest):
|
|
|
45
48
|
with self.raises(s_exc.BadArg):
|
|
46
49
|
s_getrefs.download_refs_handler('http://raw.githubusercontent.com/../../attack-flow/attack-flow-schema-2.0.0.json')
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
51
|
+
with self.getTestDir(copyfrom=s_getrefs.BASEDIR) as dirn:
|
|
52
|
+
|
|
53
|
+
filename = pathlib.Path(s_common.genpath(
|
|
54
|
+
dirn,
|
|
55
|
+
'raw.githubusercontent.com',
|
|
56
|
+
'oasis-open',
|
|
57
|
+
'cti-stix2-json-schemas',
|
|
58
|
+
'stix2.1',
|
|
59
|
+
'schemas',
|
|
60
|
+
'common',
|
|
61
|
+
'core.json'
|
|
62
|
+
))
|
|
63
|
+
|
|
64
|
+
self.true(filename.exists())
|
|
65
|
+
filename.unlink()
|
|
66
|
+
self.false(filename.exists())
|
|
67
|
+
|
|
68
|
+
# Clear the cached validator funcs so the ref handlers in s_getrefs get called
|
|
69
|
+
s_config._JsValidators = {}
|
|
70
|
+
|
|
71
|
+
with self.getLoggerStream('synapse.utils.getrefs') as stream:
|
|
72
|
+
with mock.patch('synapse.utils.getrefs.BASEDIR', dirn):
|
|
73
|
+
with self.getVcr():
|
|
74
|
+
s_getrefs.main(args)
|
|
75
|
+
|
|
76
|
+
stream.seek(0)
|
|
77
|
+
mesgs = stream.read()
|
|
78
|
+
mesg = f'Downloading schema from {CORE_URL}.'
|
|
79
|
+
self.true(filename.exists())
|
|
80
|
+
self.isin(mesg, mesgs)
|
|
81
|
+
self.notin(f'Schema {CORE_URL} already exists in local cache, skipping.', mesgs)
|
synapse/tools/changelog.py
CHANGED
|
@@ -883,9 +883,17 @@ async def format(opts: argparse.Namespace,
|
|
|
883
883
|
text = text + f'\n{header}\n{"-" * len(header)}'
|
|
884
884
|
dataz.sort(key=lambda x: x.get('prs'))
|
|
885
885
|
for data in dataz:
|
|
886
|
-
desc = data.get('desc')
|
|
887
|
-
|
|
888
|
-
|
|
886
|
+
desc = data.get('desc') # type: str
|
|
887
|
+
desc_lines = desc.splitlines()
|
|
888
|
+
for i, chunk in enumerate(desc_lines):
|
|
889
|
+
if i == 0:
|
|
890
|
+
for line in textwrap.wrap(chunk, initial_indent='- ', subsequent_indent=' ', width=opts.width):
|
|
891
|
+
text = f'{text}\n{line}'
|
|
892
|
+
else:
|
|
893
|
+
text = text + '\n'
|
|
894
|
+
for line in textwrap.wrap(chunk, initial_indent=' ', subsequent_indent=' ', width=opts.width):
|
|
895
|
+
text = f'{text}\n{line}'
|
|
896
|
+
|
|
889
897
|
if not opts.hide_prs:
|
|
890
898
|
for pr in data.get('prs'):
|
|
891
899
|
text = f'{text}\n (`#{pr} <https://github.com/vertexproject/synapse/pull/{pr}>`_)'
|
synapse/utils/getrefs.py
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import json
|
|
3
3
|
import urllib
|
|
4
|
+
import asyncio
|
|
4
5
|
import logging
|
|
5
6
|
import pathlib
|
|
6
7
|
import argparse
|
|
7
8
|
|
|
8
|
-
import
|
|
9
|
+
import aiohttp
|
|
9
10
|
|
|
10
11
|
import synapse.exc as s_exc
|
|
11
12
|
import synapse.data as s_data
|
|
@@ -15,23 +16,31 @@ import synapse.lib.config as s_config
|
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
19
|
+
BASEDIR = s_data.path('jsonschemas')
|
|
20
|
+
|
|
18
21
|
def download_refs_handler(uri):
|
|
19
22
|
'''
|
|
20
23
|
This function downloads the JSON schema at the given URI, parses the given
|
|
21
24
|
URI to get the path component, and then saves the referenced schema to the
|
|
22
25
|
'jsonschemas' directory of synapse.data.
|
|
26
|
+
|
|
27
|
+
This function runs its own asyncio loop for each URI being requested.
|
|
23
28
|
'''
|
|
29
|
+
ret = asyncio.run(_download_refs_handler(uri))
|
|
30
|
+
return ret
|
|
31
|
+
|
|
32
|
+
async def _download_refs_handler(uri):
|
|
24
33
|
|
|
25
34
|
try:
|
|
26
35
|
parts = urllib.parse.urlparse(uri)
|
|
27
36
|
except ValueError:
|
|
28
37
|
raise s_exc.BadUrl(mesg=f'Malformed URI: {uri}.') from None
|
|
29
38
|
|
|
30
|
-
filename = s_data.path(
|
|
39
|
+
filename = s_data.path(BASEDIR, parts.hostname, *parts.path.split('/'))
|
|
31
40
|
filepath = pathlib.Path(filename)
|
|
32
41
|
|
|
33
42
|
# Check for path traversal. Unlikely, but still check
|
|
34
|
-
if not str(filepath.absolute()).startswith(
|
|
43
|
+
if not str(filepath.absolute()).startswith(BASEDIR):
|
|
35
44
|
raise s_exc.BadArg(mesg=f'Path traversal in schema URL: {uri} ?')
|
|
36
45
|
|
|
37
46
|
# If we already have the file, return it
|
|
@@ -45,8 +54,12 @@ def download_refs_handler(uri):
|
|
|
45
54
|
|
|
46
55
|
# Get the data from the interwebs
|
|
47
56
|
logger.info(f'Downloading schema from {uri}.')
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
async with aiohttp.ClientSession() as session:
|
|
58
|
+
async with session.get(uri) as resp:
|
|
59
|
+
resp.raise_for_status()
|
|
60
|
+
buf = await resp.read()
|
|
61
|
+
|
|
62
|
+
data = json.loads(buf.decode())
|
|
50
63
|
|
|
51
64
|
# Save the json schema to disk
|
|
52
65
|
with filepath.open('w') as fp:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: synapse
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.187.1
|
|
4
4
|
Summary: Synapse Intelligence Analysis Framework
|
|
5
5
|
Author-email: The Vertex Project LLC <root@vertex.link>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -19,7 +19,7 @@ Classifier: Operating System :: POSIX :: Linux
|
|
|
19
19
|
Requires-Python: >=3.11
|
|
20
20
|
Description-Content-Type: text/x-rst
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: pyOpenSSL<
|
|
22
|
+
Requires-Dist: pyOpenSSL<24.3.0,>=24.0.0
|
|
23
23
|
Requires-Dist: cryptography<44.0.0,>=43.0.1
|
|
24
24
|
Requires-Dist: msgpack<1.1.0,>=1.0.5
|
|
25
25
|
Requires-Dist: xxhash<3.6.0,>=1.4.4
|
|
@@ -63,6 +63,7 @@ Requires-Dist: sphinx<9.0.0,>=8.0.0; extra == "docs"
|
|
|
63
63
|
Requires-Dist: sphinx-rtd-theme<4.0.0,>=3.0.0; extra == "docs"
|
|
64
64
|
Requires-Dist: sphinx-notfound-page<2.0.0,>=1.0.4; extra == "docs"
|
|
65
65
|
Requires-Dist: jinja2<4.0.0,>=3.1.4; extra == "docs"
|
|
66
|
+
Dynamic: license-file
|
|
66
67
|
|
|
67
68
|
Synapse
|
|
68
69
|
=======
|