# Story 6.4: Create AuditSink Plugin Wrapper

## Status: Complete

## Summary

Create an `AuditSink` plugin that wraps the existing `AuditTrail` infrastructure, making compliance logging discoverable and configurable through the standard sink mechanism.

## Motivation

The complexity audit identified that Fapilog has a full compliance audit framework (829 lines) that enterprise users cannot discover or use:

- `AuditTrail` class with GDPR/HIPAA/SOX/PCI-DSS support
- Hash-chain integrity verification
- Multiple compliance levels and event types
- **But:** Not exposed in `__init__.py`, not registered as a plugin, not documented

Enterprise buyers specifically need compliance audit trails. This is a key differentiator vs structlog (which has none). But the feature is currently hidden.

## Acceptance Criteria

- [ ] `AuditSink` class created implementing sink protocol
- [ ] Sink registered in plugin loader as `"audit"`
- [ ] Configuration via `sink_config.audit` in settings
- [ ] Users can enable via `core.sinks = ["stdout_json", "audit"]`
- [ ] Audit sink maps log events to appropriate `AuditEventType`
- [ ] Hash-chain integrity preserved across sink lifecycle
- [ ] Start/stop lifecycle properly managed
- [ ] Health check returns audit trail statistics
- [ ] Integration test demonstrating audit + compliance verification
- [ ] Documentation added to enterprise features section

## Technical Approach

### 1. Create AuditSink class

```python
# src/fapilog/plugins/sinks/audit.py

from dataclasses import dataclass
from typing import Any

from ...core.audit import AuditEventType, AuditLogLevel, AuditTrail, CompliancePolicy


@dataclass
class AuditSinkConfig:
    """Configuration for the audit compliance sink."""

    compliance_level: str = "basic"  # basic, sox, hipaa, gdpr, pci_dss, soc2, iso27001
    storage_path: str = "audit_logs"
    retention_days: int = 365
    encrypt_logs: bool = True
    require_integrity: bool = True
    real_time_alerts: bool = False


class AuditSink:
    """Sink that writes to compliance audit trail with integrity verification."""

    name = "audit"

    def __init__(self, config: AuditSinkConfig | None = None) -> None:
        self._config = config or AuditSinkConfig()
        self._trail: AuditTrail | None = None

    async def start(self) -> None:
        policy = CompliancePolicy(
            level=self._config.compliance_level,
            retention_days=self._config.retention_days,
            encrypt_audit_logs=self._config.encrypt_logs,
            require_integrity_check=self._config.require_integrity,
            real_time_alerts=self._config.real_time_alerts,
        )
        self._trail = AuditTrail(policy, Path(self._config.storage_path))
        await self._trail.start()

    async def write(self, entry: dict[str, Any]) -> None:
        if self._trail is None:
            return

        # Map log level to audit level
        level_map = {
            "DEBUG": AuditLogLevel.DEBUG,
            "INFO": AuditLogLevel.INFO,
            "WARNING": AuditLogLevel.WARNING,
            "ERROR": AuditLogLevel.ERROR,
            "CRITICAL": AuditLogLevel.CRITICAL,
        }
        audit_level = level_map.get(entry.get("level", "INFO"), AuditLogLevel.INFO)

        await self._trail.log_event(
            AuditEventType.DATA_ACCESS,  # Default; could be configurable
            entry.get("message", ""),
            log_level=audit_level,
            component=entry.get("logger"),
            request_id=entry.get("correlation_id"),
            user_id=entry.get("metadata", {}).get("user_id"),
            contains_pii=entry.get("metadata", {}).get("contains_pii", False),
        )

    async def stop(self) -> None:
        if self._trail:
            await self._trail.stop()

    async def check_health(self) -> dict[str, Any]:
        if self._trail is None:
            return {"healthy": False, "reason": "not_started"}
        stats = await self._trail.get_statistics()
        return {"healthy": True, **stats}
```

### 2. Register in plugin loader

Add to `plugins/sinks/__init__.py`:

```python
from ..loader import register_builtin
from .audit import AuditSink

register_builtin("fapilog.sinks", "audit", AuditSink)
```

### 3. Add settings

Add to `settings.py`:

```python
class AuditSinkSettings(BaseModel):
    compliance_level: str = Field(default="basic", description="Compliance level")
    storage_path: str = Field(default="audit_logs", description="Audit log directory")
    retention_days: int = Field(default=365, ge=1, description="Log retention period")
    encrypt_logs: bool = Field(default=True, description="Encrypt audit files")
    require_integrity: bool = Field(default=True, description="Verify hash chains")
    real_time_alerts: bool = Field(default=False, description="Enable real-time alerts")
```

### 4. Wire into `_sink_configs`

Add audit sink configuration mapping in `__init__.py`.

## Files Changed

- `src/fapilog/plugins/sinks/audit.py` — New file (+150 lines)
- `src/fapilog/plugins/sinks/__init__.py` — Register sink (+3 lines)
- `src/fapilog/core/settings.py` — Add `AuditSinkSettings` (+20 lines)
- `src/fapilog/__init__.py` — Wire config (+10 lines)
- `docs/plugins/sinks/audit.md` — Documentation (+100 lines)
- `tests/unit/test_audit_sink.py` — Tests (+100 lines)

## Estimated Effort

4-6 hours

## Risk Assessment

**Risk Level: Low**

- Wraps existing, tested infrastructure
- Additive change (no modification to existing sinks)
- Users must explicitly enable (`core.sinks = [..., "audit"]`)
- Existing audit module behavior unchanged

## Rollback Plan

Remove sink registration; `AuditTrail` remains available for direct use.

## Success Metrics

- Enterprise users can enable compliance logging with one config line
- Hash-chain verification works end-to-end
- Feature discoverable via `list_available_plugins("fapilog.sinks")`

## Future Enhancements

- Configurable event type mapping (log level → audit event type)
- Automatic PII detection integration with redactors
- Compliance report generation CLI command
