C-6: ConnectorRuntime enforces capability_mask per operation.
READ-only ACs cannot invoke MUTATE operations (wipe, lock, retire).
C-7: AC validated against database (exists, active, not expired)
before connector invocation.
C-9: Delegated AC capability bounded by delegator's capability.
C-10: Command counter uses atomic SQL increment with limit check.
M-23: expire_stale() uses same atomic SQL pattern.
H-1: Sensitive credential fields hidden from repr/logs via repr=False.
H-2: Stub backend requires ALLOW_STUB_CREDENTIALS=true to activate.
H-3: Kerberos backend raises CredentialResolutionError instead of
returning stub ticket.
H-4: Chronicle INTENT emitted before execution, RESULT after.
H-5: device_id validated as UUID before Graph API URL interpolation.
H-8: ConnectorRuntime enforces governance for all connector invocations.
Signed-off-by: Tyler King <tking@guildhouse.dev>
57 lines
1.6 KiB
Python
57 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
import functools
|
|
import warnings
|
|
from collections.abc import AsyncIterator, Callable, Coroutine, Iterable, Iterator
|
|
from typing import ParamSpec, TypeVar
|
|
|
|
import anyio.to_thread
|
|
|
|
P = ParamSpec("P")
|
|
T = TypeVar("T")
|
|
|
|
|
|
async def run_until_first_complete(*args: tuple[Callable, dict]) -> None: # type: ignore[type-arg]
|
|
warnings.warn(
|
|
"run_until_first_complete is deprecated and will be removed in a future version.",
|
|
DeprecationWarning,
|
|
)
|
|
|
|
async with anyio.create_task_group() as task_group:
|
|
|
|
async def run(func: Callable[[], Coroutine]) -> None: # type: ignore[type-arg]
|
|
await func()
|
|
task_group.cancel_scope.cancel()
|
|
|
|
for func, kwargs in args:
|
|
task_group.start_soon(run, functools.partial(func, **kwargs))
|
|
|
|
|
|
async def run_in_threadpool(func: Callable[P, T], *args: P.args, **kwargs: P.kwargs) -> T:
|
|
func = functools.partial(func, *args, **kwargs)
|
|
return await anyio.to_thread.run_sync(func)
|
|
|
|
|
|
class _StopIteration(Exception):
|
|
pass
|
|
|
|
|
|
def _next(iterator: Iterator[T]) -> T:
|
|
# We can't raise `StopIteration` from within the threadpool iterator
|
|
# and catch it outside that context, so we coerce them into a different
|
|
# exception type.
|
|
try:
|
|
return next(iterator)
|
|
except StopIteration:
|
|
raise _StopIteration
|
|
|
|
|
|
async def iterate_in_threadpool(
|
|
iterator: Iterable[T],
|
|
) -> AsyncIterator[T]:
|
|
as_iterator = iter(iterator)
|
|
while True:
|
|
try:
|
|
yield await anyio.to_thread.run_sync(_next, as_iterator)
|
|
except _StopIteration:
|
|
break
|