Skip to main content

Runtime guardrail for tool/function calls: policy, optional approval, and a verifiable ledger.

Project description

sudoagent

SudoAgent Logo

CI PyPI License

SudoAgent Demo

A Python library that guards function calls at runtime with policy evaluation, optional human approval, and a verifiable ledger.

Version: 0.2.0 (v2 ledger/verification)

What it does

SudoAgent wraps a function call and enforces one of three outcomes:

  • allow: execute immediately
  • deny: block the call, raise ApprovalDenied
  • require_approval: request approval; executes only if approved

By default, SudoAgent writes two local files:

  • Audit log: sudo_audit.jsonl (operational record; not tamper-evident)
  • Ledger: sudo_ledger.jsonl (tamper-evident evidence; verifiable with sudoagent verify)

How it works

  1. You create a SudoEngine with a required policy.
  2. You decorate functions with @sudo.guard() or call sudo.execute(func, ...).
  3. The engine evaluates the policy, optionally invokes the approver, writes the decision to the ledger + audit log, and then executes (or denies).

Key behavior:

  • Decision logging happens before execution and is fail-closed. If logging fails, execution is blocked and AuditLogError is raised.
  • Outcome logging happens after execution and is best-effort. Logging failures do not affect the return value.
  • Approved actions produce two audit entries (decision + outcome). Denied actions produce one (decision only).
  • Entries for the same call are linked by request_id (UUID4).
  • Audit entries include timestamp, action, decision, reason, and safe representations of args/kwargs.

See docs/architecture.md for the full execution flow and audit semantics.

Install

pip install sudoagent

Optional extras:

  • Signing / receipts: pip install "sudoagent[crypto]"
  • Adapters: pip install "sudoagent[langchain]", pip install "sudoagent[crewai]", pip install "sudoagent[autogen]"

Dev install:

python -m venv .venv
source .venv/bin/activate  # Linux/macOS
# PowerShell: .\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"

Quickstart

Run the demo:

python examples/quickstart.py

What happens:

  • A low-value refund is allowed automatically.
  • A high-value refund triggers an interactive approval prompt.
  • Decisions/outcomes are written to sudo_audit.jsonl and sudo_ledger.jsonl.

For a 5-minute walkthrough and production checklist, see docs/quickstart.md. OSS guide: docs/oss_guide.md. FAQ / gotchas: docs/faq.md.

Full workflow demo (approval + budgets + verify):

SUDOAGENT_AUTO_APPROVE=1 python examples/workflow_demo.py
sudoagent verify sudo_ledger.jsonl

v2 ledger demo (decision_hash + verification):

python examples/v2_demo.py
sudoagent verify sudo_ledger.jsonl
# Or JSON output
sudoagent verify sudo_ledger.jsonl --json

(The demo writes sudo_ledger.jsonl in the current directory; delete it between runs if you want a fresh ledger.)

CLI export/filter/search:

sudoagent export sudo_ledger.jsonl --format json
sudoagent filter sudo_ledger.jsonl --request-id <id>
sudoagent search sudo_ledger.jsonl --query refund_user

Signing and receipts:

pip install "sudoagent[crypto]"
sudoagent keygen --private-key keys/private.pem --public-key keys/public.pem
sudoagent verify sudo_ledger.jsonl --public-key keys/public.pem
sudoagent receipt sudo_ledger.jsonl --request-id <id>

To run non-interactively (CI/demo):

SUDOAGENT_AUTO_APPROVE=1 python examples/quickstart.py

On Windows PowerShell:

$env:SUDOAGENT_AUTO_APPROVE="1"; python examples/quickstart.py

Basic usage

from sudoagent import ApprovalDenied, Context, Decision, PolicyResult, SudoEngine

class HighValueRefundPolicy:
    def evaluate(self, ctx: Context) -> PolicyResult:
        refund_amount = ctx.kwargs.get("refund_amount", 0)
        if refund_amount <= 500:
            return PolicyResult(decision=Decision.ALLOW, reason="within limit")
        return PolicyResult(decision=Decision.REQUIRE_APPROVAL, reason="over limit")

policy = HighValueRefundPolicy()
sudo = SudoEngine(policy=policy)

@sudo.guard()
def refund_user(user_id: str, refund_amount: float) -> None:
    print(f"Refunding {refund_amount} to {user_id}")

refund_user("user_1", refund_amount=10.0)

try:
    refund_user("user_2", refund_amount=1500.0)
except ApprovalDenied as e:
    print(f"Denied: {e}")

