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

6.3 KiB

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:

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.