synapse 2.164.0__py311-none-any.whl → 2.166.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (89) hide show
  1. synapse/axon.py +3 -3
  2. synapse/cmds/cortex.py +1 -6
  3. synapse/common.py +7 -1
  4. synapse/cortex.py +145 -192
  5. synapse/datamodel.py +36 -1
  6. synapse/lib/agenda.py +87 -97
  7. synapse/lib/aha.py +51 -0
  8. synapse/lib/ast.py +22 -23
  9. synapse/lib/base.py +0 -6
  10. synapse/lib/boss.py +3 -0
  11. synapse/lib/cell.py +70 -39
  12. synapse/lib/certdir.py +9 -0
  13. synapse/lib/hiveauth.py +65 -12
  14. synapse/lib/httpapi.py +1 -0
  15. synapse/lib/modelrev.py +121 -33
  16. synapse/lib/modules.py +1 -0
  17. synapse/lib/nexus.py +64 -26
  18. synapse/lib/parser.py +2 -0
  19. synapse/lib/schemas.py +14 -0
  20. synapse/lib/snap.py +50 -4
  21. synapse/lib/storm.lark +4 -3
  22. synapse/lib/storm.py +96 -22
  23. synapse/lib/storm_format.py +1 -0
  24. synapse/lib/stormlib/aha.py +7 -1
  25. synapse/lib/stormlib/auth.py +13 -5
  26. synapse/lib/stormlib/cache.py +202 -0
  27. synapse/lib/stormlib/cortex.py +147 -8
  28. synapse/lib/stormlib/gen.py +53 -6
  29. synapse/lib/stormlib/math.py +1 -1
  30. synapse/lib/stormlib/model.py +11 -1
  31. synapse/lib/stormlib/spooled.py +109 -0
  32. synapse/lib/stormlib/vault.py +1 -1
  33. synapse/lib/stormtypes.py +113 -17
  34. synapse/lib/trigger.py +36 -47
  35. synapse/lib/types.py +29 -2
  36. synapse/lib/version.py +2 -2
  37. synapse/lib/view.py +80 -53
  38. synapse/models/economic.py +174 -5
  39. synapse/models/files.py +2 -0
  40. synapse/models/inet.py +77 -2
  41. synapse/models/infotech.py +12 -12
  42. synapse/models/orgs.py +72 -21
  43. synapse/models/person.py +40 -11
  44. synapse/models/risk.py +78 -24
  45. synapse/models/science.py +102 -0
  46. synapse/telepath.py +117 -35
  47. synapse/tests/test_cortex.py +84 -158
  48. synapse/tests/test_datamodel.py +22 -0
  49. synapse/tests/test_lib_agenda.py +52 -96
  50. synapse/tests/test_lib_aha.py +126 -4
  51. synapse/tests/test_lib_ast.py +412 -6
  52. synapse/tests/test_lib_cell.py +24 -8
  53. synapse/tests/test_lib_certdir.py +32 -0
  54. synapse/tests/test_lib_grammar.py +9 -1
  55. synapse/tests/test_lib_httpapi.py +0 -1
  56. synapse/tests/test_lib_jupyter.py +0 -1
  57. synapse/tests/test_lib_modelrev.py +41 -0
  58. synapse/tests/test_lib_nexus.py +38 -0
  59. synapse/tests/test_lib_storm.py +95 -5
  60. synapse/tests/test_lib_stormlib_cache.py +272 -0
  61. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  62. synapse/tests/test_lib_stormlib_gen.py +37 -2
  63. synapse/tests/test_lib_stormlib_model.py +2 -0
  64. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  65. synapse/tests/test_lib_stormlib_vault.py +12 -3
  66. synapse/tests/test_lib_stormsvc.py +0 -10
  67. synapse/tests/test_lib_stormtypes.py +60 -8
  68. synapse/tests/test_lib_trigger.py +20 -2
  69. synapse/tests/test_lib_types.py +17 -1
  70. synapse/tests/test_model_economic.py +114 -0
  71. synapse/tests/test_model_files.py +2 -0
  72. synapse/tests/test_model_inet.py +73 -1
  73. synapse/tests/test_model_infotech.py +2 -2
  74. synapse/tests/test_model_orgs.py +10 -1
  75. synapse/tests/test_model_risk.py +30 -2
  76. synapse/tests/test_model_science.py +59 -0
  77. synapse/tests/test_model_syn.py +0 -1
  78. synapse/tests/test_telepath.py +30 -7
  79. synapse/tests/test_tools_modrole.py +81 -0
  80. synapse/tests/test_tools_moduser.py +105 -0
  81. synapse/tools/modrole.py +59 -7
  82. synapse/tools/moduser.py +78 -10
  83. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
  84. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/RECORD +87 -83
  85. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +1 -1
  86. synapse/lib/provenance.py +0 -111
  87. synapse/tests/test_lib_provenance.py +0 -37
  88. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
  89. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
