Admin · Policy Engine

Phase 2a HTTP boundary · wraps 5 Phase 1 JSON models · decision service (no side effects) · 24/24 example vectors pass

Phase 2a
Live: HTTP contract · FastAPI scaffold · 7 endpoints · Python policy engine consuming role_registry · access_policy · assist_model · approval_queue_model · audit_event_model · 24 canonical decision examples. Not live: JWT · WORM audit sink · Redis cache · approval CRUD · admin flip UI.
Dev-mode only. Context via X-PTT-Actor-Role / X-PTT-Actor-User-Id / X-PTT-Actor-Tenant-Id / X-PTT-Target-Tenant-Id headers OR body/query. Bind 127.0.0.1 only.

Bring the service up

Requirement: Python ≥ 3.11 · port 8090 free (override POLICY_PORT).
Start: bash docs/runtime/admin-control-plane-service/run.sh
What it does: create .venv → install FastAPI+uvicorn → run verify_examples.py (must be 24/24 pass) → start uvicorn on 127.0.0.1:8090.

Live tester · Access check

Base URL

Live tester · Assist + View-as

Note: assist/view-as tests use fixed now_iso=2026-04-19T06:00:00Z and a sample context with active TTL. Change proposed_action in the JSON below to try different paths.

7 endpoints · all Phase 2a

Canonical decision vectors · 24 / 24 pass

Every example from policy_examples.json · click to POST against the running service. "Pass" means the returned decision shape matches the vector's expected.

Role × Category decision matrix

Default mask policy per role for each field category · generated from access_policy.masking_policy_rows · no approval held · no self-view.

Precedence rules (from Phase 1 spec)

idRuleRationale

Forbidden patterns enforced

Copy · paste · run

Assumes http://127.0.0.1:8090. Adjust host/port as needed.

Health

curl -s http://127.0.0.1:8090/api/policy/health | jq .

Access · tenant_admin own-tenant PII → allow/unmasked

curl -s 'http://127.0.0.1:8090/api/policy/access/check?actor_role=tenant_admin&actor_user_id=U-TA-1&actor_tenant_id=pty-zeroth&target_tenant_id=pty-zeroth&target_user_id=U-42&field_category=email' | jq .data

Access · sales cross-tenant no ctx → deny

curl -s 'http://127.0.0.1:8090/api/policy/access/check?actor_role=sales_ae&actor_user_id=U-SA&target_tenant_id=pty-zeroth&field_category=email' | jq .data

Access · via X-PTT-* headers

curl -s 'http://127.0.0.1:8090/api/policy/access/check?field_category=email' \
  -H 'X-PTT-Actor-Role: tenant_admin' \
  -H 'X-PTT-Actor-User-Id: U-TA-1' \
  -H 'X-PTT-Actor-Tenant-Id: pty-zeroth' \
  -H 'X-PTT-Target-Tenant-Id: pty-zeroth' \
  -H 'X-PTT-Target-User-Id: U-42' | jq .data

Mask resolve

curl -s -X POST 'http://127.0.0.1:8090/api/policy/mask/resolve' \
  -H 'Content-Type: application/json' \
  -d '{
    "context": {"actor_role":"sales_ae","actor_user_id":"U-SA","target_tenant_id":"pty-zeroth","target_user_id":"U-42"},
    "field_category": "email"
  }' | jq .data

Sensitive gate · health without approval → deny

curl -s -X POST 'http://127.0.0.1:8090/api/policy/sensitive/check' \
  -H 'Content-Type: application/json' \
  -d '{
    "context": {"actor_role":"tenant_admin","actor_user_id":"U-TA","actor_tenant_id":"pty-zeroth","target_tenant_id":"pty-zeroth"},
    "field_category": "health", "requested_action":"read"
  }' | jq .data

Assist validate · support success with consent

curl -s -X POST 'http://127.0.0.1:8090/api/policy/assist/validate' \
  -H 'Content-Type: application/json' \
  -d '{
    "context": {"actor_role":"support_success","actor_user_id":"U-SP","assist_ctx":{
      "target_tenant_id":"pty-zeroth","consent_record_id":"CR-1","case_ref":"CASE-2",
      "granted_at":"2026-04-19T05:30:00Z","expires_at":"2026-04-19T06:30:00Z",
      "scope":["edit_profile"]}, "now_iso":"2026-04-19T06:00:00Z"},
    "proposed_action": "edit_profile"
  }' | jq .data

View-as · write rejected

curl -s -X POST 'http://127.0.0.1:8090/api/policy/view-as/validate' \
  -H 'Content-Type: application/json' \
  -d '{
    "context": {"actor_role":"support_success","actor_user_id":"U-SP","view_as_ctx":{
      "target_tenant_id":"pty-zeroth","granted_at":"2026-04-19T05:45:00Z","expires_at":"2026-04-19T06:15:00Z"},
      "now_iso":"2026-04-19T06:00:00Z"},
    "proposed_action": "write"
  }' | jq .data

Batch access check

curl -s -X POST 'http://127.0.0.1:8090/api/policy/access/check/batch' \
  -H 'Content-Type: application/json' \
  -d '{
    "context":{"actor_role":"tenant_admin","actor_user_id":"U-TA","actor_tenant_id":"pty-zeroth","target_tenant_id":"pty-zeroth","target_user_id":"U-42"},
    "items":[{"field_category":"email"},{"field_category":"health","is_sensitive":true},{"field_category":"kpi"}]
  }' | jq .data

policy_contract.json

Source: docs/runtime/admin-control-plane-service/policy_contract.json · Phase 1 model refs: ../admin-control-plane/

loading…