Add Policy DSL Validator, Schema Exporter, and Simulation Smoke tools
- Implemented PolicyDslValidator with command-line options for strict mode and JSON output. - Created PolicySchemaExporter to generate JSON schemas for policy-related models. - Developed PolicySimulationSmoke tool to validate policy simulations against expected outcomes. - Added project files and necessary dependencies for each tool. - Ensured proper error handling and usage instructions across tools.
This commit is contained in:
		
							
								
								
									
										402
									
								
								docs/api/policy.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										402
									
								
								docs/api/policy.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,402 @@
 | 
			
		||||
# Policy Engine REST API
 | 
			
		||||
 | 
			
		||||
> **Audience:** Backend integrators, platform operators, and CI engineers invoking Policy Engine services programmatically.  
 | 
			
		||||
> **Base URL:** `/api/policy/*` (internal gateway route) – requires OAuth 2.0 bearer token issued by Authority with scopes listed below.
 | 
			
		||||
 | 
			
		||||
This document is the canonical reference for the Policy Engine REST surface described in Epic 2 (Policy Engine v2). Use it alongside the [DSL](../policy/dsl.md), [Lifecycle](../policy/lifecycle.md), and [Runs](../policy/runs.md) guides for end-to-end implementations.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 1 · Authentication & Headers
 | 
			
		||||
 | 
			
		||||
- **Auth:** Bearer tokens (`Authorization: Bearer <token>`) with the following scopes as applicable:
 | 
			
		||||
  - `policy:read`, `policy:write`, `policy:submit`, `policy:approve`, `policy:run`, `policy:activate`, `policy:archive`, `policy:simulate`, `policy:runs`
 | 
			
		||||
  - `findings:read` (for effective findings APIs)
 | 
			
		||||
  - `effective:write` (service identity only; not exposed to clients)
 | 
			
		||||
- **Service identity:** Authority marks the Policy Engine client with `properties.serviceIdentity: policy-engine`. Tokens missing this marker cannot obtain `effective:write`.
 | 
			
		||||
- **Tenant:** Supply tenant context via `X-Stella-Tenant`. Tokens without multi-tenant claims default to `default`.
 | 
			
		||||
- **Idempotency:** For mutating endpoints, include `Idempotency-Key` (UUID). Retries with same key return original result.
 | 
			
		||||
- **Content type:** All request/response bodies are `application/json; charset=utf-8` unless otherwise noted.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 2 · Error Model
 | 
			
		||||
 | 
			
		||||
All errors use HTTP semantics plus a structured payload:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "code": "ERR_POL_001",
 | 
			
		||||
  "message": "Policy syntax error",
 | 
			
		||||
  "details": [
 | 
			
		||||
    {"path": "rules[0].when", "error": "Unknown function foo()"}
 | 
			
		||||
  ],
 | 
			
		||||
  "traceId": "01HDV1C4E9Z4T5G6H7J8",
 | 
			
		||||
  "timestamp": "2025-10-26T14:07:03Z"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
| Code | Meaning | Notes |
 | 
			
		||||
|------|---------|-------|
 | 
			
		||||
| `ERR_POL_001` | Policy syntax/compile error | Returned by `compile`, `submit`, `simulate`, `run` when DSL invalid. |
 | 
			
		||||
| `ERR_POL_002` | Policy not approved | Attempted to run or activate unapproved version. |
 | 
			
		||||
| `ERR_POL_003` | Missing inputs | Downstream service unavailable (Concelier/Excititor/SBOM). |
 | 
			
		||||
| `ERR_POL_004` | Determinism violation | Illegal API usage (wall-clock, RNG). Triggers incident mode. |
 | 
			
		||||
| `ERR_POL_005` | Unauthorized materialisation | Identity lacks `effective:write`. |
 | 
			
		||||
| `ERR_POL_006` | Run canceled or timed out | Includes cancellation metadata. |
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 3 · Policy Management
 | 
			
		||||
 | 
			
		||||
### 3.1 Create Draft
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies
 | 
			
		||||
Scopes: policy:write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Request**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "policyId": "P-7",
 | 
			
		||||
  "name": "Default Org Policy",
 | 
			
		||||
  "description": "Baseline severity + VEX precedence",
 | 
			
		||||
  "dsl": {
 | 
			
		||||
    "syntax": "stella-dsl@1",
 | 
			
		||||
    "source": "policy \"Default Org Policy\" syntax \"stella-dsl@1\" { ... }"
 | 
			
		||||
  },
 | 
			
		||||
  "tags": ["baseline","vex"]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Response 201**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "policyId": "P-7",
 | 
			
		||||
  "version": 1,
 | 
			
		||||
  "status": "draft",
 | 
			
		||||
  "digest": "sha256:7e1d…",
 | 
			
		||||
  "createdBy": "user:ali",
 | 
			
		||||
  "createdAt": "2025-10-26T13:40:00Z"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 3.2 List Policies
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/policies?status=approved&tenant=default&page=1&pageSize=25
 | 
			
		||||
