feat: Implement Scheduler Worker Options and Planner Loop
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Docs CI / lint-and-preview (push) Has been cancelled
				
			- Added `SchedulerWorkerOptions` class to encapsulate configuration for the scheduler worker. - Introduced `PlannerBackgroundService` to manage the planner loop, fetching and processing planning runs. - Created `PlannerExecutionService` to handle the execution logic for planning runs, including impact targeting and run persistence. - Developed `PlannerExecutionResult` and `PlannerExecutionStatus` to standardize execution outcomes. - Implemented validation logic within `SchedulerWorkerOptions` to ensure proper configuration. - Added documentation for the planner loop and impact targeting features. - Established health check endpoints and authentication mechanisms for the Signals service. - Created unit tests for the Signals API to ensure proper functionality and response handling. - Configured options for authority integration and fallback authentication methods.
This commit is contained in:
		
							
								
								
									
										152
									
								
								docs/policy/exception-effects.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								docs/policy/exception-effects.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| # Policy Exception Effects | ||||
|  | ||||
| > **Audience:** Policy authors, reviewers, operators, and governance owners.   | ||||
| > **Scope:** How exception definitions are authored, resolved, and surfaced by the Policy Engine during evaluation, including precedence rules, metadata flow, and simulation/diff behaviour. | ||||
|  | ||||
| Exception effects let teams codify governed waivers without compromising determinism. This guide explains the artefacts involved, how the evaluator selects a single winning exception, and where downstream consumers observe the applied override. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 1 · Exception Building Blocks | ||||
|  | ||||
| | Artefact | Description | | ||||
| |----------|-------------| | ||||
| | **Exception Effect** | Declared inside a policy pack (`exceptions.effects`). Defines the override behaviour plus governance metadata. See effect fields in §2. | | ||||
| | **Routing Template** | Optional mapping (`exceptions.routingTemplates`) used by Authority to route approvals/MFA. Effects reference templates by id. | | ||||
| | **Exception Instance** | Stored outside the policy pack (Authority/API). Captures who requested the waiver, scope filters, metadata, and creation time. | | ||||
|  | ||||
| Effects are validated at bind time (`PolicyBinder`), while instances are ingested alongside policy evaluation inputs. Both are normalized to case-insensitive identifiers to avoid duplicate conflicts. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 2 · Effect Fields | ||||
|  | ||||
| | Field | Required | Purpose | Notes | | ||||
| |-------|----------|---------|-------| | ||||
| | `id` | ✅ | Stable identifier (`[A-Za-z0-9-_]+`). | Must be unique per policy pack. | | ||||
| | `name` | — | Friendly label for consoles/reports. | Forwarded to verdict metadata if present. | | ||||
| | `effect` | ✅ | Behaviour enum: `suppress`, `defer`, `downgrade`, `requireControl`. | Case-insensitive. | | ||||
| | `downgradeSeverity` | ⚠️ | Target severity for `downgrade`. | Must map to DSL severities (`high`, `medium`, etc.). Validation enforced in `PolicyBinder` (`policy.exceptions.effect.downgrade.missingSeverity`). | | ||||
| | `requiredControlId` | ⚠️ | Control catalogue key for `requireControl`. | Required when effect is `requireControl`. | | ||||
| | `routingTemplate` | — | Connects to an Authority approval flow. | CLI/Console resolve to `authorityRouteId`. | | ||||
| | `maxDurationDays` | — | Soft limit for temporary waivers. | Must be > 0 when provided. | | ||||
| | `description` | — | Rich-text rationale. | Displayed in approvals centre (optional). | | ||||
|  | ||||
| Authoring invalid combinations returns structured errors with JSON paths, preventing packs from compiling (see `src/StellaOps.Policy.Tests/PolicyBinderTests.cs:33`). Routing templates additionally declare `authorityRouteId` and `requireMfa` flags for governance routing. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 3 · Exception Instances & Scope | ||||
|  | ||||
| Instances are resolved from Authority or API collections and injected into the evaluation context (`PolicyEvaluationExceptions`). Each instance contains: | ||||
|  | ||||
| | Field | Source | Usage | | ||||
| |-------|--------|-------| | ||||
| | `id` | Authority storage | Propagated to annotations and `appliedException.exceptionId`. | | ||||
| | `effectId` | Links to pack-defined effect | Must resolve to a known effect; otherwise ignored. | | ||||
| | `scope.ruleNames` | Optional list | Limits to specific rule identifiers. | | ||||
| | `scope.severities` | Optional list (`severity.normalized`) | Normalized against the evaluator’s severity string. | | ||||
| | `scope.sources` | Optional advisory sources (`GHSA`, `NVD`, …) | Compared against the advisory context. | | ||||
| | `scope.tags` | Optional SBOM tags | Matched using `sbom.has_tag(...)`. | | ||||
| | `createdAt` | RFC3339 UTC timestamp | Used as tie-breaker when specificity scores match. | | ||||
| | `metadata` | Arbitrary key/value bag | Copied to verdict annotations (`exception.meta.*`). | | ||||
|  | ||||
| Scopes are case-insensitive and trimmed. Empty scopes behave as global waivers but still require routing and metadata supplied by Authority workflows. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 4 · Resolution & Specificity | ||||
|  | ||||
| Only one exception effect is applied per finding. Evaluation proceeds as follows: | ||||
|  | ||||
| 1. Filter instances whose `effectId` resolves to a known effect. | ||||
| 2. Discard instances whose scope does not match the candidate finding (rule name, severity, advisory source, SBOM tags). | ||||
| 3. Score remaining instances for **specificity**: | ||||
|    - `ruleNames` ⇒ `1000 + (count × 25)` | ||||
|    - `severities` ⇒ `500 + (count × 10)` | ||||
|    - `sources` ⇒ `250 + (count × 10)` | ||||
|    - `tags` ⇒ `100 + (count × 5)` | ||||
| 4. Highest score wins. Ties fall back to the newest `createdAt`, then lexical `id` (stable sorting). | ||||
|  | ||||
| These rules guarantee deterministic selection even when multiple waivers overlap. See `src/StellaOps.Policy.Engine.Tests/PolicyEvaluatorTests.cs:209` for tie-break coverage. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 5 · Effect Behaviours | ||||
|  | ||||
| | Effect | Status impact | Severity impact | Warnings / metadata | | ||||
| |--------|---------------|-----------------|---------------------| | ||||
| | `suppress` | Forces status `suppressed`. | No change. | `exception.status=suppressed`. | | ||||
| | `defer` | Forces status `deferred`. | No change. | `exception.status=deferred`. | | ||||
| | `downgrade` | No change. | Sets severity to configured `downgradeSeverity`. | `exception.severity` annotation. | | ||||
| | `requireControl` | No change. | No change. | Adds warning `Exception '<id>' requires control '<requiredControlId>'`. Annotation `exception.requiredControl`. | | ||||
|  | ||||
| All effects stamp shared annotations: `exception.id`, `exception.effectId`, `exception.effectType`, optional `exception.effectName`, optional `exception.routingTemplate`, plus `exception.maxDurationDays`. Instance metadata is surfaced both in annotations (`exception.meta.<key>`) and the structured `AppliedException.Metadata` payload for downstream APIs. Behaviour is validated by unit tests (`src/StellaOps.Policy.Engine.Tests/PolicyEvaluatorTests.cs:130` & `src/StellaOps.Policy.Engine.Tests/PolicyEvaluatorTests.cs:169`). | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 6 · Explain, Simulation & Outputs | ||||
|  | ||||
| - **Explain traces / CLI simulate** – Verdict payloads include `appliedException` capturing original vs applied status/severity, enabling diff visualisation in Console and CLI previews. | ||||
| - **Annotations** – Deterministic keys make it trivial for exports or alerting pipelines to flag waived findings. | ||||
| - **Warnings** – `requireControl` adds runtime warnings so operators can enforce completion of compensating controls. | ||||
| - **Routing** – When `routingTemplate` is populated, verdict metadata includes `routingTemplate`, allowing UI surfaces to deep-link into the approvals centre. | ||||
|  | ||||
| Example verdict excerpt (JSON): | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "status": "suppressed", | ||||
|   "severity": "Critical", | ||||
|   "annotations": { | ||||
|     "exception.id": "exc-001", | ||||
|     "exception.effectId": "suppress-critical", | ||||
|     "exception.effectType": "Suppress", | ||||
|     "exception.status": "suppressed", | ||||
|     "exception.meta.requestedBy": "alice" | ||||
|   }, | ||||
|   "appliedException": { | ||||
|     "exceptionId": "exc-001", | ||||
|     "effectId": "suppress-critical", | ||||
|     "effectType": "Suppress", | ||||
|     "originalStatus": "blocked", | ||||
|     "appliedStatus": "suppressed", | ||||
|     "metadata": { | ||||
|       "effectName": "Rule Critical Suppress", | ||||
|       "requestedBy": "alice" | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 7 · Operational Notes | ||||
|  | ||||
| - **Authoring** – Policy packs must ship effect definitions before Authority can issue instances. CLI validation (`stella policy lint`) fails if required fields are missing. | ||||
| - **Approvals & MFA** – Effects referencing routing templates inherit `requireMfa` rules from `exceptions.routingTemplates`. Governance guidance in `/docs/11_GOVERNANCE.md` captures Authority approval flows and audit expectations. | ||||
| - **Presence in exports** – Even when an exception suppresses a finding, explain traces and effective findings retain the applied exception metadata for audit parity. | ||||
| - **Determinism** – Specificity scoring plus tie-breakers ensure repeatable outcomes across runs, supporting sealed/offline replay. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 8 · Testing References | ||||
|  | ||||
| - `src/StellaOps.Policy.Tests/PolicyBinderTests.cs:33` – Validates schema rules for defining effects, routing templates, and downgrade guardrails. | ||||
| - `src/StellaOps.Policy.Engine.Tests/PolicyEvaluatorTests.cs:130` – Covers suppression, downgrade, and metadata propagation. | ||||
| - `src/StellaOps.Policy.Engine.Tests/PolicyEvaluatorTests.cs:209` – Confirms specificity ordering and metadata forwarding for competing exceptions. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 9 · Compliance Checklist | ||||
|  | ||||
| - [ ] **Effect catalogue maintained:** Each policy pack documents available effects and routing templates for auditors. | ||||
| - [ ] **Authority alignment:** Approval routes in Authority mirror `routingTemplate` definitions and enforce MFA where required. | ||||
| - [ ] **Explain coverage:** Console/CLI surfaces display `appliedException` details and `exception.*` annotations for every waived verdict. | ||||
| - [ ] **Simulation parity:** `stella policy simulate` outputs include exception metadata, ensuring PR/CI reviews catch unintended waivers. | ||||
| - [ ] **Audit retention:** Effective findings history retains `appliedException` payloads so exception lifecycle reviews remain replayable. | ||||
| - [ ] **Tests locked:** Binder and evaluator tests covering exception paths remain green before publishing documentation updates. | ||||
|  | ||||
| --- | ||||
|  | ||||
| *Last updated: 2025-10-27 (Sprint 25).* | ||||
		Reference in New Issue
	
	Block a user