Files
Charon/docs/plans/current_spec.md

171 lines
7.1 KiB
Markdown

## Active Plan: PR-0 Spec Correction Pass (Security Notifications Provider Events)
Date: 2026-02-20
Status: Active and authoritative (supersedes all prior appended sections in this file)
### 1) Scope and Intent
- This is a spec-only correction pass for compatibility, migration determinism, and rollout safety.
- Security notifications are provider-event subscriptions, not a single global destination.
- Notify-only runtime remains fail-closed; legacy fallback dispatch remains blocked.
### 2) Compatibility GET Aggregation Rules (Exact)
Compatibility endpoint in scope:
- `GET /api/v1/notifications/settings/security`
Aggregation source of truth:
- Active provider rows in `notification_providers` after filtering `enabled=true` and supported notify-only types.
Derived booleans (OR semantics):
- `security_waf_enabled = OR(provider.notify_security_waf_blocks)`
- `security_acl_enabled = OR(provider.notify_security_acl_denies)`
- `security_rate_limit_enabled = OR(provider.notify_security_rate_limit_hits)`
Deterministic conflict behavior when providers disagree:
- If any active provider has `true` for a category, compatibility GET returns `true` for that category.
- Returns `false` only when all active providers are `false` (or no active providers exist).
- Provider order never affects result.
Legacy destination reporting:
- If compatibility payload still includes `destination`, it is read-only compatibility metadata.
- `destination` is emitted only when exactly one active managed-legacy provider is in scope.
- If zero or more than one candidate exists, `destination` is returned as empty string and `destination_ambiguous=true` is set in compatibility metadata.
### 3) Compatibility PUT Translation Semantics (Exact)
Compatibility endpoint in scope:
- `PUT /api/v1/notifications/settings/security`
Deterministic target set:
- If one or more managed-legacy providers exist, target set is exactly that managed set.
- If none exist and request is valid, create one managed-legacy provider and use it as the target set.
- Non-managed providers are never mutated by compatibility PUT.
Translation mode: **replace on managed set** (not global merge)
- For each target provider, set security event booleans exactly to request values:
- `notify_security_waf_blocks = request.security_waf_enabled`
- `notify_security_acl_denies = request.security_acl_enabled`
- `notify_security_rate_limit_hits = request.security_rate_limit_enabled`
- Existing non-security provider event booleans remain unchanged.
- Existing provider transport fields remain unchanged unless destination mapping applies (Section 5).
Idempotency:
- Repeating identical PUT payload produces no state drift and same compatibility GET output.
- Write timestamps may change only when effective values change.
Conflict handling:
- If target set cannot be resolved deterministically (for example data corruption with duplicate managed identity keys), return `409 Conflict` and do not partially write.
- If request includes unsupported destination mapping shape, return `422 Unprocessable Entity` and do not mutate providers.
- All compatibility PUT writes are transactional: all target providers updated or none.
### 4) Migration Marker Storage and Deterministic Re-Run
Marker storage:
- Table: `settings`
- Key: `notifications.security_provider_events.migration.v1`
- Value JSON schema:
- `version` (string, fixed `v1`)
- `checksum` (string, deterministic hash of legacy source fields used for migration)
- `last_completed_at` (RFC3339 timestamp)
- `result` (`completed` | `completed_with_warnings`)
Deterministic boot-time re-run behavior:
1. Read legacy source (`notification_configs`) and compute checksum.
2. Read migration marker.
3. If marker missing: run migration and write marker.
4. If marker exists with same checksum: skip mutation (no-op).
5. If marker exists but checksum differs: re-run migration in upsert mode, then replace marker.
Determinism constraints:
- Migration is pure over legacy source + managed provider key.
- Upsert key for managed provider is fixed identity `managed_legacy_security=true` plus name `Migrated Security Notifications (Legacy)`.
- Re-run does not create duplicate managed providers.
### 5) Legacy Destination-to-Provider Mapping Rules
Supported destination mappings for compatibility PUT:
- `webhook_url` present:
- map to provider type `webhook`, set endpoint URL from `webhook_url`.
- `discord_webhook_url` present:
- map to provider type `discord`, set endpoint URL from `discord_webhook_url`.
- `slack_webhook_url` present:
- map to provider type `slack`, set endpoint URL from `slack_webhook_url`.
- `gotify_url` + `gotify_token` present:
- map to provider type `gotify`, set URL/token fields.
Unsupported/ambiguous destination handling (fail-safe):
- If multiple destination types are simultaneously present in one request, return `422`.
- If destination type is unknown or incomplete for required fields, return `422`.
- On `422`, no provider rows are created/updated and compatibility state remains unchanged.
### 6) Feature Flag as Explicit Rollout Gate
Primary gate:
- `feature.notifications.security_provider_events.enabled`
Required defaults:
- Default in production: `false`
- Default in development/test: `true`
Behavior when flag is `false`:
- Provider-based security dispatch path is disabled.
- Compatibility GET/PUT remain available.
- Runtime dispatch uses compatibility translation path only.
- Managed migration may run in read-only dry-evaluate mode, but must not mutate providers.
Behavior when flag is `true`:
- Provider-based security dispatch is authoritative.
- Compatibility GET is derived projection from providers.
- Compatibility PUT writes managed set via translation semantics defined above.
Operational rule:
- This flag is mandatory for rollout and rollback; it is not optional/recommended.
### 7) Authoritative Plan Boundary and Cleanup
- This document is now the single authoritative plan for this scope.
- All previously appended certificate flaky-test and QA remediation sections are removed from active plan scope.
- Any future unrelated plan content must go to a separate plan file under `docs/plans/`.
### 8) PR Slicing Strategy
Decision: two PR slices.
- **PR-0 (this pass):** spec correction only in `docs/plans/current_spec.md`.
- **PR-1:** backend compatibility, migration marker, and feature-flag gate implementation.
- **PR-2:** frontend alignment and compatibility deprecation messaging.
### 9) Acceptance Criteria (Spec Pass)
1. Compatibility GET rules define exact OR aggregation and disagreement behavior.
2. Compatibility PUT defines deterministic target set, replace semantics, idempotency, and transaction/conflict behavior.
3. Migration marker key/storage and deterministic re-run logic are explicit.
4. Destination mapping rules cover supported non-webhook legacy forms and fail-safe unsupported behavior.
5. File contains one authoritative plan with stale duplicate trailing sections removed.
6. Feature flag is defined as explicit mandatory rollout gate with defaults and disable behavior.
### 10) Handoff
- Delegate PR-1 implementation to `Supervisor` using this plan as the sole baseline.