Scopes: policy:read
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Returns paginated list with `X-Total-Count` header.
 | 
			
		||||
 | 
			
		||||
### 3.3 Fetch Version
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/policies/{policyId}/versions/{version}
 | 
			
		||||
Scopes: policy:read
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Returns full DSL, metadata, provenance, simulation artefact references.
 | 
			
		||||
 | 
			
		||||
### 3.4 Update Draft Version
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
PUT /api/policy/policies/{policyId}/versions/{version}
 | 
			
		||||
Scopes: policy:write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Body identical to create. Only permitted while `status=draft`.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 4 · Lifecycle Transitions
 | 
			
		||||
 | 
			
		||||
### 4.1 Submit for Review
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}:submit
 | 
			
		||||
Scopes: policy:submit
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Request**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "reviewers": ["user:kay","group:sec-reviewers"],
 | 
			
		||||
  "notes": "Simulated on golden SBOM set (diff attached)",
 | 
			
		||||
  "simulationArtifacts": [
 | 
			
		||||
    "blob://policy/P-7/v3/simulations/2025-10-26.json"
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Response 202** – submission recorded. `Location` header points to review resource.
 | 
			
		||||
 | 
			
		||||
### 4.2 Review Feedback
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}/reviews
 | 
			
		||||
Scopes: policy:review
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Request**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "decision": "approve",     // approve | request_changes | comment
 | 
			
		||||
  "note": "Looks good, ensure incident playbook covers reachability data.",
 | 
			
		||||
  "blocking": false
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 4.3 Approve
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}:approve
 | 
			
		||||
Scopes: policy:approve
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Body requires approval note and confirmation of compliance gates:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "note": "All simulations and determinism checks passed.",
 | 
			
		||||
  "acknowledgeDeterminism": true,
 | 
			
		||||
  "acknowledgeSimulation": true
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 4.4 Activate
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}:activate
 | 
			
		||||
Scopes: policy:activate, policy:run
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Marks version as active for tenant; triggers optional immediate full run (`"runNow": true`).
 | 
			
		||||
 | 
			
		||||
### 4.5 Archive
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}:archive
 | 
			
		||||
Scopes: policy:archive
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Request includes `reason` and optional `incidentId`.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 5 · Compilation & Validation
 | 
			
		||||
 | 
			
		||||
### 5.1 Compile
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/versions/{version}:compile
 | 
			
		||||
