Skip to main content

Policy-driven approval library with interactive flows and audit logging.

Project description

sudoagent

SudoAgent Architecture

A Python library that guards function calls at runtime with policy evaluation, optional human approval, and audit logging.

Version: 0.1.1

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

Every decision is recorded to an audit log (sudo_audit.jsonl by default).

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 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

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 are written to sudo_audit.jsonl.

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, 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.
  • Fail-closed: if policy, approval, or decision logging fails, execution is blocked.

Security notes

  • Rich markup in approval prompts is escaped to prevent terminal injection.
  • 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.

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 JSONL logger is intended for single-process use (append-only by normal operation, not tamper-evident). For multi-process or multi-host deployments, implement a custom AuditLogger.

Extending

v0.1 includes:

  • InteractiveApprover (terminal prompt)
  • JsonlAuditLogger (append-only JSONL)

To use Slack, email, web UIs, or a database:

  • Implement the Approver protocol.
  • Implement the AuditLogger protocol.
  • Pass them to SudoEngine(policy=..., approver=..., logger=...).

Notes:

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

Contributing

Small PRs are welcome. Include tests for new behavior.

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-0.1.1.tar.gz (777.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-0.1.1-py3-none-any.whl (13.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for sudoagent-0.1.1.tar.gz
Algorithm Hash digest
SHA256 c2a765f5034b5d3409d54489deda87803510e1c5c3dc97782ef5a0e0d5fcdf0f
MD5 e194554da3d5328612973f566c5c4bf2
BLAKE2b-256 cd89d28666b11d071fcc36f6cef12e42ddbabcc33da0e63810de4d31d776d3fa

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for sudoagent-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 802a13380f94e4ac9d415b233b988f2ef04638e5e662d5319e174ff256db5c6e
MD5 1d6d212798256adc918b4034b135866b
BLAKE2b-256 6abe434bc06bd034545a3c3d3f8d3aa113b3444d570cf0d4b7b083559d863ec9

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