# Policy Studio API Contract **Contract ID:** `CONTRACT-POLICY-STUDIO-007` **Version:** 1.0 **Status:** Published **Last Updated:** 2025-12-05 ## Overview This contract defines the Policy Studio API used for creating, editing, and managing security policies. Policy Studio extends the Policy Engine REST API with DSL compilation and draft management capabilities. ## Implementation References - **Policy Engine:** `src/Policy/StellaOps.Policy.Engine/` - **Policy API:** `src/Api/StellaOps.Api.OpenApi/policy/openapi.yaml` - **Documentation:** `docs/api/policy.md` ## Policy Lifecycle ``` Draft → Submitted → Approved → Active → Archived ``` | State | Description | |-------|-------------| | `draft` | Policy is being edited, not enforced | | `submitted` | Policy submitted for review | | `approved` | Policy approved, ready to activate | | `active` | Policy is currently enforced | | `archived` | Policy is no longer active | ## API Endpoints ### Draft Management #### Create Draft ``` POST /api/v1/policy/drafts Content-Type: application/json Authorization: Bearer { "tenant_id": "default", "name": "security-policy-v2", "description": "Enhanced security policy with KEV checks", "source_format": "stelladsl", "source": "package policy\n\ndefault allow := false\n\nallow if {\n input.severity != \"critical\"\n}" } Response: 201 Created { "draft_id": "draft-001", "name": "security-policy-v2", "state": "draft", "created_at": "2025-12-05T10:00:00Z", "created_by": "user@example.com" } ``` #### Get Draft ``` GET /api/v1/policy/drafts/{draft_id} Response: 200 OK { "draft_id": "draft-001", "name": "security-policy-v2", "description": "Enhanced security policy with KEV checks", "state": "draft", "source_format": "stelladsl", "source": "...", "compiled_rego": "...", "validation_errors": [], "created_at": "2025-12-05T10:00:00Z", "updated_at": "2025-12-05T10:00:00Z" } ``` #### Update Draft ``` PUT /api/v1/policy/drafts/{draft_id} Content-Type: application/json { "source": "updated policy source..." } Response: 200 OK ``` #### Delete Draft ``` DELETE /api/v1/policy/drafts/{draft_id} Response: 204 No Content ``` ### DSL Compilation #### Compile DSL to Rego ``` POST /api/v1/policy/dsl/compile Content-Type: application/json { "source": "package policy\n\ndefault allow := false\n\nallow if { input.severity != \"critical\" }", "format": "stelladsl" } Response: 200 OK { "rego": "package policy\n\ndefault allow := false\n\nallow = true {\n input.severity != \"critical\"\n}", "errors": [], "warnings": [ { "line": 5, "column": 1, "message": "Consider adding documentation comment" } ] } ``` #### Validate Policy ``` POST /api/v1/policy/dsl/validate Content-Type: application/json { "source": "...", "format": "stelladsl" } Response: 200 OK { "valid": true, "errors": [], "warnings": [] } ``` ### Submission & Approval #### Submit Draft for Review ``` POST /api/v1/policy/drafts/{draft_id}/submit Content-Type: application/json { "comment": "Ready for review" } Response: 200 OK { "draft_id": "draft-001", "state": "submitted", "submitted_at": "2025-12-05T10:00:00Z", "submitted_by": "user@example.com" } ``` #### Approve Policy ``` POST /api/v1/policy/drafts/{draft_id}/approve Authorization: Bearer { "comment": "Approved after review" } Response: 200 OK { "draft_id": "draft-001", "state": "approved", "approved_at": "2025-12-05T10:00:00Z", "approved_by": "admin@example.com" } ``` #### Activate Policy ``` POST /api/v1/policy/drafts/{draft_id}/activate Authorization: Bearer Response: 200 OK { "policy_id": "policy-001", "version": "1.0.0", "state": "active", "activated_at": "2025-12-05T10:00:00Z" } ``` ### Policy Versions #### List Policy Versions ``` GET /api/v1/policy/{policy_id}/versions Response: 200 OK { "versions": [ { "version": "1.0.0", "state": "active", "activated_at": "2025-12-05T10:00:00Z" }, { "version": "0.9.0", "state": "archived", "archived_at": "2025-12-05T09:00:00Z" } ] } ``` #### Get Specific Version ``` GET /api/v1/policy/{policy_id}/versions/{version} Response: 200 OK { "policy_id": "policy-001", "version": "1.0.0", "rego": "...", "hash": "sha256:...", "state": "active" } ``` ## Policy Evaluation #### Evaluate Policy ``` POST /api/v1/policy/{policy_id}/evaluate Content-Type: application/json { "input": { "finding_id": "finding-001", "severity": "high", "cvss": 7.5, "kev": true } } Response: 200 OK { "result": { "allow": false, "deny": true, "reasons": ["KEV vulnerability detected"] }, "policy_version": "1.0.0", "policy_hash": "sha256:...", "evaluated_at": "2025-12-05T10:00:00Z" } ``` ## DSL Format ### StellaOps DSL (stelladsl) ```rego package policy import future.keywords.if import future.keywords.in # Default deny default allow := false default deny := false # Allow low severity findings allow if { input.severity in ["low", "informational"] } # Deny KEV vulnerabilities deny if { input.kev == true } # Deny critical CVSS deny if { input.cvss >= 9.0 } ``` ## Error Codes | Code | Message | |------|---------| | `ERR_POL_001` | Invalid policy syntax | | `ERR_POL_002` | Compilation failed | | `ERR_POL_003` | Validation failed | | `ERR_POL_004` | Policy not found | | `ERR_POL_005` | Invalid state transition | | `ERR_POL_006` | Insufficient permissions | ## Authority Scopes | Scope | Description | |-------|-------------| | `policy:read` | Read policies and drafts | | `policy:write` | Create and edit drafts | | `policy:submit` | Submit drafts for review | | `policy:approve` | Approve submitted policies | | `policy:activate` | Activate approved policies | | `policy:archive` | Archive active policies | ## Unblocks This contract unblocks the following tasks: - CONCELIER-RISK-68-001 - POLICY-RISK-68-001 - POLICY-RISK-68-002 ## Related Contracts - [Risk Scoring Contract](./risk-scoring.md) - Policy affects scoring - [Authority Effective Write Contract](./authority-effective-write.md) - Policy attachment