403 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			403 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# 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:author`, `policy:review`, `policy:approve`, `policy:operate`, `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:author
 | 
						||
```
 | 
						||
 | 
						||
**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:author
 | 
						||
```
 | 
						||
 | 
						||
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:author
 | 
						||
```
 | 
						||
 | 
						||
**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:author
 | 
						||
```
 | 
						||
 | 
						||
**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:author
 | 
						||
```
 | 
						||
 | 
						||
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/Scheduler/__Libraries/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/Authority/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).*
 |