railiance-platform/docs/playwright-consumer-access.md
codex 6323db59ba Prepare Playwright consumer credentials and identity activation handoff
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a13690-09e0-7cd1-964b-ec83cdbcd348
2026-10-13 21:21:58 +02:00

5.4 KiB

Playwright consumer access

The release 0.1.0 pilot is running in namespace playwright on railiance01. Platform owns its lifecycle and the playwright-consumers group binding; rapp-playwright owns the browser implementation, package Role and client.

The initial membership policy includes all identified platform humans and coding agents. The group binding is installed and tested. Mapping authenticated platform identities into that Kubernetes group is still open in RPF-WP-0056-T03; a KeyCape group alone would not establish Kubernetes access. No administrator kubeconfig is distributed and no broad system:authenticated binding is installed.

Prepared consumer setup — activation pending

The helper and commands below are ready for owner integration. They are not a claim that the registrations, JWT authenticator or general consumer transport are active. The owner handoff lists the remaining changes and native acceptance checks. No further membership decision is needed.

After owner activation, use a private directory outside any Git worktree and a new token output path. keycape is the identity owner's native CLI:

install -d -m 700 "$HOME/.local/state/playwright-consumer"
keycape login --issuer https://kc.coulomb.social \
  --client-id playwright-cli --audience playwright-kubernetes \
  --scope 'openid profile groups playwright:connect' \
  --redirect-uri http://127.0.0.1:18764/callback \
  --out "$HOME/.local/state/playwright-consumer/token.json"

Registered coding agents instead use keycape service-token with their own Playwright client ID, audience playwright-kubernetes, scope playwright:connect, and --secret-env naming the variable populated by their governed custody route. Client registration and delivery are still pending; existing OpenBao/approval client credentials must not be reused. Tokens expire; authenticate again into a new private file and generate a new kubeconfig for renewal. There is no refresh token, secret provisioning or unattended human login in this helper.

From this repository, create the isolated consumer configuration:

python3 scripts/playwright_consumer.py setup \
  --token-file "$HOME/.local/state/playwright-consumer/token.json" \
  --out "$HOME/.local/state/playwright-consumer/kubeconfig.json"

Setup embeds only the public CA, exec helper and token file path. It refuses overwrites. The helper checks destination and CA before reading a mode-0600 token, then supplies a Kubernetes ExecCredential through kubectl's pipe. Local claim checks are misuse protection; Kubernetes must verify the JWT signature. The public CA was read from playwright/kube-root-ca.crt on the pinned cluster UID a553c742-0115-43d4-99a4-a5ca56fe0786; its SHA-256 is 794d3badd7c3743fe66c3671e7f152277f2ac9adddbc5cebe534802432861bd7. CA rotation requires a reviewed source update.

The owner-supported API transport must expose the TLS API on https://127.0.0.1:16444. The existing local ops-bridge tunnel is k3s-api-railiance01; its configured actor is workstation-specific and must not be shared with other users or agents. Each caller needs their own supported transport identity. With that route active, verify and forward:

python3 scripts/playwright_consumer.py verify \
  --kubeconfig "$HOME/.local/state/playwright-consumer/kubeconfig.json"
kubectl --kubeconfig "$HOME/.local/state/playwright-consumer/kubeconfig.json" \
  --context playwright -n playwright port-forward deployment/playwright \
  18081:8080 --address 127.0.0.1

Verification requires the unmodified generated kubeconfig, reads the actual API identity using SelfSubjectReview, and checks nine allowed/denied permissions. It rejects administrator identities and added impersonation settings. Its value-safe JSON result can be retained as an identity receipt. Run it separately for a human and a coding agent; then run each browser trial through that caller's forward. Existing port-forwards must be stopped separately during revocation; token expiry or client disablement does not prove an established stream closed.

In another terminal, from the existing rapp-playwright checkout:

python3 client/rapp_playwright.py preflight
python3 client/rapp_playwright.py trial --out .local/first-managed-trial

Use a new output directory each time. Keep run.json private: it contains the run capability. Download retained receipts/screenshots before the one-hour artifact expiry. Current targets are the bundled fixture and public OnCo home page; additional target admission remains separate from group membership.

Existing operator evidence

Platform can recheck the native permission boundary without changing grants:

python3 scripts/verify_playwright_access.py --output /tmp/playwright-rbac.json

The verifier uses administrator impersonation solely for authorization checks. Its success is not consumer-login proof. It checks the cluster UID, exact Role and group binding, allowed discovery/forwarding and denied exec, Secrets, workload writes, foreign scope and nonmembers.

October 13 evidence: RBAC, runtime and restart, responsive keyboard trial. Native operator-driven trials passed before and after a same-image restart; completed screenshots survived with identical hashes. Actual consumer login, abrupt-interruption recovery and cross-version rollback remain unproven.