synapse/datamodel.py CHANGED
@@ -116,6 +116,9 @@ class Prop:
116
116
  self.setperms.append(('node', 'prop', 'set', form.name, self.name))
117
117
  self.delperms.append(('node', 'prop', 'del', form.name, self.name))
118
118
 
119
+ self.setperms.reverse() # Make them in precedence order
120
+ self.delperms.reverse() # Make them in precedence order
121
+
119
122
  self.form = form
120
123
  self.type = None
121
124
  self.typedef = typedef
@@ -870,10 +873,42 @@ class Model:
870
873
  for ifname in form.type.info.get('interfaces', ()):
871
874
  self._addFormIface(form, ifname)
872
875
 
876
+ self._checkFormDisplay(form)
877
+
873
878
  self.formprefixcache.clear()
874
879
 
875
880
  return form
876
881
 
882
+ def _checkFormDisplay(self, form):
883
+
884
+ formtype = self.types.get(form.full)
885
+
886
+ display = formtype.info.get('display')
887
+ if display is None:
888
+ return
889
+
890
+ for column in display.get('columns', ()):
891
+ coltype = column.get('type')
892
+ colopts = column.get('opts')
893
+
894
+ if coltype == 'prop':
895
+ curf = form
896
+ propname = colopts.get('name')
897
+ parts = propname.split('::')
898
+
899
+ for partname in parts:
900
+ prop = curf.prop(partname)
901
+ if prop is None:
902
+ mesg = (f'Form {form.name} defines prop column {propname}'
903
+ f' but {curf.full} has no property named {partname}.')
904
+ raise s_exc.BadFormDef(mesg=mesg)
905
+
906
+ curf = self.form(prop.type.name)
907
+
908
+ else:
909
+ mesg = f'Form {form.name} defines column with invalid type ({coltype}).'
910
+ raise s_exc.BadFormDef(mesg=mesg)
911
+
877
912
  def delForm(self, formname):
878
913
 
879
914
  form = self.forms.get(formname)
@@ -960,7 +995,7 @@ class Model:
960
995
  iface = self.ifaces.get(name)
961
996
 
962
997
  if iface is None:
963
- mesg = f'Form {form.name} depends on non-existant interface: {name}'
998
+ mesg = f'Form {form.name} depends on non-existent interface: {name}'
964
999
  raise s_exc.NoSuchName(mesg=mesg)
965
1000
 
966
1001
  if iface.get('deprecated'):
synapse/lib/agenda.py CHANGED
@@ -16,7 +16,6 @@ import synapse.common as s_common
16
16
 
17
17
  import synapse.lib.base as s_base
18
18
  import synapse.lib.coro as s_coro
19
- import synapse.lib.provenance as s_provenance
20
19
 
21
20
  # Agenda: manages running one-shot and periodic tasks in the future ("appointments")
22
21
 
