Policy-driven approval library with interactive flows and audit logging.
Project description
sudoagent
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
- You create a
SudoEnginewith a required policy. - You decorate functions with
@sudo.guard()or callsudo.execute(func, ...). - 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
AuditLogErroris 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, orREQUIRE_APPROVALwith 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
AuditLogErrorand 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
Approverprotocol. - Implement the
AuditLoggerprotocol. - Pass them to
SudoEngine(policy=..., approver=..., logger=...).
Notes:
- Policy is required at construction. Pass
AllowAllPolicy()explicitly for permissive mode. InteractiveApproveris 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2a765f5034b5d3409d54489deda87803510e1c5c3dc97782ef5a0e0d5fcdf0f
|
|
| MD5 |
e194554da3d5328612973f566c5c4bf2
|
|
| BLAKE2b-256 |
cd89d28666b11d071fcc36f6cef12e42ddbabcc33da0e63810de4d31d776d3fa
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
802a13380f94e4ac9d415b233b988f2ef04638e5e662d5319e174ff256db5c6e
|
|
| MD5 |
1d6d212798256adc918b4034b135866b
|
|
| BLAKE2b-256 |
6abe434bc06bd034545a3c3d3f8d3aa113b3444d570cf0d4b7b083559d863ec9
|