--- id: FLEX-WP-0009 type: workplan title: "Provide production authorization for user-engine" domain: infotech repo: flex-auth status: finished owner: codex topic_slug: netkingdom created: "2026-08-08" updated: "2026-08-16" depends_on: - NK-WP-0024 state_hub_workstream_id: "45756b89-feba-45f5-a24a-63a1119254bf" --- # FLEX-WP-0009 - user-engine production authorization Provide the cluster-local flex-auth policy-decision service required by the user-engine portal. The consumer contract is net-kingdom/docs/user-engine-platform-expansion-contract.md. ## T01 - Pin the protected-system vocabulary ```task id: FLEX-WP-0009-T01 status: done priority: high state_hub_task_id: "e940c5a3-ecb4-43d3-9554-2bfb422ec56d" ``` Add a user-engine protected-system manifest, resource manifests, subject fixtures, and check-request fixtures. Cover self, tenant-admin, and platform-admin actions over user, membership, invitation, tenant, recovery, and outbox resources. Unknown resources/actions and cross-tenant requests must deny. Done when all manifests validate and the vocabulary matches the action and resource strings emitted by user-engine. Done 2026-08-09: `examples/user-engine` defines the dynamic protected-system registry and verified-claim request vocabulary for platform, tenant-admin, self-service, cross-tenant, missing-role, and wrong-system cases. ## T02 - Implement and verify the policy package ```task id: FLEX-WP-0009-T02 status: done priority: high state_hub_task_id: "6e0fe708-d7ff-411f-a64d-84a1692a6e11" ``` Implement policy-as-code for self-only mutations, tenant-admin authority within one tenant, and platform-admin authority for tenant creation, recovery, outbox delivery, and replay. Include allow, deny, missing-role, target-user mismatch, cross-tenant, malformed-context, and stale-policy fixtures. Done when fixture evaluation is deterministic, default deny is proven, and decision envelopes contain stable decision IDs and policy provenance. Done 2026-08-09: all six embedded Rego tests and all six request fixtures pass; the package validates under CARING 0.4.0-rc2 and the registry loads cleanly. ## T03 - Deploy the cluster-local service ```task id: FLEX-WP-0009-T03 status: done priority: high state_hub_task_id: "f8293230-136d-4f2d-8d3f-bb9840ea7e63" ``` Publish an immutable flex-auth image and deploy a namespaced Service at http://flex-auth.flex-auth.svc.cluster.local:8080. Apply least-privilege security context, readiness/liveness probes, resource limits, default-deny NetworkPolicy, and ingress restricted to approved protected systems. Done when user-engine can reach POST /v1/check, an unrelated namespace cannot, and restart/rollback procedures are documented. Done 2026-08-09: immutable digest `sha256:a31961c45215aa6baf3bc748c6741ab703c2c8325e61aa7983a355026195e51b` is deployed as `flex-auth-user-engine.flex-auth.svc.cluster.local:8080`, Ready behind ingress restricted to the user-engine workload and with no egress. ## T04 - Hand back production evidence ```task id: FLEX-WP-0009-T04 status: done priority: high state_hub_task_id: "97b931e9-ac5b-46c7-a462-e23c0c18c4f4" ``` Run live allow, deny, service-unavailable, and cross-tenant probes from the user-engine namespace. Record only non-secret decision IDs, effects, reasons, policy version, and correlation IDs. Send completion evidence to NK-WP-0024. Done when user-engine can replace its local authorization bridge without an availability bypass and the deployed failure matrix remains fail closed. 2026-08-09 live evidence: from the user-engine pod, `live-self` returned allow with decision `decision:4bf95ebb989ac628`; the cross-tenant variant returned deny/cross_tenant with decision `decision:bab072ce3ee72d98`. Runtime activation remains gated on the separately owned event and mail receivers. 2026-08-10 re-probe: all six policy fixtures were replayed against the **deployed** `flex-auth-user-engine.flex-auth.svc.cluster.local:8080` and every one matched its expected effect and reason — `self-allow` `decision:27cbab2e5533508a` allow/`self_service`; `tenant-admin-allow` `decision:350b46fb42989606` allow/`tenant_admin`; `platform-allow` `decision:79334537419466bd` allow/`platform_operator`; `cross-tenant-deny` `decision:b3cc0b7e819aecde` deny/`cross_tenant`; `missing-role-deny` `decision:818e2249491ef09f` deny/`no_matching_role_or_context`; `wrong-system-deny` `decision:5e20697e202aa7c6` deny/`wrong_system`. The deployed failure matrix is therefore confirmed still fail-closed 42h into the current rollout. **Still open, and not flex-auth's to close:** the done-criterion is that *user-engine* replaces its local authorization bridge without an availability bypass. That cutover is user-engine's decision and remains gated on the separately owned event and mail receivers. flex-auth has delivered and re-verified the service side; T04 stays `progress` rather than being marked done on evidence that only covers half the criterion. Done 2026-08-16: the consumer-side half is now closed. `NK-WP-0024` is `finished`; its T01 records that the portal runtime is live on `FlexAuthHTTPAdapter` (not the local bridge), with `USER_ENGINE_FLEX_AUTH_URL=http://flex-auth-user-engine.flex-auth.svc.cluster.local:8080`. The deployed user-engine image is `sha256:e3b5f65bafc1c0260dfdf2567a52766e67506ceb878a51759a2e9a307c4b5eb8`. Fresh flex-auth-side probe against the live service `flex-auth-user-engine.flex-auth.svc.cluster.local:8080` running `forgejo.coulomb.social/coulomb/flex-auth@sha256:1f5290376dc5fcf456dc7a785e394d8b90949dabecd1d3e856f38557149bb5f4` (registration-applicant policy included; the in-repo deploy manifest was still pinned to the older T03 digest and is synced to this one): | Fixture | Effect / reason | Decision id | | --- | --- | --- | | `self-allow` | allow / `self_service` | `decision:27cbab2e5533508a` | | `tenant-admin-allow` | allow / `tenant_admin` | `decision:350b46fb42989606` | | `platform-allow` | allow / `platform_operator` | `decision:79334537419466bd` | | `cross-tenant-deny` | deny / `cross_tenant` | `decision:b3cc0b7e819aecde` | | `missing-role-deny` | deny / `no_matching_role_or_context` | `decision:818e2249491ef09f` | | `wrong-system-deny` | deny / `wrong_system` | `decision:5e20697e202aa7c6` | | `registration-applicant-allow` | allow / `registration_applicant` | `decision:d83fc413afebf2f6` | | `registration-applicant-membership-deny` | deny / `no_matching_role_or_context` | `decision:4ca487126987f89c` | | `registration-applicant-wrong-issuer-deny` | deny / `no_matching_role_or_context` | `decision:138c574dee279d23` | All nine fixtures matched. From the user-engine pod, `http://flex-auth-user-engine.flex-auth.svc.cluster.local:8080/healthz` returned HTTP 200. Unavailability from that same namespace is connection-refused on a closed port and NXDOMAIN on a missing Service name; `FlexAuthHTTPAdapter` maps those to deny `authorization service unavailable` (no availability bypass). Completion evidence sent to `user-engine` and `net-kingdom` (NK-WP-0024).