@@ -259,6 +258,7 @@ class _Appt:
259
258
  _synced_attrs = {
260
259
  'doc',
261
260
  'name',
261
+ 'pool',
262
262
  'created',
263
263
  'enabled',
264
264
  'errcount',
@@ -271,10 +271,11 @@ class _Appt:
271
271
  'lastfinishtime',
272
272
  }
273
273
 
274
- def __init__(self, stor, iden, recur, indx, query, creator, recs, nexttime=None, view=None, created=None):
274
+ def __init__(self, stor, iden, recur, indx, query, creator, recs, nexttime=None, view=None, created=None, pool=False):
275
275
  self.doc = ''
276
276
  self.name = ''
277
277
  self.stor = stor
278
+ self.pool = pool
278
279
  self.iden = iden
279
280
  self.recur = recur # does this appointment repeat
280
281
  self.indx = indx # incremented for each appt added ever. Used for nexttime tiebreaking for stable ordering
@@ -339,6 +340,7 @@ class _Appt:
339
340
  'ver': 1,
340
341
  'doc': self.doc,
341
342
  'name': self.name,
343
+ 'pool': self.pool,
342
344
  'enabled': self.enabled,
343
345
  'recur': self.recur,
344
346
  'iden': self.iden,
@@ -366,6 +368,7 @@ class _Appt:
366
368
  appt = cls(stor, val['iden'], val['recur'], val['indx'], val['query'], val['creator'], recs, nexttime=val['nexttime'], view=val.get('view'))
367
369
  appt.doc = val.get('doc', '')
368
370
  appt.name = val.get('name', '')
371
+ appt.pool = val.get('pool', False)
369
372
  appt.created = val.get('created', None)
370
373
  appt.laststarttime = val['laststarttime']
371
374
  appt.lastfinishtime = val['lastfinishtime']
@@ -449,46 +452,9 @@ class Agenda(s_base.Base):
449
452
  self.onfini(self._wake_event.set)
450
453
 
451
454
  self._hivenode = await self.core.hive.open(('agenda', 'appts')) # Persistent storage
452
- self.onfini(self.stop)
453
455
 
454
- self.enabled = False
455
- self._schedtask = None # The task of the scheduler loop. Doesn't run until we're enabled
456
-
457
- self._running_tasks = [] # The actively running cron job tasks
458
456
  await self._load_all()
459
457
 
460
- async def start(self):
461
- '''
462
- Enable cron jobs to start running, start the scheduler loop
463
-
464
- Go through all the appointments, making sure the query is valid, and remove the ones that aren't. (We can't
465
- evaluate queries until enabled because not all the modules are loaded yet.)
466
- '''
467
- if self.enabled:
468
- return
469
-
470
- await self._load_all()
471
- for iden, appt in self.appts.items():
472
- try:
473
- await self.core.getStormQuery(appt.query)
474
- except Exception as e:
475
- logger.exception(f'Invalid appointment {iden} {appt.name} found in storage. Disabling. {e}',
476
- extra={'synapse': {'iden': iden, 'name': appt.name, 'text': appt.query}})
477
- appt.enabled = False
478
-
479
- self._schedtask = self.schedCoro(self._scheduleLoop())
480
- self.enabled = True
481
-
482
- async def stop(self):
483
- "Cancel the scheduler loop, and set self.enabled to False."
484
- if not self.enabled:
485
- return
486
- self._schedtask.cancel()
487
- for task in self._running_tasks:
488
- await task.fini()
489
-
490
- self.enabled = False
491
-
492
458
  async def _load_all(self):
