- 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.
9.9 KiB
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, Lifecycle, and Runs 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:runsfindings: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 obtaineffective:write. - Tenant: Supply tenant context via
X-Stella-Tenant. Tokens without multi-tenant claims default todefault. - 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-8unless otherwise noted.
2 · Error Model
All errors use HTTP semantics plus a structured payload:
{
"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
{
"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
{
"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
{
"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
{
"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:
{
"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
{
"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 undersamples/api/scheduler/policy-*.json.
6.1 Trigger Run
POST /api/policy/policies/{policyId}/runs
Scopes: policy:run
Request
{
"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
{
"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
{
"baseVersion": 3,
"candidateVersion": 4,
"sbomSet": ["sbom:S-42","sbom:S-318"],
"env": {"sealed": false},
"explain": true
}
Response 200
{
"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:
{
"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:
{
"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 withrunId,policyId,mode,stats,determinismHash.policy.run.failed– includes error code, retry count, guidance.policy.lifecycle.*– mirrored from lifecycle APIs (see Lifecycle guide).- 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-CountornextCursor. - Idempotency described: Mutating endpoints mandate
Idempotency-Key. - Offline parity noted: Simulate/run endpoints explain
--sealedbehaviour and bundle generation. - Cross-links added: References to lifecycle, runs, DSL, and observability docs verified.
Last updated: 2025-10-26 (Sprint 20).