🔧 Control Simulator API Reference

📌 Overview

The Control Simulator API provides programmatic access to control testing, trace generation, and test history management.

Base URL: /api/v1/pis

Authentication: All endpoints require Bearer token authentication.


🔧 Endpoints

GET /policies/loadable

Get controls available for testing filtered by environment.

Query Parameters:

  • environment (required): sandbox or production

Response:

[
  {
    "id": 1,
    "name": "Admin Access Control",
    "description": "Controls admin access to sensitive resources",
    "status": "enabled",
    "environment": "sandbox",
    "resource_name": "API Gateway",
    "bouncer_name": "Bouncer-US-East-01",
    "target_action": ["GET", "POST", "DELETE"]
  }
]

Example:

GET /api/v1/pis/policies/loadable?environment=sandbox
Authorization: Bearer {token}

GET /policies/{policy_id}/attributes

Extract input attributes from a control's Rego code using OPA AST parsing.

Path Parameters:

  • policy_id (required): Control ID

Response:

[
  {
    "key": "user.role",
    "label": "User Role",
    "type": "string",
    "default_value": "",
    "description": "Extracted from input.user.role"
  },
  {
    "key": "resource.sensitivity",
    "label": "Resource Sensitivity",
    "type": "string",
    "default_value": "",
    "description": "Extracted from input.resource.sensitivity"
  }
]

Attribute Types:

  • string: Text values
  • number: Numeric values
  • boolean: true/false
  • array: List of values
  • object: Nested structure

POST /policies/{policy_id}/simulate

Run a control simulation with provided input data.

Path Parameters:

  • policy_id (required): Control ID

Query Parameters:

  • environment (required): sandbox or production

Request Body:

{
  "input_json": {
    "user": {
      "role": "admin",
      "id": "user-123"
    },
    "resource": {
      "type": "api",
      "sensitivity": "high"
    },
    "action": "read"
  },
  "test_type": "decision"
}

Response:

{
  "simulation_id": 42,
  "decision": "ALLOW",
  "reason": "Access ALLOWED by control 'Admin Access Control'. All control conditions were satisfied.",
  "trace": [
    {
      "step_number": 1,
      "step_type": "policy_matched",
      "description": "Control 'Admin Access Control' selected for evaluation",
      "result": true,
      "details": {
        "policy_id": 1,
        "policy_name": "Admin Access Control"
      }
    }
  ],
  "input_json": { /* ... */ },
  "output_json": { /* ... */ },
  "execution_time_ms": 45.3,
  "timestamp": "2025-01-05T10:30:00Z"
}

Decision Values:

  • ALLOW: Access granted
  • DENY: Access denied
  • MASK: Access granted with data masking
  • NO_MATCH: No control matched, default action applied

Trace Step Types:

  • policy_matched: Control was selected
  • condition_eval: Condition evaluation
  • final_decision: Final decision computed

GET /policies/{policy_id}/test-history

Get test history for a specific control.

Path Parameters:

  • policy_id (required): Control ID

Query Parameters:

  • limit (optional, default: 50, max: 200): Results per page
  • offset (optional, default: 0): Pagination offset
  • start_date (optional): ISO 8601 datetime
  • end_date (optional): ISO 8601 datetime

Response:

{
  "entries": [
    {
      "id": 42,
      "policy_id": 1,
      "policy_name": "Admin Access Control",
      "user": "john.doe",
      "decision": "ALLOW",
      "execution_time_ms": 45.3,
      "timestamp": "2025-01-05T10:30:00Z",
      "input_summary": "role=admin, action=read",
      "can_export": true,
      "environment": "sandbox"
    }
  ],
  "total": 150,
  "limit": 50,
  "offset": 0,
  "has_more": true
}

GET /test-history

Get test history for the current user across all controls.

Query Parameters:

  • limit (optional, default: 50, max: 200): Results per page
  • offset (optional, default: 0): Pagination offset
  • start_date (optional): ISO 8601 datetime
  • end_date (optional): ISO 8601 datetime

Response: Same format as per-control history


POST /export/{simulation_id}

Export a simulation result in various formats.

Path Parameters:

  • simulation_id (required): Simulation log ID

Query Parameters:

  • format (required): json, csv, or pdf

Response: File download with appropriate Content-Type

Content-Types:

  • application/json for JSON
  • text/csv for CSV
  • application/pdf for PDF

Example:

POST /api/v1/pis/export/42?format=json
Authorization: Bearer {token}

