Files
git.stella-ops.org/docs/modules/policy/guides/gateway.md
master c1ecc75ace refactor(policy): merge policy gateway into policy-engine
- Move 24 gateway source files (endpoints, services, contracts) into engine
  under Endpoints/Gateway/, Services/Gateway/, Contracts/Gateway/ namespaces
- Add gateway DI registrations and endpoint mappings to engine Program.cs
- Add missing project references (StellaOps.Policy.Scoring, DeltaVerdict, Localization)
- Remove HTTP proxy layer (PolicyEngineClient, DPoP, forwarding context not copied)
- Update gateway routes in router appsettings to point to policy-engine
- Comment out policy service in docker-compose, add backwards-compat network alias
- Update services-matrix (gateway build line commented out)
- Update all codebase references: AdvisoryAI, JobEngine, CLI, router tests, helm
- Update docs: OFFLINE_KIT, configuration-migration, gateway guide, port-registry
- Deprecate etc/policy-gateway.yaml.sample with notice
- Eliminates 1 container, 9 HTTP round-trips, DPoP token flow

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:19:09 +03:00

104 lines
6.3 KiB
Markdown

# 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.