493
459
  '''
494
460
  Load all the appointments from persistent storage
@@ -599,6 +565,8 @@ class Agenda(s_base.Base):
599
565
  view = cdef.get('view')
600
566
  created = cdef.get('created')
601
567
 
568
+ pool = cdef.get('pool', False)
569
+
602
570
  recur = incunit is not None
603
571
  indx = self._next_indx
604
572
  self._next_indx += 1
@@ -639,7 +607,7 @@ class Agenda(s_base.Base):
639
607
  incvals = (incvals, )
640
608
  recs.extend(ApptRec(rd, incunit, v) for (rd, v) in itertools.product(reqdicts, incvals))
641
609
 
642
- appt = _Appt(self, iden, recur, indx, query, creator, recs, nexttime=nexttime, view=view, created=created)
610
+ appt = _Appt(self, iden, recur, indx, query, creator, recs, nexttime=nexttime, view=view, created=created, pool=pool)
643
611
  self._addappt(iden, appt)
644
612
 
645
613
  appt.doc = cdef.get('doc', '')
@@ -683,8 +651,7 @@ class Agenda(s_base.Base):
683
651
  if not query:
684
652
  raise ValueError('empty query')
685
653
 
686
- if self.enabled:
687
- await self.core.getStormQuery(query)
654
+ await self.core.getStormQuery(query)
688
655
 
689
656
  appt.query = query
690
657
  appt.enabled = True # in case it was disabled for a bad query
@@ -736,7 +703,14 @@ class Agenda(s_base.Base):
736
703
  self.tickoff += offs
737
704
  self._wake_event.set()
738
705
 
739
- async def _scheduleLoop(self):
706
+ async def clearRunningStatus(self):
707
+ '''Used for clearing the running state at startup or change of leadership.'''
708
+ for appt in list(self.appts.values()):
709
+ if appt.isrunning:
710
+ logger.debug(f'Clearing the isrunning flag for {appt.iden}')
711
+ await self.core.addCronEdits(appt.iden, {'isrunning': False})
712
+
713
+ async def runloop(self):
740
714
  '''
741
715
  Task loop to issue query tasks at the right times.
