# Hexarch Guardrails Python SDK

**Stop production disasters before they happen.** Lightweight policy-driven API protection for students, solo developers, and hackathons.

## 🚨 Stop Disasters Before They Happen

**Has this ever happened to you?**

```python
# Innocent cleanup script...
def cleanup_old_data():
    db.execute("DELETE FROM users WHERE last_login < '2023-01-01'")

cleanup_old_data()  # 💥 Just deleted 10,000 production records
```

**Or this?**

```python
# Weekend GPT-4 experiment...
for prompt in user_prompts:  # 1000 prompts
    openai.ChatCompletion.create(model="gpt-4", ...)
    
# Monday morning: $4,200 OpenAI bill 💸
```

**With Hexarch Guardrails:**

```python
from hexarch_guardrails import Guardian
guardian = Guardian()

@guardian.check("safe_delete")  # ← Add one line
def cleanup_old_data():
    db.execute("DELETE FROM users WHERE last_login < '2023-01-01'")

# Now it blocks: ❌ [BLOCKED] Policy 'safe_delete' requires confirmation
```

[**→ Try the 30-second interactive demo**](https://github.com/no1rstack/Hexarch/tree/main/hexarch-guardrails-py/examples/safe_automation_runner)

---

## Source-of-truth

This SDK is synced from the private monorepo (`no1rstack/Hexarch`) via an automated subtree publish workflow.

## Installation

```bash
pip install hexarch-guardrails
```

## Quick Start

### 1. Create a policy file (`hexarch.yaml`)

```yaml
policies:
  - id: "api_budget"
    description: "Protect against overspending"
    rules:
      - resource: "openai"
        monthly_budget: 10
        action: "warn_at_80%"

  - id: "rate_limit"
    description: "Prevent API abuse"
    rules:
      - resource: "*"
        requests_per_minute: 100
        action: "block"

  - id: "safe_delete"
    description: "Require confirmation for destructive ops"
    rules:
      - operation: "delete"
        action: "require_confirmation"
```

### 2. Use in your code

```python
from hexarch_guardrails import Guardian

# Initialize (auto-discovers hexarch.yaml)
guardian = Guardian()

# Protect API calls
@guardian.check("api_budget")
def call_openai(prompt):
    import openai
    return openai.ChatCompletion.create(
        model="gpt-4",
        messages=[{"role": "user", "content": prompt}]
    )

# Use it
response = call_openai("Hello AI!")
```

## Features

- ✅ **Zero-config** - Auto-discovers `hexarch.yaml`
- ✅ **Decorator-based** - Drop in `@guardian.check(policy_id)`
- ✅ **Policy-driven** - YAML-based rules, no code changes
- ✅ **Local-first** - Works offline or with local OPA
- ✅ **Pluggable** - Works with any API/SDK
- ✅ **Async-First** - Full support for `async def` functions
- ✅ **Fail-Safe** - Denials don't crash your app (logged gracefully)
- ✅ **Test-Friendly** - Bypass policies in test environments
- ✅ **Production-Ready** - Used in live systems handling millions of requests

## Examples

### Budget Protection (OpenAI)

```python
@guardian.check("api_budget")
def expensive_operation():
    # This call is protected by budget limits
    return openai.ChatCompletion.create(model="gpt-4", ...)
```

### Rate Limiting

```python
@guardian.check("rate_limit")
def send_discord_message(msg):
    return client.send(msg)
```

### Safe File Operations

```python
@guardian.check("safe_delete")
def delete_file(path):
    os.remove(path)
```

### Prevent API Bill Shock (Async)

```python
@guardian.check("openai_budget")
async def generate_content_batch(prompts: list[str]):
    return await asyncio.gather(*[
        openai.ChatCompletion.acreate(
            model="gpt-4",
            messages=[{"role": "user", "content": p}]
        ) for p in prompts
    ])

# hexarch.yaml enforces: max $100/month, warn at 80%
```

### Business Hours Enforcement

```python
@guardian.check("business_hours_only")
def send_customer_email_blast(emails: list[str]):
    for email in emails:
        send_marketing_email(email)

# Blocks execution outside 9am-5pm EST
# (Prevents accidental 3am customer notifications)
```

### Discord/Slack Rate Limiting

```python
@guardian.check("webhook_rate_limit")
def send_discord_alert(message: str):
    webhook.send(message)

# Automatically throttles to 5 msg/min (TOS compliant)
```

### Database Migration Safety

```python
@guardian.check("migration_safety")
def run_schema_migration(migration_file: str):
    db.execute_migration(migration_file)

# Requires: production env flag + confirmation + backup verified
```

### Safe Automation Runner (CLI demo app)

A minimal, self-contained example that shows rate limits, budgets, and destructive safeguards enforced at the function boundary.

- Docs + code: [examples/safe_automation_runner](examples/safe_automation_runner)

---

## Who Uses Hexarch?

- **Solo Developers** — Prevent accidental production disasters
- **Hackathon Teams** — Ship fast without breaking things  
- **Startups** — Enforce compliance before you have a DevOps team
- **AI/ML Engineers** — Control GPU/API costs without code changes
- **Enterprises** — Policy-as-code for regulated industries (HIPAA, SOC 2)

> *"Saved us from a $3k Anthropic bill when an intern accidentally ran a batch job with Claude Opus instead of Haiku."*  
> — Startup CTO using Hexarch in production

> *"We enforce 'no destructive operations after 4pm Friday' as policy. Game changer for weekend on-call."*  
> — Platform Engineer

---

## Why Not Just Use Try/Catch or Environment Variables?

**Try/catch** — Reactive. Runs code first, handles errors after damage is done.  
**Hexarch Guardrails** — Proactive. Blocks execution before the function body runs.

**Environment variables** — Scattered across codebase, easy to bypass.  
**Hexarch Guardrails** — Centralized policies in `hexarch.yaml`, enforced at the decorator boundary.

**Manual checks in every function** — Brittle, gets skipped during refactors.  
**Hexarch Guardrails** — One decorator, policies evolve without touching code.

---

## Documentation

- [Policy Authoring Guide](./docs/POLICY_GUIDE.md)
- [API Reference](./docs/API_REFERENCE.md)
- [Examples](./examples/)

## Admin CLI (v0.3.0+)

Hexarch includes a command-line interface for managing policies and monitoring decisions:

### Installation

```bash
# Install with CLI extras
pip install hexarch-guardrails[cli]
```

### Quick Start

```bash
# List all policies
hexarch-ctl policy list

# Export a policy
hexarch-ctl policy export ai_governance --format rego

# Validate policy syntax
hexarch-ctl policy validate ./policy.rego

# Compare policy versions
hexarch-ctl policy diff ai_governance
```

### Available Commands

**Policy Management**:
- `hexarch-ctl policy list` - List all OPA policies
- `hexarch-ctl policy export` - Export policy to file or stdout
- `hexarch-ctl policy validate` - Validate OPA policy syntax
- `hexarch-ctl policy diff` - Compare policy versions

**Upcoming** (Phase 3-4):
- Decision querying and analysis
- Metrics and performance monitoring
- Configuration management

For detailed CLI documentation, see [POLICY_COMMANDS_GUIDE.md](./POLICY_COMMANDS_GUIDE.md)

## REST API Server (Phase 3)

Hexarch includes a hardened FastAPI server intended to back a UI/dev workflow.

### Install server extras

```bash
pip install "hexarch-guardrails[server]"
```

### Run locally (recommended)

```bash
hexarch-ctl serve api --host 127.0.0.1 --port 8099 --init-db --api-token dev-token
```

Notes:
- `/health` is public; most endpoints require a bearer token.
- API key management endpoints (`/api-keys`) are disabled by default and can be enabled explicitly with `HEXARCH_API_KEY_ADMIN_ENABLED=true`.

## Credibility: OpenAPI fuzz scan (Schemathesis)

This repo includes a reproducible harness that starts the local FastAPI server with docs enabled and runs a Schemathesis scan against `/openapi.json`.

- Installs: `pip install -e ".[server,credibility]"`
- Runs (Windows): `./scripts/run_openapi_credibility_scan.ps1 -MaxExamples 25`
- Output: `evidence/credibility/openapi-schemathesis/<timestamp>/`

The scan is configured with a conservative credibility check (`not_a_server_error`) to demonstrate resilience under generated inputs (no 5xx), without requiring that every auth error path is explicitly modeled in the OpenAPI spec.

## Credibility: OWASP ZAP baseline scan (Docker)

This repo also includes an OWASP ZAP baseline scan harness (passive scan + spider) that produces HTML/JSON/XML/Markdown reports.

- Runs (Windows): `./scripts/run_zap_baseline_credibility_scan.ps1 -Mins 1 -MaxWaitMins 5`
- Output: `evidence/credibility/zap-baseline/<timestamp>/`

Notes:
- By default it keeps auth enabled (hardened posture) and does not fail the command on warnings; it always writes the reports.
- For deeper crawling you can run with `-AllowAnon` (this changes server posture for the scan).
- To propagate ZAP exit codes (WARN/FAIL), pass `-Strict`.

## Credibility: Policy correctness evals (golden cases)

Golden-case evaluation that exercises the decision engine via `POST /authorize` and writes a dated report.

- Cases file: `evals/policy_cases.json` (edit/extend this as you like)
- Runs (Windows): `./scripts/run_policy_credibility_evals.ps1`
- Output: `evidence/credibility/policy-evals/<timestamp>/` (`report.md`, `results.json`, `server.log`)

### Smoke test (starts server, hits `/health`, stops)

PowerShell:

```powershell
./scripts/smoke_api.ps1 -Port 8099
```

Bash:

```bash
./scripts/smoke_api.sh
```

## n8n End-to-End (Single User Milestone)

For a complete local workflow that (1) calls `/authorize`, (2) calls a provider (Ollama), and (3) logs a tamper-evident provider-call event via `/events/provider-calls`, see:

- [N8N_SINGLE_USER_MILESTONE.md](./N8N_SINGLE_USER_MILESTONE.md)

## Node-RED End-to-End (Single User Milestone)

If you prefer an Apache-2.0 OSS orchestrator for guardrails testing (authorize → echo → log provider call), see:

- [NODE_RED_SINGLE_USER_MILESTONE.md](./NODE_RED_SINGLE_USER_MILESTONE.md)

## License

MIT © Noir Stack LLC

See LICENSE for full details.

---

## Publishing to PyPI (Maintainers Only)

### Prerequisites

1. **Install build tools**:
   ```bash
   pip install --upgrade pip build twine
   ```

2. **PyPI Account Setup**:
   - Create account at https://pypi.org/account/register/
   - Enable 2FA (required for trusted publishers)
   - Generate API token: https://pypi.org/manage/account/token/
   - Save token securely (starts with `pypi-`)

3. **Configure PyPI credentials**:
   
   **Option A: Token in `.pypirc`** (recommended):
   ```bash
   # Create/edit ~/.pypirc (Linux/Mac) or %USERPROFILE%\.pypirc (Windows)
   [pypi]
   username = __token__
   password = pypi-YOUR_API_TOKEN_HERE
   ```

   **Option B: Environment variable**:
   ```bash
   # Linux/Mac
   export TWINE_USERNAME=__token__
   export TWINE_PASSWORD=pypi-YOUR_API_TOKEN_HERE

   # Windows PowerShell
   $env:TWINE_USERNAME = "__token__"
   $env:TWINE_PASSWORD = "pypi-YOUR_API_TOKEN_HERE"
   ```

### Pre-Publish Checklist

- [ ] Update version in `setup.py` or `pyproject.toml` (use semantic versioning: `0.4.0`, `1.0.0`, etc.)
- [ ] Update `CHANGELOG.md` with release notes
- [ ] Ensure `README.md` renders correctly (PyPI uses this as long description)
- [ ] Run tests: `pytest tests/`
- [ ] Build locally to verify: `python -m build`
- [ ] Check package metadata: `twine check dist/*`
- [ ] Tag release in git: `git tag v0.4.0 && git push origin v0.4.0`

### Publishing Steps

#### 1. Navigate to package directory

```bash
cd hexarch-guardrails-py
```

#### 2. Clean previous builds

```bash
# Linux/Mac
rm -rf build/ dist/ *.egg-info

# Windows PowerShell
Remove-Item -Recurse -Force build, dist, *.egg-info -ErrorAction SilentlyContinue
```

#### 3. Build distribution packages

```bash
python -m build
```

This creates:
- `dist/hexarch_guardrails-0.4.0-py3-none-any.whl` (wheel - preferred)
- `dist/hexarch-guardrails-0.4.0.tar.gz` (source distribution)

#### 4. Verify package contents

```bash
# Check metadata and README rendering
twine check dist/*

# Expected output:
# Checking dist/hexarch_guardrails-0.4.0-py3-none-any.whl: PASSED
# Checking dist/hexarch-guardrails-0.4.0.tar.gz: PASSED
```

#### 5. Test upload to TestPyPI (optional but recommended)

```bash
# Upload to TestPyPI
twine upload --repository testpypi dist/*

# Test install from TestPyPI
pip install --index-url https://test.pypi.org/simple/ hexarch-guardrails==0.4.0

# Verify it works
python -c "from hexarch_guardrails import Guardian; print('✓ Package OK')"
```

#### 6. Upload to production PyPI

```bash
twine upload dist/*
```

You'll see:
```
Uploading distributions to https://upload.pypi.org/legacy/
Uploading hexarch_guardrails-0.4.0-py3-none-any.whl
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 25.2/25.2 kB • 00:00
Uploading hexarch-guardrails-0.4.0.tar.gz
100% ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 22.8/22.8 kB • 00:00

View at:
https://pypi.org/project/hexarch-guardrails/0.4.0/
```

#### 7. Verify live package

```bash
# Wait 1-2 minutes for PyPI CDN propagation, then:
pip install --upgrade hexarch-guardrails

# Test
python -c "from hexarch_guardrails import Guardian; print(Guardian.__version__)"
```

#### 8. Announce release

- Update GitHub release notes: https://github.com/no1rstack/Hexarch/releases
- Tweet/social media: "🚀 Hexarch Guardrails v0.4.0 now on PyPI: [link]"
- Update docs site if applicable

### Troubleshooting

**Error: `403 Forbidden` during upload**
- Check API token is valid and not expired
- Ensure you have maintainer/owner role on the package
- Verify `.pypirc` formatting (no spaces around `=`)

**Error: `File already exists`**
- PyPI does not allow re-uploading the same version
- Increment version number in `setup.py`/`pyproject.toml`
- Rebuild: `python -m build`

**Error: `Invalid distribution metadata`**
- Run `twine check dist/*` to see specific errors
- Common issues:
  - Missing `README.md` reference in `setup.py`
  - Invalid `classifiers` in `setup.py`
  - Non-UTF-8 characters in `README.md`

**README not rendering on PyPI**
- Ensure `setup.py` has `long_description_content_type="text/markdown"`
- Check for unsupported Markdown extensions (PyPI uses CommonMark)
- Test locally: `python -m readme_renderer README.md -o /tmp/output.html`

**Package installs but imports fail**
- Verify `packages=find_packages()` in `setup.py` includes all submodules
- Check `MANIFEST.in` includes necessary non-Python files
- Test in clean virtualenv: `python -m venv test_env && source test_env/bin/activate`

### Automation (GitHub Actions)

For automated PyPI releases on git tags, see `.github/workflows/publish-pypi.yml` (if configured).

Example workflow trigger:
```bash
git tag v0.4.0
git push origin v0.4.0
# GitHub Actions automatically builds and publishes to PyPI
```

### Security Best Practices

- **Never** commit `.pypirc` or API tokens to git
- Use PyPI API tokens (not password) — tokens are scoped and revocable
- Enable 2FA on PyPI account
- Use different tokens for TestPyPI vs production PyPI
- Rotate tokens quarterly or after team member departures
- Consider using GitHub's OIDC trusted publisher (no tokens needed)

### Rollback Procedure

PyPI does not support deleting releases. If you need to rollback:

1. **Yank the bad release** (hides from `pip install` but keeps historical link):
   ```bash
   # Via PyPI web UI: Project → Releases → Manage → Yank
   ```

2. **Publish fixed version**:
   ```bash
   # Increment version: 0.4.0 → 0.4.1
   python -m build
   twine upload dist/*
   ```

3. **Notify users**:
   ```markdown
   ⚠️ **Security Advisory**: hexarch-guardrails 0.4.0 has been yanked due to [issue].
   Please upgrade to 0.4.1 immediately:
   
   pip install --upgrade hexarch-guardrails
   ```

---

**Questions?** Open an issue: https://github.com/no1rstack/Hexarch/issues  
**Want to contribute?** See [CONTRIBUTING.md](https://github.com/no1rstack/Hexarch/blob/main/CONTRIBUTING.md)
