net-kingdom/docs/playwright-registration.md
tegwick 5dd74dfbdf
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
security: prepare scoped Playwright consumer registrations and owner delivery
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a1346b-72a4-7d40-b8bd-8b8ca346cfa2
2026-10-13 23:13:48 +02:00

6.7 KiB

Playwright registration owner contract

Source preparation under NK-WP-0050; live custody, rollout and consumer acceptance remain open. Implements the registration part of RPF-WP-0056 and CUST-WP-0080-T05. The existing browser SecurityCaseType remains unchanged: its HTTPS/standard-scope admission does not cover this loopback/custom-scope use. No case acceptance record is fabricated or borrowed from Forgejo/OpenBao.

Prepare the non-secret records

Run python3 sso-mfa/k8s/keycape/playwright-registration.py for the public client, or add --agents <identity-references.json> for the complete proposed Playwright agent inventory. The latter is an array with one object per existing registered identity:

[
  {
    "agent_id": "test-agent",
    "service_subject": "service:test-agent:platform",
    "tenant": "tenant:test",
    "identity_record": "synthetic/agent-record.json"
  }
]

This example is synthetic; it is not an admitted consumer. The identity owner must confirm each real record, subject, tenant and agent assignment. A reference string is not evidence of registration. Initial eligibility already covers all identified platform humans and coding agents; no new membership decision is needed. The compiler does not provision identities or retrieve/mint credentials.

Field Public human client Each coding agent
client ID playwright-cli playwright-agent-<agent_id>
grant authorization code, public PKCE client credentials, confidential
audience playwright-kubernetes playwright-kubernetes
scope openid profile groups playwright:connect playwright:connect
redirect exact http://127.0.0.1:18764/callback none
subject/tenant existing directory user and tenant exact registered subject/tenant supplied by owner
role existing human roles only coding-agent
lifetime existing issuer setting, explicit and at most one hour 15 minutes

The public client has no per-client lifetime override; KeyCape supports that only for client-credentials clients. Existing issuer lifetime outside the accepted bound refuses preparation and needs owner reconciliation; this tool does not change every client's lifetime. No public tenant override or MFA opt-out is added. The callback, dedicated audience and custom scope match Platform's candidate. The resource uses access tokens; ID tokens retain the client audience.

Each agent gets a distinct proposed env binding from keycape-<client-id>-client, key client-secret, to KEYCAPE_<CLIENT_ID_WITH_UNDERSCORES>_CLIENT_SECRET. These names describe a proposed delivery contract, not existing Secrets or admitted custody. Platform must bind an exact OpenBao/ESO and consumer delivery route with its own source task and acceptance. No existing OpenBao client or secret is reused. Secret values must never enter this identity-reference file, Git, command arguments, coordination messages or receipts.

Registry and activation boundary

The pure prepare_registry(secret, identities, operation) adapter reuses keycape-client.py's byte-preserving insertion/removal. It validates the entire inventory first, refuses differing existing records, ambiguous YAML, duplicate IDs, shared secret references and unreviewed registrations for this dedicated audience. An identical registration is a no-op. A separate existing OpenBao registration for the same agent subject is preserved, with its distinct audience and secret reference. Unrelated configuration, including signing material, is unchanged. The encoded result contains private registry data and must stay inside the protected activation process; the CLI never accepts or emits that registry.

This is not a live apply command. NK-WP-0050-T02 must finish the exact owner activation path using existing registry/Deployment operations:

  1. Bind verified identity inventory and source digests to the proposal. Obtain the governed per-agent custody and delivery references from Platform.
  2. Pin current cluster, issuer image and object identities. Read the registry only within the existing protected owner execution path. Run the actual pinned KeyCape check-config on live and proposed configurations, with the exact Deployment env names and policy-store mode; suppress private diagnostics.
  3. Prepare UID/resource-version/data-bound registry mutation and exact env bindings. Preserve all unrelated data and authentication methods. Retain created-only provenance, restart prerequisites, readback and guarded rollback before proposing any live action. A compare-and-swap conflict means reconcile, never replay a stale whole registry.
  4. Obtain the scoped live action disposition under the existing supervision rules, execute its exact revision, verify config/env/image/readiness and existing human/service login. No new runtime authority comes from this file.

operation=remove is an exact inventory removal proposal, not automatic rollback: the activation adapter must remove only registrations it created, preserve pre-existing identical entries and refuse intervening drift. Keep custody material until recovery/retention requirements are met. Disabling/removing registration stops new issuance after the issuer loads the change; issued JWTs remain valid until expiry, and established connections need separate termination through the transport owner. No immediate global revocation is claimed.

Verification and completion

Python tests exercise preservation, add/no-op/remove, lifetime bounds, identity conflicts, distinct credentials and contained invalid-input output. The native Go fixture tests/playwright_registration_native_test.go is copied into a disposable committed KeyCape checkout at src/internal/authclient/ and consumes the merged synthetic configuration through PLAYWRIGHT_SYNTHETIC_CONFIG. It loads the config and domain registrations, performs native token/JWKS exchanges for both client kinds, and checks dedicated claims, wrong secret, scope, audience, signature, PKCE and callback refusals. It uses synthetic users and seeded authorization sessions; it does not prove upstream login, production image compatibility, native Kubernetes CEL validation or consumer eligibility.

T03 needs actual issuer issuance and native API allow/deny receipts, one real human and one real registered coding agent independently running Platform's consumer command and provider responsive/keyboard trial, renewal, revocation and active connection termination. Cluster authentication and ops-bridge transport remain their owners' implementations. Platform/provider must accept the receipts before managed discovery is published. Same-image abrupt provider recovery is already evidenced; cross-version rollback is still explicitly unproven.