Skip to content

Add Tenuo authorization contrib module#1

Merged
aimable100 merged 1 commit intomainfrom
contrib/tenuo
Apr 14, 2026
Merged

Add Tenuo authorization contrib module#1
aimable100 merged 1 commit intomainfrom
contrib/tenuo

Conversation

@aimable100
Copy link
Copy Markdown

@aimable100 aimable100 commented Apr 14, 2026

Summary

Adds temporalio.contrib.tenuo, a SimplePlugin that wires Tenuo warrant-based authorization into Temporal workflows. Agents (workflows) carry signed warrants specifying which tools (activities) they can call and with what argument constraints. Sub-agents (child workflows) receive attenuated warrants — capabilities can only shrink, never expand.

  • TenuoPlugin — registers client interceptor (warrant header injection), worker interceptors (PoP signing + authorization verification), and sandbox passthrough for the tenuo native extension.
  • Thin adapter — only 3 symbols exported from the contrib module (TenuoPlugin, TENUO_PLUGIN_NAME, ensure_tenuo_workflow_runner). All other types are imported from tenuo.temporal, matching the pattern established by openai_agents and other contrib modules.
  • No private imports — all tenuo.temporal internals used by the plugin are exposed through public lazy-loaded names.

Files

File Lines Purpose
temporalio/contrib/tenuo/__init__.py 27 Public API (3 exports)
temporalio/contrib/tenuo/_plugin.py 180 TenuoPlugin SimplePlugin subclass
temporalio/contrib/tenuo/README.md 371 Documentation with multi-agent delegation example
tests/contrib/tenuo/test_tenuo.py 464 Unit tests + live integration tests
tests/contrib/tenuo/test_tenuo_replay.py 243 Record-and-replay determinism tests
pyproject.toml +2 tenuo optional dependency

Replay safety

Replay determinism is verified at two levels:

  1. Static analysis — source inspection confirms workflow.now() (not time.time()), no datetime.now(), no os.urandom/random/uuid4, no time.sleep, no threading.Thread.
  2. Live record-and-replay — workflows execute against a local Temporal server, history is captured via fetch_history(), and a fresh TenuoPlugin instance replays via Replayer. Tests cover single-tool and multi-tool (sequential PoP ordering) scenarios.

Integration tests

  • test_authorized_activity_succeeds — full warrant → PoP → authorization flow
  • test_start_workflow_authorizedstart_workflow_authorized returns a handle
  • test_unauthorized_activity_is_non_retryable — unauthorized tool call produces WorkflowFailureError with ApplicationError(non_retryable=True)
  • test_duplicate_registration_raises — same plugin instance on two workers raises RuntimeError

Test plan

  • pytest tests/contrib/tenuo/test_tenuo.py -v — unit + integration tests pass
  • pytest tests/contrib/tenuo/test_tenuo_replay.py -v — replay determinism tests pass
  • ruff check temporalio/contrib/tenuo/ tests/contrib/tenuo/ — no lint errors

Adds `temporalio.contrib.tenuo`, a SimplePlugin integration for
Tenuo warrant-based authorization in Temporal workflows.

The plugin (`TenuoPlugin`) wires client interceptors, worker
interceptors, and workflow sandbox passthrough in a single line:

    from temporalio.contrib.tenuo import TenuoPlugin
    plugin = TenuoPlugin(config)
    client = await Client.connect("localhost:7233", plugins=[plugin])

Key design decisions:
- Thin adapter: only TenuoPlugin, TENUO_PLUGIN_NAME, and
  ensure_tenuo_workflow_runner are exported from the contrib module.
  All other types (TenuoPluginConfig, EnvKeyResolver, etc.) are
  imported directly from tenuo.temporal.
- No private imports: all tenuo.temporal internals used by the plugin
  are exposed through public lazy-loaded names.
- No re-exports of external package types, matching the pattern
  established by openai_agents and other contrib modules.

Files:
- temporalio/contrib/tenuo/__init__.py — public API (3 exports)
- temporalio/contrib/tenuo/_plugin.py — TenuoPlugin SimplePlugin subclass
- temporalio/contrib/tenuo/README.md — multi-agent delegation example
- tests/contrib/tenuo/test_tenuo.py — unit + live integration tests
- tests/contrib/tenuo/test_tenuo_replay.py — record-and-replay tests
- pyproject.toml — tenuo optional dependency
@aimable100 aimable100 merged commit cad64dc into main Apr 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant