- Add ConsoleSessionStore for managing console session state including tenants, profile, and token information. - Create OperatorContextService to manage operator context for orchestrator actions. - Implement OperatorMetadataInterceptor to enrich HTTP requests with operator context metadata. - Develop ConsoleProfileComponent to display user profile and session details, including tenant information and access tokens. - Add corresponding HTML and SCSS for ConsoleProfileComponent to enhance UI presentation. - Write unit tests for ConsoleProfileComponent to ensure correct rendering and functionality.
		
			
				
	
	
	
		
			6.1 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	Policy Gateway
Delivery scope:
StellaOps.Policy.Gatewayminimal API service fronting Policy Engine pack CRUD + activation endpoints for UI/CLI clients. Sender-constrained with DPoP and tenant headers, suitable for online and Offline Kit deployments.
1 · Responsibilities
- Proxy policy pack CRUD and activation requests to Policy Engine while enforcing scope policies (policy:read,policy:author,policy:review,policy:operate,policy:activate).
- Normalise responses (DTO + ProblemDetails) so Console, CLI, and automation receive consistent payloads.
- Guard activation actions with structured logging and metrics so approvals are auditable.
- Support dual auth modes:
- Forwarded caller tokens (Console/CLI) with DPoP proofs + X-Stella-Tenantheader.
- Gateway client credentials (DPoP) for service automation or Offline Kit flows when no caller token is present.
 
- Forwarded caller tokens (Console/CLI) with DPoP proofs + 
2 · Endpoints
| 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, orPolicyRevisionActivationDtoas described in the Policy Engine API doc (/docs/api/policy.md).
- Errors always return RFC 7807 ProblemDetailswith deterministic fields (title,detail,status). Missing caller credentials now surface401with"Upstream authorization missing"detail.
3 · Authentication & headers
| Header | Source | Notes | 
|---|---|---|
| Authorization | Forwarded caller token or gateway client credentials. | Caller tokens must include tenant scope; gateway tokens default to DPoPscheme. | 
| DPoP | Caller or gateway. | Required when Authority mandates proof-of-possession (default). Generated per request; gateway keeps ES256/ES384 key material under etc/policy-gateway-dpop.pem. | 
| X-Stella-Tenant | Caller | Tenant isolation header. Forwarded unchanged; gateway automation omits it. | 
Gateway client credentials are configured in policy-gateway.yaml:
policyEngine:
  baseAddress: "https://policy-engine.internal"
  audience: "api://policy-engine"
  clientCredentials:
    enabled: true
    clientId: "policy-gateway"
    clientSecret: "<secret>"
    scopes:
      - policy:read
      - policy:author
      - policy:review
      - policy:operate
      - policy:activate
  dpop:
    enabled: true
    keyPath: "../etc/policy-gateway-dpop.pem"
    algorithm: "ES256"
🔐 DPoP key – store the private key alongside Offline Kit secrets; rotate it whenever the gateway identity or Authority configuration changes.
4 · Metrics & logging
All activation calls emit:
- policy_gateway_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).
- policy_gateway_activation_latency_ms{outcome,source}– histogram measuring proxy latency.
Structured logs (category StellaOps.Policy.Gateway.Activation) include PackId, Version, Outcome, Source, and upstream status code for audit trails.
5 · Sample curl workflows
Assuming you already obtained a DPoP-bound access token ($TOKEN) for tenant acme:
# Generate a DPoP proof for GET via the CLI helper
DPoP_PROOF=$(stella auth dpop proof \
  --htu https://gateway.example.com/api/policy/packs \
  --htm GET \
  --token "$TOKEN")
curl -sS https://gateway.example.com/api/policy/packs \
  -H "Authorization: DPoP $TOKEN" \
  -H "DPoP: $DPoP_PROOF" \
  -H "X-Stella-Tenant: acme"
# Draft a new revision
DPoP_PROOF=$(stella auth dpop proof \
  --htu https://gateway.example.com/api/policy/packs/policy.core/revisions \
  --htm POST \
  --token "$TOKEN")
curl -sS https://gateway.example.com/api/policy/packs/policy.core/revisions \
  -H "Authorization: DPoP $TOKEN" \
  -H "DPoP: $DPoP_PROOF" \
  -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)
DPoP_PROOF=$(stella auth dpop proof \
  --htu https://gateway.example.com/api/policy/packs/policy.core/revisions/5:activate \
  --htm POST \
  --token "$TOKEN")
curl -sS https://gateway.example.com/api/policy/packs/policy.core/revisions/5:activate \
  -H "Authorization: DPoP $TOKEN" \
  -H "DPoP: $DPoP_PROOF" \
  -H "X-Stella-Tenant: acme" \
  -H "Content-Type: application/json" \
  -d '{"comment":"Rollout baseline"}'
For air-gapped environments, bundle policy-gateway.yaml and the DPoP key in the Offline Kit (see /docs/24_OFFLINE_KIT.md §5.7).
DPoP proof helper: Use
stella auth dpop proofto mint sender-constrained proofs locally. The command accepts--htu,--htm, and--tokenarguments and emits a ready-to-use header value. Teams maintaining alternate tooling (for example,scripts/make-dpop.sh) can substitute it as long as the inputs and output match the CLI behaviour.
6 · Offline Kit guidance
- Include policy-gateway.yaml.sampleand the resolved runtime config in the Offline Kit’sconfig/tree.
- Place the DPoP private key under secrets/policy-gateway-dpop.pemwith restricted permissions; document rotation steps in the manifest.
- When building verification scripts, use the gateway endpoints above instead of hitting Policy Engine directly. The Offline Kit validator now expects policy_gateway_activation_requests_totalmetrics in the Prometheus snapshot.
7 · Change log
- 2025-10-27 – Sprint 18.5: Initial gateway bootstrap + activation metrics + DPoP client credentials.