742
716
  '''
@@ -766,7 +740,7 @@ class Agenda(s_base.Base):
766
740
  if appt.nexttime:
767
741
  heapq.heappush(self.apptheap, appt)
768
742
 
769
- if not appt.enabled or not self.enabled:
743
+ if not appt.enabled:
770
744
  continue
771
745
 
772
746
  if appt.isrunning: # pragma: no cover
@@ -818,12 +792,10 @@ class Agenda(s_base.Base):
818
792
  return
819
793
 
820
794
  info = {'iden': appt.iden, 'query': appt.query, 'view': view.iden}
821
- task = await self.core.boss.execute(self._runJob(user, appt), f'Cron {appt.iden}', user, info=info)
822
795
 
823
- appt.task = task
824
- self._running_tasks.append(task)
825
-
826
- task.onfini(functools.partial(self._running_tasks.remove, task))
796
+ coro = self._runJob(user, appt)
797
+ task = self.core.runActiveTask(coro)
798
+ appt.task = await self.core.boss.promotetask(task, f'Cron {appt.iden}', user, info=info)
827
799
 
828
800
  async def _markfailed(self, appt, reason):
829
801
  now = self._getNowTick()
@@ -848,57 +820,75 @@ class Agenda(s_base.Base):
848
820
  }
849
821
  await self.core.addCronEdits(appt.iden, edits)
850
822
 
851
- with s_provenance.claim('cron', iden=appt.iden):
852
- logger.info(f'Agenda executing for iden={appt.iden}, name={appt.name} user={user.name}, view={appt.view}, query={appt.query}',
853
- extra={'synapse': {'iden': appt.iden, 'name': appt.name, 'user': user.iden, 'text': appt.query,
854
- 'username': user.name, 'view': appt.view}})
855
- starttime = self._getNowTick()
856
- success = False
857
- try:
858
- opts = {'user': user.iden, 'view': appt.view, 'vars': {'auto': {'iden': appt.iden, 'type': 'cron'}}}
859
- opts = self.core._initStormOpts(opts)
860
- view = self.core._viewFromOpts(opts)
861
- # Yes, this isn't technically on the bottom half of a nexus transaction
862
- # But because the scheduling loop only runs on non-mirrors, we can kinda skirt by all that
863
- # and be relatively okay. The only catch is that the nexus offset will correspond to the
864
- # last nexus transaction, and not the start/stop
865
- await self.core.feedBeholder('cron:start', {'iden': appt.iden})
866
- async for node in view.eval(appt.query, opts=opts, log_info={'cron': appt.iden}):
823
+ logger.info(f'Agenda executing for iden={appt.iden}, name={appt.name} user={user.name}, view={appt.view}, query={appt.query}',
824
+ extra={'synapse': {'iden': appt.iden, 'name': appt.name, 'user': user.iden, 'text': appt.query,
825
+ 'username': user.name, 'view': appt.view}})
826
+ starttime = self._getNowTick()
827
+ success = False
828
+ try:
829
+ opts = {
830
+ 'user': user.iden,
831
+ 'view': appt.view,
832
+ 'mirror': appt.pool,
833
+ 'vars': {'auto': {'iden': appt.iden, 'type': 'cron'}},
834
+ }
835
+ opts = self.core._initStormOpts(opts)
836
+
837
+ await self.core.feedBeholder('cron:start', {'iden': appt.iden})
838
+
839
+ async for mesg in self.core.storm(appt.query, opts=opts):
840
+
841
+ if mesg[0] == 'node':
867
842
  count += 1
868
- except asyncio.CancelledError:
869
- result = 'cancelled'
870
- raise
871
- except Exception as e:
872
- result = f'raised exception {e}'
873
- logger.exception(f'Agenda job {appt.iden} {appt.name} raised exception',
874
- extra={'synapse': {'iden': appt.iden, 'name': appt.name}}
875
- )
876
- else:
877
- success = True
878
- result = f'finished successfully with {count} nodes'
879
- finally:
880
- finishtime = self._getNowTick()
881
- if not success:
882
- appt.lasterrs.append(result)
883
- edits = {
884
- 'errcount': appt.errcount + 1,
885
- # we only care about the last five errors
886
- 'lasterrs': list(appt.lasterrs[-5:]),
887
- }
888
- await self.core.addCronEdits(appt.iden, edits)
889
843
 
890
- took = finishtime - starttime
891
- mesg = f'Agenda completed query for iden={appt.iden} name={appt.name} with result "{result}" ' \
892
- f'took {took:.3f}s'
893
- logger.info(mesg, extra={'synapse': {'iden': appt.iden, 'name': appt.name, 'user': user.iden,
894
- 'result': result, 'username': user.name, 'took': took}})
844
+ elif mesg[0] == 'err':
845
+ excname, errinfo = mesg[1]
846
+ errinfo.pop('eline', None)
847
+ errinfo.pop('efile', None)
848
+ excctor = getattr(s_exc, excname, s_exc.SynErr)
849
+ raise excctor(**errinfo)
850
+
851
+ except asyncio.CancelledError:
852
+ result = 'cancelled'
853
+ raise
854
+
855
+ except Exception as e:
856
+ result = f'raised exception {e}'
857
+ logger.exception(f'Agenda job {appt.iden} {appt.name} raised exception',
858
+ extra={'synapse': {'iden': appt.iden, 'name': appt.name}}
859
+ )
860
+ else:
861
+ success = True
862
+ result = f'finished successfully with {count} nodes'
863
+
864
+ finally:
865
+ finishtime = self._getNowTick()
866
+ if not success:
867
+ appt.lasterrs.append(result)
895
868
  edits = {
896
- 'lastfinishtime': finishtime,
897
- 'isrunning': False,
898
- 'lastresult': result,
869
+ 'errcount': appt.errcount + 1,
870
+ # we only care about the last five errors
871
+ 'lasterrs': list(appt.lasterrs[-5:]),
899
872
  }
873
+
874
+ if self.core.isactive:
875
+ await self.core.addCronEdits(appt.iden, edits)
876
+
877
+ took = finishtime - starttime
878
+ mesg = f'Agenda completed query for iden={appt.iden} name={appt.name} with result "{result}" ' \
879
+ f'took {took:.3f}s'
880
+ if not self.core.isactive:
881
+ mesg = mesg + ' Agenda status will not be saved since the Cortex is no longer the leader.'
882
+ logger.info(mesg, extra={'synapse': {'iden': appt.iden, 'name': appt.name, 'user': user.iden,
883
+ 'result': result, 'username': user.name, 'took': took}})
884
+ edits = {
885
+ 'lastfinishtime': finishtime,
886
+ 'isrunning': False,
887
+ 'lastresult': result,
888
+ }
889
+ if self.core.isactive:
900
890
  await self.core.addCronEdits(appt.iden, edits)
901
891
 
902
- if not self.isfini:
903
- # fire beholder event before invoking nexus change (in case readonly)
904
- await self.core.feedBeholder('cron:stop', {'iden': appt.iden})
892
+ if not self.isfini:
893
+ # fire beholder event before invoking nexus change (in case readonly)
894
+ await self.core.feedBeholder('cron:stop', {'iden': appt.iden})
synapse/lib/aha.py CHANGED
@@ -327,6 +327,20 @@ class AhaApi(s_cell.CellApi):
327
327
  '''
