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.

@@ -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
- nodes = await core.nodes('[ it:sec:cpe=cpe:2.3:a:vertex:synapse ]')
1782
- self.eq(nodes[0].ndef, ('it:sec:cpe', 'cpe:2.3:a:vertex:synapse:*:*:*:*:*:*:*:*'))
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
- nodes = await core.nodes("[ it:sec:cpe='cpe:2.3:a:openbsd:openssh:7.4\r\n:*:*:*:*:*:*:*' ]")
1796
- self.len(1, nodes)
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.path
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
- async def test_basics(self):
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
- filename = pathlib.Path(s_data.path(
49
- 'jsonschemas',
50
- 'raw.githubusercontent.com',
51
- 'oasis-open',
52
- 'cti-stix2-json-schemas',
53
- 'stix2.1',
54
- 'schemas',
55
- 'common',
56
- 'core.json'
57
- ))
58
-
59
- self.true(filename.exists())
60
- filename.unlink()
61
-
62
- # Clear the cached validator funcs so the ref handlers in s_getrefs get called
63
- s_config._JsValidators = {}
64
-
65
- with self.getLoggerStream('synapse.utils.getrefs') as stream:
66
- with self.getVcr() as cass:
67
- s_getrefs.main(args)
68
-
69
- stream.seek(0)
70
- mesgs = stream.read()
71
- mesg = f'Downloading schema from {CORE_URL}.'
72
- self.true(filename.exists())
73
- self.isin(mesg, mesgs)
74
- self.notin(f'Schema {CORE_URL} already exists in local cache, skipping.', mesgs)
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)
@@ -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
- for line in textwrap.wrap(desc, initial_indent='- ', subsequent_indent=' ', width=opts.width):
888
- text = f'{text}\n{line}'
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 requests
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('jsonschemas', parts.hostname, *parts.path.split('/'))
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(s_data.path('jsonschemas')):
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
- resp = requests.get(uri)
49
- data = resp.json()
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
1
+ Metadata-Version: 2.4
2
2
  Name: synapse
3
- Version: 2.186.0
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<25.0.0,>=24.0.0
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
  =======