Metadata-Version: 2.4
Name: nodus-governance
Version: 0.1.0
Summary: Operator governance: scopes, policy bundles, trust surfaces, and immutable audit trail
Author: Shawn Knight
License: MIT
Project-URL: Homepage, https://github.com/Masterplanner25/nodus-governance
Project-URL: Repository, https://github.com/Masterplanner25/nodus-governance
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

# nodus-governance

**Operator governance for Nodus AI systems: scopes, policy bundles, trust
surfaces, and an immutable audit trail.**

Provides the management-plane primitives for controlling what operators can
do, which approval rules apply, which channel peers are trusted, and a
tamper-evident log of every governance decision. No required external
dependencies — pure stdlib.

> **Status:** v0.1.0 — prepared, not yet published.

---

## Install

```bash
pip install nodus-governance
```

---

## What it provides

| Component | Purpose |
|---|---|
| `OperatorScope` / `ScopeBundle` | Named permission sets for operators |
| `PolicyBundle` / `PolicyBundleRegistry` | Named approval rules + scope bundles |
| `TrustSurface` | Per-channel allowlist/blocklist of trusted peers |
| `AuditTrail` | Append-only governance event log with multi-field query |

---

## Scopes and permissions

```python
from nodus_governance import (
    OperatorScope, ScopeBundle, ALL_PERMISSIONS,
    PERM_MANAGE_AGENTS, PERM_MANAGE_KEYS,
    PERM_MANAGE_POLICIES, PERM_VIEW_AUDIT_TRAIL,
    PERM_MANAGE_EXTENSIONS, PERM_MANAGE_TRUST, PERM_ADMIN,
)

# Define a named scope
read_only = OperatorScope(
    name="read-only",
    permissions=frozenset({PERM_VIEW_AUDIT_TRAIL}),
)
admin_scope = OperatorScope(
    name="admin",
    permissions=ALL_PERMISSIONS,
)

# Collect scopes into a bundle
bundle = ScopeBundle(scopes=[read_only, admin_scope])
scope = bundle.get("admin")         # OperatorScope | None
has_perm = read_only.has(PERM_ADMIN)  # False
```

### Permission constants

| Constant | String value |
|---|---|
| `PERM_MANAGE_AGENTS` | `"manage_agents"` |
| `PERM_MANAGE_EXTENSIONS` | `"manage_extensions"` |
| `PERM_MANAGE_KEYS` | `"manage_keys"` |
| `PERM_MANAGE_POLICIES` | `"manage_policies"` |
| `PERM_VIEW_AUDIT_TRAIL` | `"view_audit_trail"` |
| `PERM_MANAGE_TRUST` | `"manage_trust"` |
| `PERM_ADMIN` | `"admin"` |

---

## PolicyBundle and registry

```python
from nodus_governance import PolicyBundle, PolicyBundleRegistry

bundle = PolicyBundle(
    name="standard",
    approval_rules={"agent.run": "require", "agent.cancel": "auto"},
    scope_bundle=my_scope_bundle,
)

registry = PolicyBundleRegistry()
registry.register(bundle)

policy = registry.get("standard")   # PolicyBundle | None
all_policies = registry.list_all()  # list[PolicyBundle]
registry.unregister("standard")
```

---

## TrustSurface

```python
from nodus_governance import TrustSurface

surface = TrustSurface(channel_id="slack", deny_by_default=True)

surface.allow(peer_id="U123", reason="verified team member")
surface.block(peer_id="U999", reason="known spam account")

surface.is_allowed("U123")   # True
surface.is_allowed("U999")   # False (blocked)
surface.is_allowed("U456")   # False (deny_by_default=True, not explicitly allowed)

entry = surface.get("U123")  # TrustEntry | None
surface.revoke("U123")       # remove from allowlist
```

---

## AuditTrail

```python
from nodus_governance import AuditTrail, AuditEntry

trail = AuditTrail()

trail.record(
    event_type="policy.applied",
    actor_id="operator-1",
    target_id="agent-run-abc",
    payload={"policy": "standard", "decision": "approve"},
)

# Query by multiple fields
entries = trail.query(event_type="policy.applied")
entries = trail.query(actor_id="operator-1")
entries = trail.query(target_id="agent-run-abc", limit=10)

# Each entry
entry = entries[0]
entry.id          # UUID str
entry.event_type  # str
entry.actor_id    # str | None
entry.target_id   # str | None
entry.payload     # dict | None
entry.timestamp   # datetime (UTC)
```

The audit trail is **append-only** — entries cannot be modified or deleted.

---

## Design

- **No required dependencies.** Pure stdlib (`threading`, `dataclasses`,
  `datetime`, `uuid`).
- **Thread-safe.** `PolicyBundleRegistry`, `TrustSurface`, and `AuditTrail`
  use `threading.Lock`.
- **Deny-by-default trust.** `TrustSurface(deny_by_default=True)` requires
  explicit `allow()` calls before a peer is trusted.
- **Immutable audit log.** `AuditTrail` is append-only with no delete or
  update operations.

---

## Development

```bash
pip install -e ".[dev]"
pytest tests/ -q
```

---

## License

MIT — see [LICENSE](LICENSE).