328
328
  return await self.cell.delAhaUserEnroll(iden)
329
329
 
330
+ @s_cell.adminapi()
331
+ async def clearAhaSvcProvs(self):
332
+ '''
333
+ Remove all unused service provisioning values.
334
+ '''
335
+ return await self.cell.clearAhaSvcProvs()
336
+
337
+ @s_cell.adminapi()
338
+ async def clearAhaUserEnrolls(self):
339
+ '''
340
+ Remove all unused user enrollment provisioning values.
341
+ '''
342
+ return await self.cell.clearAhaUserEnrolls()
343
+
330
344
  class ProvDmon(s_daemon.Daemon):
331
345
 
332
346
  async def __anit__(self, aha):
@@ -386,6 +400,9 @@ class EnrollApi:
386
400
  mesg = f'Invalid user CSR CN={name}.'
387
401
  raise s_exc.BadArg(mesg=mesg)
388
402
 
403
+ logger.info(f'Signing user CSR for [{username}], signas={ahanetw}',
404
+ extra=await self.aha.getLogExtra(name=username, signas=ahanetw))
405
+
389
406
  pkey, cert = self.aha.certdir.signUserCsr(xcsr, ahanetw, save=False)
390
407
  return self.aha.certdir._certToByts(cert)
391
408
 
@@ -415,6 +432,9 @@ class ProvApi:
415
432
  mesg = f'Invalid host CSR CN={name}.'
416
433
  raise s_exc.BadArg(mesg=mesg)
417
434
 
435
+ logger.info(f'Signing host CSR for [{hostname}], signas={ahanetw}',
436
+ extra=await self.aha.getLogExtra(name=hostname, signas=ahanetw))
437
+
418
438
  pkey, cert = self.aha.certdir.signHostCsr(xcsr, ahanetw, save=False)
419
439
  return self.aha.certdir._certToByts(cert)
420
440
 
@@ -431,6 +451,9 @@ class ProvApi:
431
451
  mesg = f'Invalid user CSR CN={name}.'
432
452
  raise s_exc.BadArg(mesg=mesg)
433
453
 
454
+ logger.info(f'Signing user CSR for [{username}], signas={ahanetw}',
455
+ extra=await self.aha.getLogExtra(name=username, signas=ahanetw))
456
+
434
457
  pkey, cert = self.aha.certdir.signUserCsr(xcsr, ahanetw, save=False)
435
458
  return self.aha.certdir._certToByts(cert)
436
459
 
@@ -1010,6 +1033,9 @@ class AhaCell(s_cell.Cell):
1010
1033
  mesg = 'The AHA server does not have a provision:listen URL!'