GET /scenarios

List saved test scenarios for the current user.

Query Parameters:

  • policy_id (optional): Filter by control ID

Response:

[
  {
    "id": 10,
    "name": "Admin Happy Path",
    "description": "Test admin access during business hours",
    "policy_id": 1,
    "policy_name": "Admin Access Control",
    "attributes": {
      "user.role": "admin",
      "context.time": "14:00:00"
    },
    "created_at": "2025-01-05T09:00:00Z",
    "last_used": "2025-01-05T10:30:00Z"
  }
]

POST /scenarios

Save a new test scenario.

Request Body:

{
  "policy_id": 1,
  "name": "Admin Happy Path",
  "description": "Test admin access during business hours",
  "attributes": {
    "user.role": "admin",
    "context.time": "14:00:00"
  }
}

Response: Same as GET /scenarios (single scenario)


PUT /scenarios/{scenario_id}

Update an existing test scenario.

Path Parameters:

  • scenario_id (required): Scenario ID

Request Body: Same as POST /scenarios

Response: Updated scenario


DELETE /scenarios/{scenario_id}

Delete a test scenario.

Path Parameters:

  • scenario_id (required): Scenario ID

Response:

{
  "message": "Test scenario deleted successfully"
}

📌 Data Models

PolicyAttribute

interface PolicyAttribute {
  key: string;                 // Attribute path without "input." prefix
  label: string;               // Human-readable label
  type: string;                // "string" | "number" | "boolean" | "array"
  default_value: any;          // Type-appropriate default
  description?: string;        // Description
}

TraceStep

interface TraceStep {
  step_number: number;         // Sequential step number
  step_type: string;           // "policy_matched" | "condition_eval" | "final_decision"
  description: string;         // Human-readable description
  result: boolean;             // Pass/fail
  details?: Record<string, any>; // Additional details
}

SimulationResult

interface SimulationResult {
  simulation_id: number | null;
  decision: string;            // "ALLOW" | "DENY" | "MASK" | "NO_MATCH"
  reason: string;              // Human-readable explanation
  trace: TraceStep[];          // Execution trace
  input_json: Record<string, any>;
  output_json: Record<string, any>;
  execution_time_ms: number;
  timestamp: string;           // ISO 8601
}

📌 Error Responses

All endpoints use standard HTTP status codes:

  • 200: Success
  • 400: Bad request (invalid parameters)
  • 401: Unauthorized (missing/invalid token)
  • 404: Not found (control/scenario doesn't exist)
  • 500: Server error

Error Format:

{
  "detail": "Error message describing what went wrong"
}

📌 Rate Limits

No explicit rate limits for authenticated users. Simulation execution is limited to 30 seconds per request.


📌 Examples

Complete Test Flow

// 1. Get loadable controls
const policies = await fetch('/api/v1/pis/policies/loadable?environment=sandbox', {
  headers: { 'Authorization': `Bearer ${token}` }
});

// 2. Get attributes for selected control
const attributes = await fetch('/api/v1/pis/policies/1/attributes', {
  headers: { 'Authorization': `Bearer ${token}` }
});

// 3. Run simulation
const result = await fetch('/api/v1/pis/policies/1/simulate?environment=sandbox', {
  method: 'POST',
  headers: { 
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    input_json: {
      user: { role: 'admin' },
      resource: { type: 'api' },
      action: 'read'
    },
    test_type: 'decision'
  })
});

// 4. Save as scenario
await fetch('/api/v1/pis/scenarios', {
  method: 'POST',
  headers: { 
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    policy_id: 1,
    name: 'Admin Access Test',
    description: 'Test admin access to API',
    attributes: {
      'user.role': 'admin',
      'resource.type': 'api',
      'action': 'read'
    }
  })
});

📌 Implementation Notes

Attribute Extraction

The attribute extraction uses:

  1. opa parse --format json to get AST
  2. Recursive traversal to find input.* references
  3. Type inference from usage patterns in code
  4. Label generation from attribute paths

OPA Simulation

Simulations execute:

  1. Create isolated OPA bundle with control code
  2. Run opa eval --explain=full for tracing
  3. Parse trace output into structured steps
  4. Log to audit trail and simulation logs table

Audit Logging

Every simulation creates:

  • Audit log entry with event type POLICY_SIMULATION_RUN
  • Detailed simulation log in policy_simulation_logs table
  • Linked via simulation_id for compliance tracking