Scopes: policy:write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Response 200**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "digest": "sha256:7e1d…",
 | 
			
		||||
  "warnings": [],
 | 
			
		||||
  "rules": {
 | 
			
		||||
    "count": 24,
 | 
			
		||||
    "actions": {
 | 
			
		||||
      "block": 5,
 | 
			
		||||
      "warn": 4,
 | 
			
		||||
      "ignore": 3,
 | 
			
		||||
      "requireVex": 2
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 5.2 Lint / Simulate Quick Check
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/lint
 | 
			
		||||
Scopes: policy:write
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Slim wrapper used by CLI; returns 204 on success or `ERR_POL_001` payload.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 6 · Run & Simulation APIs
 | 
			
		||||
 | 
			
		||||
> Schema reference: canonical policy run request/status/diff payloads ship with the Scheduler Models guide (`src/StellaOps.Scheduler.Models/docs/SCHED-MODELS-20-001-POLICY-RUNS.md`) and JSON fixtures under `samples/api/scheduler/policy-*.json`.
 | 
			
		||||
 | 
			
		||||
### 6.1 Trigger Run
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/runs
 | 
			
		||||
Scopes: policy:run
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Request**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "mode": "incremental",           // full | incremental
 | 
			
		||||
  "runId": "run:P-7:2025-10-26:auto",   // optional idempotency key
 | 
			
		||||
  "sbomSet": ["sbom:S-42","sbom:S-318"],
 | 
			
		||||
  "env": {"exposure": "internet"},
 | 
			
		||||
  "priority": "normal"             // normal | high | emergency
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Response 202**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "runId": "run:P-7:2025-10-26:auto",
 | 
			
		||||
  "status": "queued",
 | 
			
		||||
  "queuedAt": "2025-10-26T14:05:00Z"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 6.2 Get Run Status
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/policies/{policyId}/runs/{runId}
 | 
			
		||||
Scopes: policy:runs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Includes status, stats, determinism hash, failure diagnostics.
 | 
			
		||||
 | 
			
		||||
### 6.3 List Runs
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/policies/{policyId}/runs?mode=incremental&status=failed&page=1&pageSize=20
 | 
			
		||||
Scopes: policy:runs
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Supports filtering by `mode`, `status`, `from`/`to` timestamps, `tenant`.
 | 
			
		||||
 | 
			
		||||
### 6.4 Simulate
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/simulate
 | 
			
		||||
Scopes: policy:simulate
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Request**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "baseVersion": 3,
 | 
			
		||||
  "candidateVersion": 4,
 | 
			
		||||
  "sbomSet": ["sbom:S-42","sbom:S-318"],
 | 
			
		||||
  "env": {"sealed": false},
 | 
			
		||||
  "explain": true
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Response 200**
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "diff": {
 | 
			
		||||
    "added": 12,
 | 
			
		||||
    "removed": 8,
 | 
			
		||||
    "unchanged": 657,
 | 
			
		||||
    "bySeverity": {
 | 
			
		||||
      "Critical": {"up": 1, "down": 0},
 | 
			
		||||
      "High": {"up": 3, "down": 4}
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "explainUri": "blob://policy/P-7/simulations/2025-10-26-4-vs-3.json"
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 6.5 Replay Run
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
POST /api/policy/policies/{policyId}/runs/{runId}:replay
 | 
			
		||||
Scopes: policy:runs, policy:simulate
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Produces sealed bundle for determinism verification; returns location of bundle.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 7 · Effective Findings APIs
 | 
			
		||||
 | 
			
		||||
### 7.1 List Findings
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/findings/{policyId}?sbomId=S-42&status=affected&severity=High,Critical&page=1&pageSize=100
 | 
			
		||||
Scopes: findings:read
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Response includes cursor-based pagination:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "items": [
 | 
			
		||||
    {
 | 
			
		||||
      "findingId": "P-7:S-42:pkg:npm/lodash@4.17.21:CVE-2021-23337",
 | 
			
		||||
      "status": "affected",
 | 
			
		||||
      "severity": {"normalized": "High", "score": 7.5},
 | 
			
		||||
      "sbomId": "sbom:S-42",
 | 
			
		||||
      "advisoryIds": ["CVE-2021-23337"],
 | 
			
		||||
      "vex": {"winningStatementId": "VendorX-123"},
 | 
			
		||||
      "policyVersion": 4,
 | 
			
		||||
      "updatedAt": "2025-10-26T14:06:01Z"
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "nextCursor": "eyJwYWdlIjoxfQ=="
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### 7.2 Fetch Explain Trace
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
GET /api/policy/findings/{policyId}/{findingId}/explain?mode=verbose
 | 
			
		||||
Scopes: findings:read
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Returns rule hit sequence:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{
 | 
			
		||||
  "findingId": "P-7:S-42:pkg:npm/lodash@4.17.21:CVE-2021-23337",
 | 
			
		||||
  "policyVersion": 4,
 | 
			
		||||
  "steps": [
 | 
			
		||||
    {"rule": "vex_precedence", "status": "not_affected", "inputs": {"statementId": "VendorX-123"}},
 | 
			
		||||
    {"rule": "severity_baseline", "severity": {"normalized": "Low", "score": 3.4}}
 | 
			
		||||
  ],
 | 
			
		||||
  "sealedHints": [{"message": "Using cached EPSS percentile from bundle 2025-10-20"}]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 8 · Events & Webhooks
 | 
			
		||||
 | 
			
		||||
- `policy.run.completed` – emitted with `runId`, `policyId`, `mode`, `stats`, `determinismHash`.
 | 
			
		||||
- `policy.run.failed` – includes error code, retry count, guidance.
 | 
			
		||||
- `policy.lifecycle.*` – mirrored from lifecycle APIs (see [Lifecycle guide](../policy/lifecycle.md)).
 | 
			
		||||
- Webhook registration occurs via `/api/policy/webhooks` (future work, reserved). For now, integrate with Notifier streams documented in `/docs/notifications/*`.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
## 9 · Compliance Checklist
 | 
			
		||||
 | 
			
		||||
- [ ] **Scopes enforced:** Endpoint access requires correct Authority scope mapping (see `/src/StellaOps.Authority/TASKS.md`).
 | 
			
		||||
- [ ] **Schemas current:** JSON examples align with Scheduler Models (`SCHED-MODELS-20-001`) and Policy Engine DTOs; update when contracts change.
 | 
			
		||||
- [ ] **Error codes mapped:** `ERR_POL_*` table reflects implementation and CI tests cover edge cases.
 | 
			
		||||
- [ ] **Pagination documented:** List endpoints specify page/size and cursor semantics; responses include `X-Total-Count` or `nextCursor`.
 | 
			
		||||
- [ ] **Idempotency described:** Mutating endpoints mandate `Idempotency-Key`.
 | 
			
		||||
- [ ] **Offline parity noted:** Simulate/run endpoints explain `--sealed` behaviour and bundle generation.
 | 
			
		||||
- [ ] **Cross-links added:** References to lifecycle, runs, DSL, and observability docs verified.
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
*Last updated: 2025-10-26 (Sprint 20).*
 | 
			
		||||
		Reference in New Issue
	
	Block a user