Core concepts

  • Context: captures the function call (action name, redacted args/kwargs, metadata).
  • Policy: returns ALLOW, DENY, or REQUIRE_APPROVAL with a reason.
  • Approver: handles the approval step. Default is InteractiveApprover (terminal y/n).
  • AuditLogger: writes audit entries. Default is JsonlAuditLogger.
  • Budgets: optional rate limits via BudgetManager (pass budget_cost to execute/guard for spend accounting).
  • Fail-closed: if policy, approval, or decision logging fails, execution is blocked.
  • decision_hash: SHA-256 over canonical decision payload (request_id, intent, parameters, actor, policy_hash).
  • policy_id: stable policy identifier (class name by default).
  • policy_hash: SHA-256 over canonicalized policy identifier (class name by default).
  • Ledger schema: entries include schema_version, ledger_version, agent_id, policy_id, policy_hash, and redacted args/kwargs metadata.
  • Ledger verification: sudoagent verify <ledger_path> checks schema/ledger versions, hash chain, and decision_hash references.

Reason codes

Stable, searchable reason codes are emitted in decision metadata and ledger entries:

  • POLICY_ALLOW_LOW_RISK
  • POLICY_DENY_HIGH_RISK
  • POLICY_REQUIRE_APPROVAL_HIGH_VALUE
  • POLICY_EVALUATION_FAILED
  • BUDGET_EXCEEDED_AGENT_RATE
  • BUDGET_EXCEEDED_TOOL_RATE
  • BUDGET_EVALUATION_FAILED
  • APPROVAL_DENIED
  • APPROVAL_PROCESS_FAILED
  • LEDGER_WRITE_FAILED_DECISION

Security

  • Threat model: see THREAT_MODEL.md.
  • Security policy: see SECURITY.md.
  • Rich markup in approval prompts is escaped to prevent terminal injection.
  • Redaction is centralized and applied before policy evaluation, approval prompts, and ledger hashing.
  • Audit logging redacts sensitive key names (api_key, token, password, etc.) and values (JWT-like strings, sk- prefixes, PEM blocks).
  • Decision logging failures raise AuditLogError and block execution. Outcome logging failures do not block.
  • Denied actions log the decision only. Approved actions log decision and outcome, linked by request_id.
  • SudoAgent is not a sandbox; protect the host and secrets separately.

Example audit entries:

{"event":"decision","request_id":"...","action":"...","decision":"allow","reason":"within limit",...}
{"event":"outcome","request_id":"...","outcome":"success",...}

Limitations:

  • This is not a sandbox. Side effects inside the guarded function are not prevented.
  • The default audit log (sudo_audit.jsonl) is not tamper-evident and is intended for single-process use.
  • The default JSONL ledger (sudo_ledger.jsonl) is single-writer; for multi-process on one host, use SQLiteLedger.

Extending

SudoAgent is designed for dependency injection:

  • Implement Policy.evaluate(ctx) -> PolicyResult.
  • Implement Approver.approve(ctx, result, request_id) -> bool (Slack/UI/etc.).
  • Implement Ledger for custom evidence stores.
  • Implement AuditLogger for operational logging sinks.

Notes:

  • Policy is required at construction. Pass AllowAllPolicy() explicitly for permissive mode.
  • InteractiveApprover is intended for local development. For production, implement a custom approver.

Adapters:

  • LangChain: pip install "sudoagent[langchain]" + docs/adapters.md
  • CrewAI: pip install "sudoagent[crewai]"
  • AutoGen: pip install "sudoagent[autogen]"

Roadmap

See ROADMAP.md for a short, best-effort plan.

Support policy

We support the latest minor release line. See SUPPORT.md for details.

Contributing

Small PRs are welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

pytest -q
ruff check .
mypy src

License

MIT License. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sudoagent-2.0.0.tar.gz (272.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sudoagent-2.0.0-py3-none-any.whl (33.8 kB view details)

Uploaded Python 3

File details

Details for the file sudoagent-2.0.0.tar.gz.

File metadata

  • Download URL: sudoagent-2.0.0.tar.gz
  • Upload date:
  • Size: 272.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for sudoagent-2.0.0.tar.gz
Algorithm Hash digest
SHA256 27fefc16f1a286b27dff8ad45ab4aa0b2adc2fe6ff4f8991ed437645dde967b2
MD5 88267100f33f881d4eeff01311d59bef
BLAKE2b-256 0553ecdcaf1b015781b4c6c4c005f32624b41c8d731c5e313966fdb28cd320f0

See more details on using hashes here.

File details

Details for the file sudoagent-2.0.0-py3-none-any.whl.

File metadata

  • Download URL: sudoagent-2.0.0-py3-none-any.whl
  • Upload date:
  • Size: 33.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for sudoagent-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6346e6f488c7a994a55ce3a5fb9a0f25a058fe2c3839955a4bf42ec4f09743d0
MD5 0d0eed74bae285bbfe532b357eeee244
BLAKE2b-256 82ed276048fb2b197cbfeab8d8e488787760a78706627e47addd02026312835f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page