1011
1034
  raise s_exc.NeedConfValu(mesg=mesg)
1012
1035
 
1036
+ if not name:
1037
+ raise s_exc.BadArg(mesg='Empty name values are not allowed for provisioning.')
1038
+
1013
1039
  if provinfo is None:
1014
1040
  provinfo = {}
1015
1041
 
@@ -1039,6 +1065,10 @@ class AhaCell(s_cell.Cell):
1039
1065
 
1040
1066
  hostname = f'{name}.{netw}'
1041
1067
 
1068
+ if len(hostname) > 64:
1069
+ mesg = f'Hostname value must not exceed 64 characters in length. {hostname=}, len={len(hostname)}'
1070
+ raise s_exc.BadArg(mesg=mesg)
1071
+
1042
1072
  conf.setdefault('aha:name', name)
1043
1073
  dmon_port = provinfo.get('dmon:port', 0)
1044
1074
  dmon_listen = f'ssl://0.0.0.0:{dmon_port}?hostname={hostname}&ca={netw}'
@@ -1124,6 +1154,20 @@ class AhaCell(s_cell.Cell):
1124
1154
  self.slab.put(iden.encode(), s_msgpack.en(provinfo), db='aha:provs')
1125
1155
  return iden
1126
1156
 
1157
+ @s_nexus.Pusher.onPushAuto('aha:svc:prov:clear')
1158
+ async def clearAhaSvcProvs(self):
1159
+ for iden, byts in self.slab.scanByFull(db='aha:provs'):
1160
+ self.slab.delete(iden, db='aha:provs')
1161
+ provinfo = s_msgpack.un(byts)
1162
+ logger.info(f'Deleted service provisioning service={provinfo.get("conf").get("aha:name")}, iden={iden.decode()}')
1163
+
1164
+ @s_nexus.Pusher.onPushAuto('aha:enroll:clear')
1165
+ async def clearAhaUserEnrolls(self):
1166
+ for iden, byts in self.slab.scanByFull(db='aha:enrolls'):
1167
+ self.slab.delete(iden, db='aha:enrolls')
1168
+ userinfo = s_msgpack.un(byts)
1169
+ logger.info(f'Deleted user enrollment username={userinfo.get("name")}, iden={iden.decode()}')
1170
+
1127
1171
  @s_nexus.Pusher.onPushAuto('aha:svc:prov:del')
1128
1172
  async def delAhaSvcProv(self, iden):
1129
1173
  self.slab.delete(iden.encode(), db='aha:provs')
@@ -1140,8 +1184,15 @@ class AhaCell(s_cell.Cell):
1140
1184
  mesg = 'AHA server requires aha:network configuration.'
1141
1185
  raise s_exc.NeedConfValu(mesg=mesg)
1142
1186
 
1187
+ if not name:
1188
+ raise s_exc.BadArg(mesg='Empty name values are not allowed for provisioning.')
1189
+
1143
1190
  username = f'{name}@{ahanetw}'
1144
1191
 
1192
+ if len(username) > 64:
1193
+ mesg = f'Username value must not exceed 64 characters in length. username={username}, len={len(username)}'
1194
+ raise s_exc.BadArg(mesg=mesg)
1195
+
1145
1196
  user = await self.auth.getUserByName(username)
1146
1197
 
1147
1198
  if user is not None:
synapse/lib/ast.py CHANGED
@@ -24,7 +24,6 @@ import synapse.lib.scrape as s_scrape
24
24
  import synapse.lib.msgpack as s_msgpack
25
25
  import synapse.lib.spooled as s_spooled
26
26
  import synapse.lib.stormctrl as s_stormctrl
27
- import synapse.lib.provenance as s_provenance
28
27
  import synapse.lib.stormtypes as s_stormtypes
29
28
 
30
29
  from synapse.lib.stormtypes import tobool, toint, toprim, tostr, tonumber, tocmprvalu, undef
