# Policy Gateway (Merged into Policy Engine) > **Status:** The `StellaOps.Policy.Gateway` service has been **merged into > `StellaOps.Policy.Engine`**. All gateway endpoints (exceptions, deltas, > gates, governance, tool-lattice, pack CRUD, activation) are now served > directly by the policy-engine process. The separate gateway container, > HTTP proxy layer, DPoP token flow, and `PolicyEngineClient` have been > removed. ## 1 - Responsibilities (now handled by Policy Engine) - Policy pack CRUD and activation endpoints enforcing scope policies (`policy:read`, `policy:author`, `policy:review`, `policy:operate`, `policy:activate`). - Normalised responses (DTO + `ProblemDetails`) so Console, CLI, and automation receive consistent payloads. - Structured logging and metrics for activation actions so approvals are auditable. - Exception management, delta computation, gate evaluation, governance, and tool-lattice endpoints. ## 2 - Endpoints All endpoints below are served by the **policy-engine** service. | Route | Method | Description | Required scope(s) | |-------|--------|-------------|-------------------| | `/api/policy/packs` | `GET` | List policy packs and revisions for the active tenant. | `policy:read` | | `/api/policy/packs` | `POST` | Create a policy pack shell or upsert display metadata. | `policy:author` | | `/api/policy/packs/{packId}/revisions` | `POST` | Create or update a policy revision (draft/approved). | `policy:author` | | `/api/policy/packs/{packId}/revisions/{version}:activate` | `POST` | Activate a revision, enforcing single/two-person approvals. | `policy:operate`, `policy:activate` | ### Response shapes - Successful responses return camel-case DTOs matching `PolicyPackDto`, `PolicyRevisionDto`, or `PolicyRevisionActivationDto` as described in the Policy Engine API doc (`/docs/api/policy.md`). - Errors always return RFC 7807 `ProblemDetails` with deterministic fields (`title`, `detail`, `status`). ### Dual-control activation - **Config-driven.** Set `PolicyEngine.activation.forceTwoPersonApproval=true` when every activation must collect two distinct `policy:activate` approvals. When false, operators can opt into dual-control per revision (`requiresTwoPersonApproval: true`). - **Defaults.** `PolicyEngine.activation.defaultRequiresTwoPersonApproval` feeds the default when callers omit the checkbox/flag. - **Statuses.** First approval on a dual-control revision returns `202 pending_second_approval`; duplicate actors get `400 duplicate_approval`; the second distinct approver receives the usual `200 activated`. - **Audit trail.** With `PolicyEngine.activation.emitAuditLogs` on, Policy Engine emits structured `policy.activation.*` scopes (pack id, revision, tenant, approver IDs, comments). #### Activation configuration wiring - **Helm ConfigMap.** `devops/helm/stellaops/values*.yaml` now include a `policy-engine-activation` ConfigMap. The chart automatically injects it via `envFrom` into the Policy Engine pod, so overriding the ConfigMap data updates the service with no manifest edits. - **Type safety.** Quote ConfigMap values (e.g., `"true"`, `"false"`) because Kubernetes ConfigMaps carry string data. - **File-based overrides (optional).** The Policy Engine host probes `/config/policy-engine/activation.yaml`, `../etc/policy-engine.activation.yaml`, and ambient `policy-engine.activation.yaml` files beside the binary. - **Offline/Compose.** Compose/offline bundles can continue exporting `STELLAOPS_POLICY_ENGINE__ACTIVATION__*` variables directly; the ConfigMap wiring simply mirrors those keys for Kubernetes clusters. ## 3 - Authentication & headers | Header | Source | Notes | |--------|--------|-------| | `Authorization` | Caller token. | Caller tokens must include tenant scope. | | `X-Stella-Tenant` | Caller | Tenant isolation header. | > **Note:** The previous DPoP proxy layer (gateway client credentials, `PolicyEngineClient`, > `PolicyGatewayDpopHandler`) has been removed. Callers authenticate directly with Policy Engine > using standard StellaOps resource server authentication. ## 4 - Metrics & logging All activation calls emit: - `policy_engine_activation_requests_total{outcome,source}` -- counter labelled with `outcome` (`activated`, `pending_second_approval`, `already_active`, `bad_request`, `not_found`, `unauthorized`, `forbidden`, `error`) and `source` (`caller`, `service`). Structured logs (category `StellaOps.Policy.Engine.Activation`) include `PackId`, `Version`, `Outcome`, `Source`, and status code for audit trails. ## 5 - Sample `curl` workflows Assuming you already obtained an access token (`$TOKEN`) for tenant `acme`: ```bash curl -sS https://gateway.example.com/api/policy/packs \ -H "Authorization: Bearer $TOKEN" \ -H "X-Stella-Tenant: acme" # Draft a new revision curl -sS https://gateway.example.com/api/policy/packs/policy.core/revisions \ -H "Authorization: Bearer $TOKEN" \ -H "X-Stella-Tenant: acme" \ -H "Content-Type: application/json" \ -d '{"version":5,"requiresTwoPersonApproval":true,"initialStatus":"Draft"}' # Activate revision 5 (returns 202 when awaiting the second approver) curl -sS https://gateway.example.com/api/policy/packs/policy.core/revisions/5:activate \ -H "Authorization: Bearer $TOKEN" \ -H "X-Stella-Tenant: acme" \ -H "Content-Type: application/json" \ -d '{"comment":"Rollout baseline"}' ``` ## 6 - Offline Kit guidance - Include `policy-engine.yaml.sample` and the resolved runtime config in the Offline Kit's `config/` tree. - When building verification scripts, use the policy-engine endpoints above. The Offline Kit validator expects `policy_engine_activation_requests_total` metrics in the Prometheus snapshot. ## 7 - Backwards compatibility - The `policy-gateway.stella-ops.local` hostname is preserved as a network alias on the policy-engine container in both docker-compose and hosts files. Existing configurations referencing `policy-gateway.stella-ops.local` will continue to work. - The `STELLAOPS_POLICY_GATEWAY_URL` environment variable has been removed from service defaults. Services that previously used it should use `STELLAOPS_POLICY_ENGINE_URL` instead. ## 8 - Change log - **2026-04-08 -- Gateway merge**: Gateway merged into Policy Engine. Separate container, HTTP proxy layer, DPoP flow, and `PolicyEngineClient` removed. All endpoints served directly by policy-engine. - **2025-10-27 -- Sprint 18.5**: Initial gateway bootstrap + activation metrics + DPoP client credentials.