Metadata-Version: 2.4
Name: sfln
Version: 0.1.14
Summary: A framework for safety-critical operations with audit trails, locking, and approval workflows
Project-URL: Homepage, https://github.com/ccollicutt/safeline
Project-URL: Repository, https://github.com/ccollicutt/safeline
Project-URL: Issues, https://github.com/ccollicutt/safeline/issues
Author-email: Curtis Collicutt <curtis@serverascode.com>
License: MIT
License-File: LICENSE
Keywords: audit,operations,pipeline,safety,workflow
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Provides-Extra: all
Requires-Dist: click>=8.1.0; extra == 'all'
Requires-Dist: pyyaml>=6.0; extra == 'all'
Provides-Extra: cli
Requires-Dist: click>=8.1.0; extra == 'cli'
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: click>=8.1.0; extra == 'dev'
Requires-Dist: mypy>=1.5.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
Requires-Dist: pytest>=7.4.0; extra == 'dev'
Requires-Dist: pyyaml>=6.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Provides-Extra: yaml
Requires-Dist: pyyaml>=6.0; extra == 'yaml'
Description-Content-Type: text/markdown

# Safeline

A Python framework for building safety-critical operations with arbitrary stage pipelines, audit trails, locking, and approval workflows.

## Why Safeline?

When building tools that perform critical operations (deployments, data migrations, infrastructure changes), you need:

- **Structured workflows** - Break complex operations into reviewable stages
- **Audit trails** - Know who did what, when, and why
- **Approval gates** - Require sign-off before dangerous actions
- **Rollback support** - Undo operations when things go wrong
- **Environment awareness** - Different rules for prod vs dev

Safeline provides the infrastructure so you can focus on your domain logic.

## Installation

```bash
pip install sfln

# With optional dependencies
pip install sfln[cli]      # CLI support (click)
pip install sfln[yaml]     # YAML config (pyyaml)
pip install sfln[all]      # All optional deps
```

## Quick Example

Safeline recommends a standard stage pattern for safety-critical operations:

```
plan -> validate -> stage -> apply -> verify
```

- **plan** - Analyze what will be done, calculate risk
- **validate** - Check preconditions, ensure operation is safe to proceed
- **stage** - Prepare resources, create backups (reversible)
- **apply** - Execute the actual change (requires approval in production)
- **verify** - Confirm the operation succeeded

```python
from sfln import Operation, Stage, StageResult, Context, Safeline, MemoryStore

class DeployOperation(Operation):
    name = "deploy"
    stages = [
        Stage("plan"),
        Stage("validate"),
        Stage("stage", reversible=True),
        Stage("apply", needs_approval=True, reversible=True),
        Stage("verify"),
    ]

    def plan(self, context: Context) -> StageResult:
        # Analyze what will be deployed
        return StageResult(data={"targets": context.targets, "version": "2.0.0"})

    def validate(self, context: Context) -> StageResult:
        # Check preconditions
        return StageResult(data={"valid": True})

    def stage(self, context: Context) -> StageResult:
        # Create backup before changes
        backup_id = create_backup()
        return StageResult(
            data={"backup_id": backup_id},
            rollback_data={"backup_id": backup_id}
        )

    def apply(self, context: Context) -> StageResult:
        # Execute the deployment
        version = context.get_stage_result("plan")["version"]
        return StageResult(data={"deployed": version})

    def verify(self, context: Context) -> StageResult:
        # Confirm deployment succeeded
        return StageResult(data={"healthy": True})

    def rollback_stage(self, context: Context) -> StageResult:
        return StageResult(data={"cleaned": True})

    def rollback_apply(self, context: Context) -> StageResult:
        backup_id = context.get_stage_result("stage")["backup_id"]
        restore_from_backup(backup_id)
        return StageResult(data={"restored": True})

# Run it
sl = Safeline(store=MemoryStore())
result = sl.run(DeployOperation(targets=["app-server-1"]))
print(f"Success: {result.success}")
```

### Custom Stages

The standard stages are a recommendation, not a requirement. Define whatever stages make sense for your operation:

```python
# Database migration with custom stages
stages = [
    Stage("analyze"),
    Stage("backup_schema"),
    Stage("migrate", needs_approval=True),
    Stage("verify_data"),
    Stage("cleanup"),
]

# Simple file operation
stages = [
    Stage("scan"),
    Stage("execute"),
]
```

## Key Features

### Standard Stage Pattern
The recommended pattern for safety-critical operations:

```python
stages = [
    Stage("plan"),                                    # Analyze
    Stage("validate"),                                # Check preconditions
    Stage("stage", reversible=True),                  # Prepare/backup
    Stage("apply", needs_approval=True, reversible=True),  # Execute
    Stage("verify"),                                  # Confirm success
]
```

### Per-Stage Controls
Each stage can have its own requirements:

```python
Stage(
    name="apply",
    required=True,           # Operation fails if this fails
    needs_approval=True,     # Must be approved first
    needs_lock=True,         # Exclusive lock during execution
    reversible=True,         # Can be rolled back
    timeout_seconds=300,     # Max execution time
)
```

### Audit Trail
All operations automatically emit events:

```python
sl = Safeline(
    store=MemoryStore(),
    auditor=AuditStoreClient(url="http://audit-store:8080"),
)
```

Events: `operation_created`, `stage_started`, `stage_completed`, `approval_granted`, `lock_acquired`, etc.

### Environment-Aware Protection

```python
from sfln import get_protection_level

level = get_protection_level("production")
# level.require_approval = True
# level.require_backup = True
# level.allow_force = False
```

## Development

```bash
# Setup
make quickstart
source .venv/bin/activate

# Test
make test

# Code quality
make check
make format
```

## License

MIT