@@ -1180,33 +1179,32 @@ class CmdOper(Oper):
1180
1179
  mesg = f'Command ({name}) is not marked safe for readonly use.'
1181
1180
  raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
1182
1181
 
1183
- with s_provenance.claim('stormcmd', name=name):
1184
- async def genx():
1182
+ async def genx():
1185
1183
 
1186
- async for node, path in genr:
1187
- argv = await self.kids[1].compute(runt, path)
1188
- if not await scmd.setArgv(argv):
1189
- raise s_stormctrl.StormExit()
1184
+ async for node, path in genr:
1185
+ argv = await self.kids[1].compute(runt, path)
1186
+ if not await scmd.setArgv(argv):
1187
+ raise s_stormctrl.StormExit()
1190
1188
 
1191
- yield node, path
1189
+ yield node, path
1192
1190
 
1193
- # must pull through the genr to get opts set
1194
- # ( many commands expect self.opts is set at run() )
1195
- genr, empty = await pullone(genx())
1191
+ # must pull through the genr to get opts set
1192
+ # ( many commands expect self.opts is set at run() )
1193
+ genr, empty = await pullone(genx())
1196
1194
 
1197
- try:
1198
- if runtsafe:
1199
- argv = await self.kids[1].compute(runt, None)
1200
- if not await scmd.setArgv(argv):
1201
- raise s_stormctrl.StormExit()
1202
-
1203
- if runtsafe or not empty:
1204
- async with contextlib.aclosing(scmd.execStormCmd(runt, genr)) as agen:
1205
- async for item in agen:
1206
- yield item
1195
+ try:
1196
+ if runtsafe:
1197
+ argv = await self.kids[1].compute(runt, None)
1198
+ if not await scmd.setArgv(argv):
1199
+ raise s_stormctrl.StormExit()
1200
+
1201
+ if runtsafe or not empty:
1202
+ async with contextlib.aclosing(scmd.execStormCmd(runt, genr)) as agen:
1203
+ async for item in agen:
1204
+ yield item
1207
1205
 
1208
- finally:
1209
- await genr.aclose()
1206
+ finally:
1207
+ await genr.aclose()
1210
1208
 
1211
1209
  class SetVarOper(Oper):
1212
1210
 
@@ -3359,6 +3357,7 @@ class VarValue(Value):
3359
3357
  def prepare(self):
3360
3358
  assert isinstance(self.kids[0], Const)
3361
3359
  self.name = self.kids[0].value()
3360
+ self.isconst = False
3362
3361
 
3363
3362
  def isRuntSafe(self, runt):
3364
3363
  return runt.isRuntVar(self.name)
synapse/lib/base.py CHANGED
@@ -477,8 +477,6 @@ class Base:
477
477
  asyncio.Task: An asyncio.Task object.
478
478
 
479
479
  '''
480
- import synapse.lib.provenance as s_provenance # avoid import cycle
481
-
482
480
  if __debug__:
483
481
  assert inspect.isawaitable(coro)
484
482
  import synapse.lib.threads as s_threads # avoid import cycle
@@ -491,10 +489,6 @@ class Base:
491
489
 
492
490
  s_scope.clone(task)
493
491
 
494
- # In rare cases, (Like this function being triggered from call_soon_threadsafe), there's no task context
495
- if asyncio.current_task():
496
- s_provenance.dupstack(task)
497
-
498
492
  def taskDone(task):
499
493
  self._active_tasks.remove(task)
500
494
  try:
synapse/lib/boss.py CHANGED
@@ -41,6 +41,9 @@ class Boss(s_base.Base):
41
41
  s_task.Task: The Synapse Task object.
42
42
  '''
43
43
  task = asyncio.current_task()
44
+ return await self.promotetask(task, name, user, info=info, taskiden=taskiden)
45
+
46
+ async def promotetask(self, task, name, user, info=None, taskiden=None):
44
47
 
45
48
  synt = getattr(task, '_syn_task', None)
46
49