Activate Playwright pilot with scoped consumer group and native evidence
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13690-09e0-7cd1-964b-ec83cdbcd348
This commit is contained in:
parent
b98d17c09f
commit
60101b0932
21 changed files with 1055 additions and 28 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,6 +13,7 @@ helm/*.yaml
|
||||||
!helm/*-probe.yaml
|
!helm/*-probe.yaml
|
||||||
!helm/vergabe-demo-company-role.yaml
|
!helm/vergabe-demo-company-role.yaml
|
||||||
!helm/vergabe-demo-company-database.yaml
|
!helm/vergabe-demo-company-database.yaml
|
||||||
|
!helm/playwright-consumer-access.yaml
|
||||||
|
|
||||||
# ArgoCD repository credentials — encrypt locally, never commit
|
# ArgoCD repository credentials — encrypt locally, never commit
|
||||||
argocd/repositories/*.repository.sops.yaml
|
argocd/repositories/*.repository.sops.yaml
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
| task | RPF-WP-0035-T13 | done | — | workplans/RPF-WP-0035-credential-lane-implementation.md |
|
| task | RPF-WP-0035-T13 | done | — | workplans/RPF-WP-0035-credential-lane-implementation.md |
|
||||||
| task | RPF-WP-0036-T01 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T01 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
| task | RPF-WP-0036-T02 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T02 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
| task | RPF-WP-0036-T03 | todo | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T03 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
| task | RPF-WP-0036-T04 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T04 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
| task | RPF-WP-0036-T05 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T05 | done | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
| task | RPF-WP-0036-T06 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
| task | RPF-WP-0036-T06 | wait | — | workplans/RPF-WP-0036-platform-service-assurance.md |
|
||||||
|
|
@ -94,12 +94,12 @@
|
||||||
| task | RPF-WP-0043-T05 | done | — | workplans/RPF-WP-0043-policy-nexus-argocd-onboarding.md |
|
| task | RPF-WP-0043-T05 | done | — | workplans/RPF-WP-0043-policy-nexus-argocd-onboarding.md |
|
||||||
| task | RPF-WP-0044-T01 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T01 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T02 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T02 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T03 | todo | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T03 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T04 | todo | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T04 | wait | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T05 | todo | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T05 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T06 | todo | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T06 | wait | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T07 | wait | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T07 | wait | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0044-T08 | wait | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
| task | RPF-WP-0044-T08 | done | — | workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md |
|
||||||
| task | RPF-WP-0045-T01 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
| task | RPF-WP-0045-T01 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
||||||
| task | RPF-WP-0045-T02 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
| task | RPF-WP-0045-T02 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
||||||
| task | RPF-WP-0045-T03 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
| task | RPF-WP-0045-T03 | done | — | workplans/RPF-WP-0045-eso-kubernetes-auth-activity-core-email-connect.md |
|
||||||
|
|
@ -116,7 +116,7 @@
|
||||||
| task | RPF-WP-0047-T02 | done | — | workplans/RPF-WP-0047-bao-coulomb-social-notice-page.md |
|
| task | RPF-WP-0047-T02 | done | — | workplans/RPF-WP-0047-bao-coulomb-social-notice-page.md |
|
||||||
| task | RPF-WP-0047-T03 | done | — | workplans/RPF-WP-0047-bao-coulomb-social-notice-page.md |
|
| task | RPF-WP-0047-T03 | done | — | workplans/RPF-WP-0047-bao-coulomb-social-notice-page.md |
|
||||||
| task | RPF-WP-0048-T01 | done | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
| task | RPF-WP-0048-T01 | done | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
||||||
| task | RPF-WP-0048-T02 | todo | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
| task | RPF-WP-0048-T02 | wait | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
||||||
| task | RPF-WP-0048-T03 | done | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
| task | RPF-WP-0048-T03 | done | — | workplans/RPF-WP-0048-activity-core-gitops-adoption.md |
|
||||||
| task | RPF-WP-0049-T01 | done | — | workplans/RPF-WP-0049-platform-root-custody-record-delivery.md |
|
| task | RPF-WP-0049-T01 | done | — | workplans/RPF-WP-0049-platform-root-custody-record-delivery.md |
|
||||||
| task | RPF-WP-0049-T02 | done | — | workplans/RPF-WP-0049-platform-root-custody-record-delivery.md |
|
| task | RPF-WP-0049-T02 | done | — | workplans/RPF-WP-0049-platform-root-custody-record-delivery.md |
|
||||||
|
|
|
||||||
54
docs/adr/ADR-0006-playwright-consumer-group.md
Normal file
54
docs/adr/ADR-0006-playwright-consumer-group.md
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
id: RPLAT-ADR-0006
|
||||||
|
title: "ADR-0006 — Give Playwright consumers a dedicated namespace-scoped group"
|
||||||
|
status: accepted
|
||||||
|
revision: "1.0"
|
||||||
|
owner: railiance-platform
|
||||||
|
date: "2026-10-13"
|
||||||
|
last_reviewed: "2026-10-13"
|
||||||
|
review_interval: 6m
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
rapp-playwright's published private pilot has a namespace Role but deliberately
|
||||||
|
no consumer binding. The user requested establishing a group during the Platform
|
||||||
|
open-work review. Existing cluster documentation provides administrative access;
|
||||||
|
the live binding inventory contains no non-system consumer group.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
Establish Kubernetes RBAC group subject `playwright-consumers`, bound only to
|
||||||
|
the package-owned `playwright-consumer` Role in namespace `playwright`. Platform
|
||||||
|
owns the RoleBinding; rapp-playwright retains the Role and workload source.
|
||||||
|
The initial membership policy includes all identified platform humans and coding
|
||||||
|
agents, as explicitly directed by the user. No per-use-case membership restriction
|
||||||
|
is introduced now. The identity/cluster owners must implement an authenticated
|
||||||
|
group claim for those entities before general consumer availability is accepted.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
The Role permits pod get/list, pod port-forward creation and get of Deployment
|
||||||
|
`playwright`. It grants no Secrets, pod exec, workload writes, identity
|
||||||
|
impersonation or other namespaces. The namespace must remain dedicated to this
|
||||||
|
service because pod discovery and forwarding cover all its pods. Membership
|
||||||
|
confers browser-job submission for the reviewed trusted targets; it does not
|
||||||
|
authorize private targets, hostile pages or mutually untrusted tenant workloads.
|
||||||
|
|
||||||
|
Kubernetes has no separate Group object to create. This establishes an RBAC
|
||||||
|
subject and permissions, not a KeyCape group, login integration or membership.
|
||||||
|
Administrator impersonation can verify the permission boundary but cannot prove
|
||||||
|
consumer authentication. RPF-WP-0056 retains those outstanding acceptance steps.
|
||||||
|
|
||||||
|
Rollback removes only the Platform RoleBinding after reviewing its exact live
|
||||||
|
identity; it does not delete the Namespace, workload or artifact PVC. Existing
|
||||||
|
port-forwards require separate termination when revoking a consumer's active
|
||||||
|
access. Do not treat removal of a binding as proof that a running tunnel closed.
|
||||||
|
|
||||||
|
## Alternatives considered
|
||||||
|
|
||||||
|
Binding all authenticated users would broaden browser access beyond the human/coding-agent
|
||||||
|
identity population. Sharing the administrator kubeconfig would convey unrelated cluster
|
||||||
|
authority. Both are rejected. Selecting OIDC configuration or issuing client
|
||||||
|
certificates without an owner-supported membership route remains outside this
|
||||||
|
bounded group-binding change.
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
{
|
||||||
|
"id": "b11fd28b-58fe-4b20-a15e-32b18ea76f2b",
|
||||||
|
"api_version": "1",
|
||||||
|
"status": "passed",
|
||||||
|
"error": null,
|
||||||
|
"label": "independent-browser-trial",
|
||||||
|
"target": "fixture",
|
||||||
|
"viewports": [
|
||||||
|
{
|
||||||
|
"name": "desktop",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 800
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow",
|
||||||
|
"width": 390,
|
||||||
|
"height": 844
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeout_ms": 60000,
|
||||||
|
"created_at": "2026-10-13T18:52:59.076Z",
|
||||||
|
"expires_at": "2026-10-13T19:52:59.076Z",
|
||||||
|
"service_version": "0.1.0",
|
||||||
|
"playwright_version": "1.64.0",
|
||||||
|
"release": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"execution_location": "railiance01/playwright",
|
||||||
|
"browser_version": "156.0.8078.4",
|
||||||
|
"completed_steps": 14,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 0,
|
||||||
|
"action": "visible",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.091Z",
|
||||||
|
"selector": "h1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 1,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.214Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 2,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.323Z",
|
||||||
|
"key": "Tab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 3,
|
||||||
|
"action": "focused",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.360Z",
|
||||||
|
"selector": "#increment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 4,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.393Z",
|
||||||
|
"key": "Enter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 5,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.407Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 6,
|
||||||
|
"action": "screenshot",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:01.454Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 0,
|
||||||
|
"action": "visible",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.526Z",
|
||||||
|
"selector": "h1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 1,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.786Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 2,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.877Z",
|
||||||
|
"key": "Tab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 3,
|
||||||
|
"action": "focused",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.891Z",
|
||||||
|
"selector": "#increment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 4,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.896Z",
|
||||||
|
"key": "Enter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 5,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.905Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 6,
|
||||||
|
"action": "screenshot",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:53:02.915Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"artifacts": [
|
||||||
|
{
|
||||||
|
"name": "desktop-6-keyboard-result.png",
|
||||||
|
"bytes": 26622
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "desktop-final.png",
|
||||||
|
"bytes": 26622
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-6-keyboard-result.png",
|
||||||
|
"bytes": 24280
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-final.png",
|
||||||
|
"bytes": 24280
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"started_at": "2026-10-13T18:52:59.078Z",
|
||||||
|
"blocked_requests": 12,
|
||||||
|
"finished_at": "2026-10-13T18:53:03.351Z",
|
||||||
|
"downloads": [
|
||||||
|
{
|
||||||
|
"name": "desktop-6-keyboard-result.png",
|
||||||
|
"bytes": 26622,
|
||||||
|
"sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "desktop-final.png",
|
||||||
|
"bytes": 26622,
|
||||||
|
"sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-6-keyboard-result.png",
|
||||||
|
"bytes": 24280,
|
||||||
|
"sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-final.png",
|
||||||
|
"bytes": 24280,
|
||||||
|
"sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/evidence/2026-10-13-playwright-managed/desktop-final.png
Normal file
BIN
docs/evidence/2026-10-13-playwright-managed/desktop-final.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/evidence/2026-10-13-playwright-managed/narrow-final.png
Normal file
BIN
docs/evidence/2026-10-13-playwright-managed/narrow-final.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"wrong_token": true,
|
||||||
|
"wrong_artifact_token": true,
|
||||||
|
"ui_failure_distinguished": true,
|
||||||
|
"bounded_cancellation": true,
|
||||||
|
"private_target_refused": true,
|
||||||
|
"preflight_healthy": true
|
||||||
|
}
|
||||||
24
docs/evidence/2026-10-13-playwright-managed/preflight.json
Normal file
24
docs/evidence/2026-10-13-playwright-managed/preflight.json
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
"available": true,
|
||||||
|
"error": null,
|
||||||
|
"checked_at": "2026-10-13T18:49:56.214Z",
|
||||||
|
"browser_version": "156.0.8078.4",
|
||||||
|
"api_version": "1",
|
||||||
|
"service_version": "0.1.0",
|
||||||
|
"playwright_version": "1.64.0",
|
||||||
|
"execution_location": "railiance01/playwright",
|
||||||
|
"release": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"allowed_origins": [
|
||||||
|
"https://onco.cc"
|
||||||
|
],
|
||||||
|
"fixture": true,
|
||||||
|
"active": 0,
|
||||||
|
"queued": 0,
|
||||||
|
"limits": {
|
||||||
|
"concurrency": 1,
|
||||||
|
"max_queue": 4,
|
||||||
|
"max_timeout_ms": 120000,
|
||||||
|
"retention_ms": 3600000,
|
||||||
|
"max_runs": 64
|
||||||
|
}
|
||||||
|
}
|
||||||
184
docs/evidence/2026-10-13-playwright-managed/receipt.json
Normal file
184
docs/evidence/2026-10-13-playwright-managed/receipt.json
Normal file
|
|
@ -0,0 +1,184 @@
|
||||||
|
{
|
||||||
|
"id": "6a51e164-cec5-46ed-89b1-92b93dd16d23",
|
||||||
|
"api_version": "1",
|
||||||
|
"status": "passed",
|
||||||
|
"error": null,
|
||||||
|
"label": "independent-browser-trial",
|
||||||
|
"target": "fixture",
|
||||||
|
"viewports": [
|
||||||
|
{
|
||||||
|
"name": "desktop",
|
||||||
|
"width": 1280,
|
||||||
|
"height": 800
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow",
|
||||||
|
"width": 390,
|
||||||
|
"height": 844
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"timeout_ms": 60000,
|
||||||
|
"created_at": "2026-10-13T18:50:40.554Z",
|
||||||
|
"expires_at": "2026-10-13T19:50:40.554Z",
|
||||||
|
"service_version": "0.1.0",
|
||||||
|
"playwright_version": "1.64.0",
|
||||||
|
"release": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"execution_location": "railiance01/playwright",
|
||||||
|
"browser_version": "156.0.8078.4",
|
||||||
|
"completed_steps": 14,
|
||||||
|
"steps": [
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 0,
|
||||||
|
"action": "visible",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.655Z",
|
||||||
|
"selector": "h1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 1,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.815Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 2,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.851Z",
|
||||||
|
"key": "Tab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 3,
|
||||||
|
"action": "focused",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.911Z",
|
||||||
|
"selector": "#increment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 4,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.924Z",
|
||||||
|
"key": "Enter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 5,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.937Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "desktop",
|
||||||
|
"index": 6,
|
||||||
|
"action": "screenshot",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:42.949Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 0,
|
||||||
|
"action": "visible",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:43.919Z",
|
||||||
|
"selector": "h1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 1,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.063Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 2,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.180Z",
|
||||||
|
"key": "Tab"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 3,
|
||||||
|
"action": "focused",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.228Z",
|
||||||
|
"selector": "#increment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 4,
|
||||||
|
"action": "press",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.260Z",
|
||||||
|
"key": "Enter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 5,
|
||||||
|
"action": "text",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.275Z",
|
||||||
|
"selector": "#count"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"viewport": "narrow",
|
||||||
|
"index": 6,
|
||||||
|
"action": "screenshot",
|
||||||
|
"status": "passed",
|
||||||
|
"at": "2026-10-13T18:50:44.314Z"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"artifacts": [
|
||||||
|
{
|
||||||
|
"name": "desktop-6-keyboard-result.png",
|
||||||
|
"bytes": 26622
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "desktop-final.png",
|
||||||
|
"bytes": 26622
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-6-keyboard-result.png",
|
||||||
|
"bytes": 24280
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-final.png",
|
||||||
|
"bytes": 24280
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"started_at": "2026-10-13T18:50:40.557Z",
|
||||||
|
"blocked_requests": 12,
|
||||||
|
"finished_at": "2026-10-13T18:50:44.840Z",
|
||||||
|
"downloads": [
|
||||||
|
{
|
||||||
|
"name": "desktop-6-keyboard-result.png",
|
||||||
|
"bytes": 26622,
|
||||||
|
"sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "desktop-final.png",
|
||||||
|
"bytes": 26622,
|
||||||
|
"sha256": "b15998824256b86c74f2bbb75f061061be65db0b4f3bb5444529ac69a723cdad"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-6-keyboard-result.png",
|
||||||
|
"bytes": 24280,
|
||||||
|
"sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "narrow-final.png",
|
||||||
|
"bytes": 24280,
|
||||||
|
"sha256": "49d27cb169b8e180ce93969c6d2b8619a7684cf035bb9dcae9cd91d8bd9952e8"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
40
docs/evidence/2026-10-13-playwright-managed/runtime.json
Normal file
40
docs/evidence/2026-10-13-playwright-managed/runtime.json
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"observed_at": "2026-10-13T18:52:58.325239+00:00",
|
||||||
|
"image": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"replica_ready": true,
|
||||||
|
"pvc_phase": "Bound",
|
||||||
|
"pvc_uid": "da36929a-1d69-457a-ad99-7580ef86ab18",
|
||||||
|
"pvc_size": "2Gi",
|
||||||
|
"initial_pod_uid": "3475ad46-d9d8-4b97-99b7-54b4d984d2f2",
|
||||||
|
"restarted_pod_uid": "a22030a4-c12d-4e97-be8d-98a8d80808c2",
|
||||||
|
"same_image_restart_completed_artifacts_verified": true,
|
||||||
|
"preflight_after_restart": {
|
||||||
|
"available": true,
|
||||||
|
"error": null,
|
||||||
|
"checked_at": "2026-10-13T18:51:59.595Z",
|
||||||
|
"browser_version": "156.0.8078.4",
|
||||||
|
"api_version": "1",
|
||||||
|
"service_version": "0.1.0",
|
||||||
|
"playwright_version": "1.64.0",
|
||||||
|
"execution_location": "railiance01/playwright",
|
||||||
|
"release": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"allowed_origins": [
|
||||||
|
"https://onco.cc"
|
||||||
|
],
|
||||||
|
"fixture": true,
|
||||||
|
"active": 0,
|
||||||
|
"queued": 0,
|
||||||
|
"limits": {
|
||||||
|
"concurrency": 1,
|
||||||
|
"max_queue": 4,
|
||||||
|
"max_timeout_ms": 120000,
|
||||||
|
"retention_ms": 3600000,
|
||||||
|
"max_runs": 64
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"access_path": "Existing authenticated operator SSH; administrator impersonation of playwright-consumers; loopback-only port-forward",
|
||||||
|
"actual_consumer_authentication_proven": false,
|
||||||
|
"cross_version_rollback_proven": false,
|
||||||
|
"abrupt_interruption_recovery_proven": false,
|
||||||
|
"source_workload_sha256": "d5d3f3d816dd4320059b4fcdc8409fb84d6075aeb1f409f4d112263d7e14191d"
|
||||||
|
}
|
||||||
194
docs/evidence/2026-10-13-playwright-rbac.json
Normal file
194
docs/evidence/2026-10-13-playwright-rbac.json
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
{
|
||||||
|
"schema": "platform-playwright-rbac/v1",
|
||||||
|
"observed_at": "2026-10-13T18:49:52.369304+00:00",
|
||||||
|
"cluster_uid": "a553c742-0115-43d4-99a4-a5ca56fe0786",
|
||||||
|
"role_uid": "d24e8b51-7456-4000-8816-b4a49a06ca37",
|
||||||
|
"binding_uid": "190eb32f-8649-4b36-a525-8936cf3ceb51",
|
||||||
|
"group": "playwright-consumers",
|
||||||
|
"checks": [
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "get",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": true,
|
||||||
|
"allowed": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "list",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": true,
|
||||||
|
"allowed": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "portforward",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": true,
|
||||||
|
"allowed": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "get",
|
||||||
|
"resource": "deployments",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "apps",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": "playwright"
|
||||||
|
},
|
||||||
|
"expected": true,
|
||||||
|
"allowed": true,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "get",
|
||||||
|
"resource": "deployments",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "apps",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": "other"
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "get",
|
||||||
|
"resource": "secrets",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "exec",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "patch",
|
||||||
|
"resource": "deployments",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "apps",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": "playwright"
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "portforward",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "default",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": true,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "rolebindings",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "rbac.authorization.k8s.io",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": false,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "list",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"member": false,
|
||||||
|
"attributes": {
|
||||||
|
"verb": "create",
|
||||||
|
"resource": "pods",
|
||||||
|
"subresource": "portforward",
|
||||||
|
"group": "",
|
||||||
|
"namespace": "playwright",
|
||||||
|
"name": ""
|
||||||
|
},
|
||||||
|
"expected": false,
|
||||||
|
"allowed": false,
|
||||||
|
"passed": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"passed": true,
|
||||||
|
"actual_consumer_authentication_proven": false
|
||||||
|
}
|
||||||
16
docs/evidence/2026-10-13-playwright-source-review.json
Normal file
16
docs/evidence/2026-10-13-playwright-source-review.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"schema": "platform-playwright-source-review/v1",
|
||||||
|
"source_commit": "70268154c06cf78c5d9e1f4eb900213ffd436d1b",
|
||||||
|
"source_sha256": {
|
||||||
|
"declarations/rapp.yaml": "5b030686f1e3ca737805e681fc8b714e1452f879a3fa30bbac8ca30798bb3343",
|
||||||
|
"manifests/workload.yaml": "7d76ad38e25597b629660d31782867d84d7241020a2e450e346a3792ce43290c",
|
||||||
|
"releases/0.1.0.json": "364dcbc16fd50155b7d8eddb0ecb87b1709f0efdc8a41c9f15afd81e5a18506e",
|
||||||
|
"docs/platform-admission.md": "c37dc9f77d5be5bc55c873af98e8ecb0bc945ddd37ea42010d169f5d472b53c0",
|
||||||
|
"docs/operations.md": "fea5f9e25752c0199839559da5bba0ebca77be7c4906dbce4b7b6278ce5b4dab"
|
||||||
|
},
|
||||||
|
"image": "forgejo.coulomb.social/coulomb/rapp-playwright@sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441",
|
||||||
|
"provider_unit_tests_passed": 3,
|
||||||
|
"managed_runtime_accepted": false,
|
||||||
|
"group": "playwright-consumers",
|
||||||
|
"member_identities": []
|
||||||
|
}
|
||||||
47
docs/playwright-consumer-access.md
Normal file
47
docs/playwright-consumer-access.md
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
Once the caller has the supported group identity and API route:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
kubectl -n playwright port-forward deployment/playwright 18081:8080 --address 127.0.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
In another terminal, from the existing rapp-playwright checkout:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
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.
|
||||||
|
|
||||||
|
Platform can recheck the native permission boundary without changing grants:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
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](evidence/2026-10-13-playwright-rbac.json),
|
||||||
|
[runtime and restart](evidence/2026-10-13-playwright-managed/runtime.json),
|
||||||
|
[responsive keyboard trial](evidence/2026-10-13-playwright-managed/receipt.json).
|
||||||
|
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.
|
||||||
18
helm/playwright-consumer-access.yaml
Normal file
18
helm/playwright-consumer-access.yaml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Group membership and authentication are managed by the identity/cluster owners.
|
||||||
|
# This binding does not issue credentials or make anyone a member.
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: playwright-consumers
|
||||||
|
namespace: playwright
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: rapp-playwright
|
||||||
|
app.kubernetes.io/managed-by: railiance-platform
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: playwright-consumer
|
||||||
|
subjects:
|
||||||
|
- apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Group
|
||||||
|
name: playwright-consumers
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
---
|
||||||
|
id: RPF-IN-0012
|
||||||
|
kind: intake
|
||||||
|
type: intake
|
||||||
|
title: "Return independent task-execution contract and wrapped-delivery owner review"
|
||||||
|
repo: railiance-platform
|
||||||
|
status: open
|
||||||
|
owner: railiance-platform
|
||||||
|
requested_by: secrets-engine
|
||||||
|
origin: handoff
|
||||||
|
origin_ref: SECRETS-WP-0013-T01
|
||||||
|
priority: high
|
||||||
|
created: "2026-10-11"
|
||||||
|
updated: "2026-10-11"
|
||||||
|
---
|
||||||
|
|
||||||
|
Review the proposed SECRETS-EXEC-20261011-v1 metadata-only mediated execution
|
||||||
|
contract and return the exact Platform owner workplan/task binding and reviewed
|
||||||
|
revision. Identity/approval/PDP owners still owe independent returns. This intake
|
||||||
|
records no foreign owner assent and requests no credential value or native action.
|
||||||
|
|
||||||
|
D3 P3=b separately selects response-wrapped issuer delivery. The existing issuer
|
||||||
|
primitive is hardened in Secrets Engine: native KV-v2/AppRole creation path and
|
||||||
|
TTL/accessor are verified, a fresh private recipient file is exclusively reserved
|
||||||
|
and fsynced before mint, and uncertain attempts cannot silently overwrite/remint.
|
||||||
|
Disposable local OpenBao proves a first unwrap and specific consumed-token denial;
|
||||||
|
it does not prove estate custody or delivery. Review the exact actor/path/audience,
|
||||||
|
deadline, authorization/consume, destination, audit, replay/crash reconciliation and
|
||||||
|
rollback requirements for a separate delivery operation. Metadata execute-ccr
|
||||||
|
explicitly excludes wrap/KV-value delivery and cannot lend its grant to this lane.
|
||||||
|
|
||||||
|
Source: secrets-engine/docs/task-scoped-openbao-execution-contract.md and
|
||||||
|
src/secrets_engine/{openbao,wrap}.py; tests/test_wrapped_issuer_native.py is an
|
||||||
|
isolated test, not a production proof. The already D2-approved repository issuer
|
||||||
|
has its own prepared bounded command and attended Platform login requirement;
|
||||||
|
no second repository scope approval is requested and its waiting task is not
|
||||||
|
reopened by this source review. Owner-prepared execution must precede any new
|
||||||
|
attended item. Genuinely expanded scope belongs in the single daily red batch.
|
||||||
94
scripts/verify_playwright_access.py
Normal file
94
scripts/verify_playwright_access.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Read-only native RBAC checks; impersonation is not consumer login proof."""
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
CLUSTER_UID = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
|
||||||
|
GROUP = 'playwright-consumers'
|
||||||
|
ROLE = 'playwright-consumer'
|
||||||
|
|
||||||
|
|
||||||
|
def verify(target):
|
||||||
|
def kubectl(args, body=None):
|
||||||
|
result = subprocess.run(
|
||||||
|
['ssh', '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=10', target,
|
||||||
|
shlex.join(['kubectl', '--request-timeout=10s', *args])],
|
||||||
|
input=json.dumps(body) if body is not None else None,
|
||||||
|
capture_output=True, text=True, timeout=20, check=True)
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
|
||||||
|
uid = kubectl(['get', 'ns', 'kube-system', '-o', 'json'])['metadata']['uid']
|
||||||
|
if uid != CLUSTER_UID:
|
||||||
|
raise RuntimeError('wrong cluster')
|
||||||
|
binding = kubectl(['get', 'rolebinding', GROUP, '-n', 'playwright', '-o', 'json'])
|
||||||
|
role = kubectl(['get', 'role', ROLE, '-n', 'playwright', '-o', 'json'])
|
||||||
|
if binding['subjects'] != [{'apiGroup': 'rbac.authorization.k8s.io',
|
||||||
|
'kind': 'Group', 'name': GROUP}]:
|
||||||
|
raise RuntimeError('consumer binding subjects differ')
|
||||||
|
if binding['roleRef'] != {'apiGroup': 'rbac.authorization.k8s.io',
|
||||||
|
'kind': 'Role', 'name': ROLE}:
|
||||||
|
raise RuntimeError('consumer binding role differs')
|
||||||
|
expected = [
|
||||||
|
{'apiGroups': [''], 'resources': ['pods'], 'verbs': ['get', 'list']},
|
||||||
|
{'apiGroups': [''], 'resources': ['pods/portforward'], 'verbs': ['create']},
|
||||||
|
{'apiGroups': ['apps'], 'resources': ['deployments'],
|
||||||
|
'resourceNames': ['playwright'], 'verbs': ['get']},
|
||||||
|
]
|
||||||
|
if role['rules'] != expected:
|
||||||
|
raise RuntimeError('consumer role rules differ')
|
||||||
|
cases = [
|
||||||
|
(True, 'get', 'pods', '', '', 'playwright', '', True),
|
||||||
|
(True, 'list', 'pods', '', '', 'playwright', '', True),
|
||||||
|
(True, 'create', 'pods', 'portforward', '', 'playwright', '', True),
|
||||||
|
(True, 'get', 'deployments', '', 'apps', 'playwright', 'playwright', True),
|
||||||
|
(True, 'get', 'deployments', '', 'apps', 'playwright', 'other', False),
|
||||||
|
(True, 'get', 'secrets', '', '', 'playwright', '', False),
|
||||||
|
(True, 'create', 'pods', 'exec', '', 'playwright', '', False),
|
||||||
|
(True, 'create', 'pods', '', '', 'playwright', '', False),
|
||||||
|
(True, 'patch', 'deployments', '', 'apps', 'playwright', 'playwright', False),
|
||||||
|
(True, 'create', 'pods', 'portforward', '', 'default', '', False),
|
||||||
|
(True, 'create', 'rolebindings', '', 'rbac.authorization.k8s.io', 'playwright', '', False),
|
||||||
|
(False, 'list', 'pods', '', '', 'playwright', '', False),
|
||||||
|
(False, 'create', 'pods', 'portforward', '', 'playwright', '', False),
|
||||||
|
]
|
||||||
|
checks = []
|
||||||
|
for member, verb, resource, subresource, group, namespace, name, expected_allowed in cases:
|
||||||
|
attributes = dict(verb=verb, resource=resource, subresource=subresource,
|
||||||
|
group=group, namespace=namespace, name=name)
|
||||||
|
args = ['--as=rpf-playwright-rbac-probe', '--as-group=system:authenticated']
|
||||||
|
if member:
|
||||||
|
args.append('--as-group=' + GROUP)
|
||||||
|
# Raw review endpoint avoids kubectl's unrelated CRD-discovery permission.
|
||||||
|
review = kubectl([*args, 'create', '--raw',
|
||||||
|
'/apis/authorization.k8s.io/v1/selfsubjectaccessreviews',
|
||||||
|
'-f', '-'], {
|
||||||
|
'apiVersion': 'authorization.k8s.io/v1', 'kind': 'SelfSubjectAccessReview',
|
||||||
|
'spec': {'resourceAttributes': attributes}})
|
||||||
|
status = review['status']
|
||||||
|
if status.get('evaluationError') or type(status.get('allowed')) is not bool:
|
||||||
|
raise RuntimeError('authorization review incomplete')
|
||||||
|
checks.append(dict(member=member, attributes=attributes,
|
||||||
|
expected=expected_allowed, allowed=status['allowed'],
|
||||||
|
passed=status['allowed'] == expected_allowed))
|
||||||
|
return dict(schema='platform-playwright-rbac/v1',
|
||||||
|
observed_at=datetime.now(timezone.utc).isoformat(), cluster_uid=uid,
|
||||||
|
role_uid=role['metadata']['uid'], binding_uid=binding['metadata']['uid'],
|
||||||
|
group=GROUP, checks=checks, passed=all(c['passed'] for c in checks),
|
||||||
|
actual_consumer_authentication_proven=False)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('--target', default='railiance01', choices=['railiance01'])
|
||||||
|
parser.add_argument('--output', required=True, type=Path)
|
||||||
|
args = parser.parse_args()
|
||||||
|
result = verify(args.target)
|
||||||
|
args.output.write_text(json.dumps(result, indent=2) + '\n')
|
||||||
|
print(json.dumps({'passed': result['passed'], 'checks': len(result['checks']),
|
||||||
|
'evidence': str(args.output)}))
|
||||||
|
raise SystemExit(0 if result['passed'] else 1)
|
||||||
|
|
@ -1,25 +1,27 @@
|
||||||
# Current platform work
|
# Current platform work
|
||||||
|
|
||||||
Reviewed September 27, 2026. Eight workplans remain blocked with 23 waiting
|
Reviewed October 13, 2026 against source workplans and the live inbox. Source
|
||||||
tasks. No active, ready or proposed source workplan remains. Completed work
|
files remain authoritative; the generated brief contains historical aliases.
|
||||||
retains its IDs and managed UUIDs, including plans under `archived/`.
|
Completed plans retain their IDs and managed UUIDs, including archived plans.
|
||||||
|
|
||||||
| Workplan | Remaining tasks | Next dependency |
|
| Workplan | Open tasks | Next work or dependency |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [RPF-WP-0015](RPF-WP-0015-audit-core-custody-and-recovery-coordination.md) | T02/T03 | Fresh recovery windows, synthetic sender/abort owner and snapshot/quorum/access evidence |
|
| [RPF-WP-0015](RPF-WP-0015-audit-core-custody-and-recovery-coordination.md) (active) | T02, T03 | Recovery windows, sender/abort owner and snapshot/quorum/access evidence |
|
||||||
| [RPF-WP-0027](RPF-WP-0027-keycape-live-secret-exposure-recovery.md) | T03/T06 | Complete historical resolver custody/routing contract; T05 closed from September 23 operator disposition and owner receipt |
|
| [RPF-WP-0027](RPF-WP-0027-keycape-live-secret-exposure-recovery.md) (blocked) | T03, T06 | Resolver and custody owner contracts |
|
||||||
| [RPF-WP-0035](RPF-WP-0035-credential-lane-implementation.md) | T02/T03/T06/T07/T08 | Exact service registration/custody, human memo acceptance, reader/disablement returns, governed npm migration and formerly-valid audit-bearer revocation proof |
|
| [RPF-WP-0035](RPF-WP-0035-credential-lane-implementation.md) (blocked) | T02, T03, T07, T08, T10, T12 | Execution integration and owner acceptance; verified-source compiler correction tested October 13 |
|
||||||
| [RPF-WP-0036](RPF-WP-0036-platform-service-assurance.md) | T03/T04/T06 | Current recovery/cadence/custody evidence, Q2 production delivery and owner/projection acceptance; local archive adapter implemented |
|
| [RPF-WP-0036](RPF-WP-0036-platform-service-assurance.md) (blocked) | T03, T04, T06 | Bounded scheduler, telemetry receiving contract and ownership returns |
|
||||||
| [RPF-WP-0038](RPF-WP-0038-forgejo-scaleway-primary-coverage.md) | T04 | Durable scheduled caller, canonical verified inventory and quota/retention gates; September 15 cutover/expiration hold persists |
|
| [RPF-WP-0038](RPF-WP-0038-forgejo-scaleway-primary-coverage.md) (blocked) | T04 | Durable caller, verified inventory and quota/retention; expiration/cutover hold persists |
|
||||||
| [RPF-WP-0043](RPF-WP-0043-policy-nexus-argocd-onboarding.md) | T02/T03/T04 | Cross-owner chart/values agreement, committed values and source access, zero-diff proof and adoption |
|
| [RPF-WP-0043](RPF-WP-0043-policy-nexus-argocd-onboarding.md) (blocked) | T03, T04 | Owner values/render diff, then root automation before adoption |
|
||||||
| [RPF-WP-0044](RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md) | T03–T08 | Per-app promotion gates, issue-core credentials/ownership, target-revenue hook acceptance, ESO adoption/observation and readable old-controller inventory |
|
| [RPF-WP-0044](RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md) (blocked) | T04, T06, T07 | Attended issue-core issuer login, ordered ESO adoption and root automation |
|
||||||
| [RPF-WP-0048](RPF-WP-0048-activity-core-gitops-adoption.md) | T02 | Healthy observation through September 28 at 16:06:22 Berlin plus bounded authenticated release broker/admission and rollback proof |
|
| [RPF-WP-0048](RPF-WP-0048-activity-core-gitops-adoption.md) (blocked) | T02 | Activity-core promotion evidence |
|
||||||
|
| [RPF-WP-0053](RPF-WP-0053-coulomb-paired-backup-admission.md) (proposed) | T01, T02, T03, T04, T05 | Paired archive execution/custody, retrieval/recovery and monitoring admission |
|
||||||
|
| [RPF-WP-0055](RPF-WP-0055-keycape-client-secret-rotation-residual.md) (backlog) | T01 | Unpromoted rotation residual; do not implement without demand/risk promotion |
|
||||||
|
| [RPF-WP-0056](RPF-WP-0056-playwright-consumer-admission.md) (blocked) | T03 | Dedicated Playwright consumer group, managed pilot and authenticated identity route |
|
||||||
|
|
||||||
Latest [review and evidence](../history/2026-09-27-loose-end-review.md).
|
October 13 review corrected WP-0038-T04's stale `todo` state to the documented
|
||||||
No new task or workplan was created. Existing completed credential reviews,
|
`wait`. RPF-IN-0012 remains an open independent execution/wrapped-delivery review;
|
||||||
delivery, retention projection and rotations are not reopened by these waits.
|
the compiler fix does not close it. Playwright publication is resolved; its new
|
||||||
|
Platform workplan records the user-requested group and actual activation evidence.
|
||||||
|
|
||||||
Source files are authoritative. The generated brief still contains retired
|
Routine synchronization uses the exact-commit Repo Manager receipt described in
|
||||||
aliases and stale statuses; do not recreate work from it. Routine synchronization
|
AGENTS.md. Legacy alias repair remains the scoped WP-0036-T06 dependency.
|
||||||
uses the exact-commit Repo Manager receipt described in AGENTS.md. Legacy alias
|
|
||||||
repair remains the scoped owner dependency in WP-0036-T06.
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ status: blocked
|
||||||
flavor: implementation
|
flavor: implementation
|
||||||
owner: codex
|
owner: codex
|
||||||
created: "2026-09-06"
|
created: "2026-09-06"
|
||||||
updated: "2026-10-03"
|
updated: "2026-10-13"
|
||||||
state_hub_workstream_id: "7beec1a7-aa82-5a36-9a66-6b60008a2455"
|
state_hub_workstream_id: "7beec1a7-aa82-5a36-9a66-6b60008a2455"
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -72,7 +72,8 @@ removed. Evidence: `docs/evidence/forgejo-scaleway-restore-2026-09-06.json`.
|
||||||
|
|
||||||
```task
|
```task
|
||||||
id: RPF-WP-0038-T04
|
id: RPF-WP-0038-T04
|
||||||
status: todo
|
status: wait
|
||||||
|
blocking_reason: "Durable scheduled caller, verified inventory and quota/retention gates remain open; September 15 prohibits expiration and scheduled secondary cutover."
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "a4807df0-ec96-58f1-9cbd-42b1dcde0d6f"
|
state_hub_task_id: "a4807df0-ec96-58f1-9cbd-42b1dcde0d6f"
|
||||||
```
|
```
|
||||||
|
|
|
||||||
122
workplans/RPF-WP-0056-playwright-consumer-admission.md
Normal file
122
workplans/RPF-WP-0056-playwright-consumer-admission.md
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
---
|
||||||
|
id: RPF-WP-0056
|
||||||
|
type: workplan
|
||||||
|
title: "Admit the Playwright pilot and establish scoped consumer group access"
|
||||||
|
domain: financials
|
||||||
|
repo: railiance-platform
|
||||||
|
status: blocked
|
||||||
|
owner: codex
|
||||||
|
topic_slug: railiance
|
||||||
|
created: "2026-10-13"
|
||||||
|
updated: "2026-10-13"
|
||||||
|
---
|
||||||
|
|
||||||
|
Incoming owner request: State Hub c82d75f3-3191-410d-a8c8-fd647bf7f3ef,
|
||||||
|
superseding publication return a282c300-eaef-4cd6-99b0-f4fb255203b3;
|
||||||
|
consumer RAPP-PLAYWRIGHT-WP-0004-T01. The user selected establishing a group
|
||||||
|
in this session. Platform owns lifecycle admission; implementation remains in
|
||||||
|
rapp-playwright. Publication is complete, and must not remain a blocker.
|
||||||
|
|
||||||
|
## Review the immutable package and pilot boundary
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: RPF-WP-0056-T01
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
Reviewed rapp-playwright revision 70268154c06cf78c5d9e1f4eb900213ffd436d1b:
|
||||||
|
declaration, release, workload, admission and operations contract. The published
|
||||||
|
image is sha256:8d6fd5a8172cf906bb503642ed620761945c5138b86f6396c36f65cbe6def441.
|
||||||
|
Three provider contract/network/proxy tests pass independently in this session.
|
||||||
|
One Recreate replica requests 100m CPU/256Mi memory, limits 1 CPU/1Gi, and uses
|
||||||
|
a 2Gi transient artifact PVC with one-hour retention. Non-root, read-only root,
|
||||||
|
no service-account token, dropped capabilities, loopback listener, denied ingress
|
||||||
|
and public HTTPS/DNS egress match the proposed trusted-target pilot.
|
||||||
|
Chromium's OS sandbox is disabled; this is no hostile-page or cross-tenant
|
||||||
|
isolation acceptance. Initial targets remain the bundled fixture and public
|
||||||
|
https://onco.cc; no private preview, source import or data-license grant follows.
|
||||||
|
|
||||||
|
## Establish and verify the consumer group RBAC boundary
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: RPF-WP-0056-T02
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
User requested a group; use exact Kubernetes group `playwright-consumers`.
|
||||||
|
Platform binding: helm/playwright-consumer-access.yaml, referring to the package's
|
||||||
|
existing namespace Role `playwright-consumer`. Bootstrap only its reviewed
|
||||||
|
Namespace and Role, then bind the group. No cluster-wide role, Secret access,
|
||||||
|
pod execution, workload mutation, credential issuance or group membership grant.
|
||||||
|
Verify live allowed discovery/port-forward and denied execution/Secrets/foreign
|
||||||
|
namespace/workload changes, plus nonmember denial. Impersonated authorization
|
||||||
|
checks prove RBAC only, not actual consumer authentication or connectivity.
|
||||||
|
|
||||||
|
## Connect platform identities and prove managed consumer operation
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: RPF-WP-0056-T03
|
||||||
|
status: wait
|
||||||
|
priority: high
|
||||||
|
blocked_on: message-from:railiance-cluster
|
||||||
|
blocking_reason: "User admitted all identified platform humans and coding agents; their supported Kubernetes authentication/group-mapping route remains unimplemented."
|
||||||
|
```
|
||||||
|
|
||||||
|
The session's initial readback found only built-in/system user/group bindings;
|
||||||
|
the cluster documentation describes an administrator kubeconfig. A group subject
|
||||||
|
in RBAC does not create an identity-provider group or convey membership. The user admitted all identified platform humans and coding agents; establish
|
||||||
|
their existing-owner authentication and group-mapping route,
|
||||||
|
including expiration/revocation. Do not distribute the admin kubeconfig or infer
|
||||||
|
that a KeyCape group is already understood by the Kubernetes API.
|
||||||
|
|
||||||
|
The immutable pilot is now deployed after fresh capacity, server dry-run and
|
||||||
|
diff: 1/1 Ready, 2Gi PVC Bound and matching imageID. A real group-identity trial
|
||||||
|
is still required; administrator impersonation is recorded separately.
|
||||||
|
Retain screenshots/keyboard receipts, wrong-token/assertion/target negatives,
|
||||||
|
cancellation and restart/interrupted/completed-artifact recovery. One available
|
||||||
|
release supports same-image recovery only; cross-version rollback stays unproven.
|
||||||
|
Keep RAPP-PLAYWRIGHT-WP-0004-T01 open until its owner accepts those receipts.
|
||||||
|
|
||||||
|
|
||||||
|
## October 13 native implementation
|
||||||
|
|
||||||
|
ADR-0006 records the group decision. Namespace, package Role and Platform binding
|
||||||
|
are applied on the pinned railiance01 cluster. Thirteen native authorization
|
||||||
|
checks pass: intended discovery/forwarding is allowed; Secrets, exec, writes,
|
||||||
|
foreign namespaces, foreign deployment and nonmember access are denied. The
|
||||||
|
initial verifier's kubectl schema discovery needed unrelated CRD access; using
|
||||||
|
the native SelfSubjectAccessReview endpoint corrected the verifier without any
|
||||||
|
permission expansion. Re-run scripts/verify_playwright_access.py with --output.
|
||||||
|
|
||||||
|
Fresh capacity before deployment: 3460m/4000m CPU requested, 9472Mi memory
|
||||||
|
requested and 126Gi free storage. Adding 100m/256Mi plus a 2Gi PVC fits that
|
||||||
|
scheduling headroom; aggregate CPU/memory limits were already overcommitted.
|
||||||
|
The declared single-browser limits remain in force. Full package server dry-run
|
||||||
|
and diff passed and the published immutable image reached Ready.
|
||||||
|
|
||||||
|
Initial fixture trial through administrator-impersonated group port-forward
|
||||||
|
passed desktop/narrow keyboard and screenshot checks. This demonstrates native
|
||||||
|
RBAC and browser operation; it does not turn the administrative SSH identity
|
||||||
|
into a generally available consumer authentication route. T03 retains that gap.
|
||||||
|
|
||||||
|
## Activate the bounded pilot and verify operator-driven recovery
|
||||||
|
|
||||||
|
```task
|
||||||
|
id: RPF-WP-0056-T04
|
||||||
|
status: done
|
||||||
|
priority: high
|
||||||
|
```
|
||||||
|
|
||||||
|
The published package is running. Thirteen RBAC checks and six native negative/
|
||||||
|
health checks pass, including wrong receipt/artifact token, deliberate assertion
|
||||||
|
failure, bounded cancellation and private-target refusal. Actual Deployment
|
||||||
|
restart reached Ready with a new pod UID, the same immutable image and the same
|
||||||
|
PVC; all four completed artifacts were retrieved and their hashes matched.
|
||||||
|
Evidence: docs/evidence/2026-10-13-playwright-managed/ and
|
||||||
|
docs/evidence/2026-10-13-playwright-rbac.json. This is same-image recovery, not
|
||||||
|
cross-version rollback or abrupt-interruption proof. T03 remains open for actual
|
||||||
|
consumer identity/group mapping and the remaining package-owner acceptance.
|
||||||
|
|
||||||
|
Group decision mirrored to State Hub d2426028-0b04-4ea2-b199-d7f9e19e38e6.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue