RCP-WP-0002 finished: publisher identity done, verified on a verdict that states its basis

uptime 36m > lease TTL 30m, 21 samples, zero not-ready, zero query failures,
zero kubelet readiness 503s, no restarts. The verdict now names the uptime it
checked, so the claim can be audited rather than taken.

T05 done upstream in canned-prompts 0.2.0 / migration 0003. DR-3 had already
resolved the identity question as app-local accounts with OIDC demand-gated;
research found that rather than my judgement supplying it.

Left open deliberately: the NetworkPolicy ingress rule still admits any
namespace. Publisher identity now gates writes so it is no longer the only
control, and it should narrow once the legitimate callers are known — recorded
rather than tightened on a guess.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjefh8NUiEiahN4JLwoSKM

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 388925@bnt-lap001
Assistant-Session: 3507023f-e0fd-4a1e-9d90-a0d4217d1502
This commit is contained in:
tegwick 2026-09-08 11:11:55 +02:00
parent bdbef58259
commit 40ac59271a
3 changed files with 58 additions and 13 deletions

View file

@ -4,7 +4,7 @@ rapp_id: rapp-canned-prompts
repo: rapp-canned-prompts repo: rapp-canned-prompts
ownership_repo: canned-prompts ownership_repo: canned-prompts
contract_version: 1.0.0 contract_version: 1.0.0
readiness_state: deployed readiness_state: verified
workload_identity: workload_identity:
name: canned-prompts name: canned-prompts
package_type: manifest-managed-platform-service package_type: manifest-managed-platform-service

View file

@ -1,2 +1,27 @@
started 2026-09-08T10:48:16+02:00 — 22m watch (runtime lease TTL 30m) started 2026-09-08T10:48:16+02:00 — 22m watch (runtime lease TTL 30m)
2026-09-08T10:48:17+02:00 ready=1/1 2026-09-08T10:48:17+02:00 ready=1/1
2026-09-08T10:49:23+02:00 ready=1/1
2026-09-08T10:50:26+02:00 ready=1/1
2026-09-08T10:51:32+02:00 ready=1/1
2026-09-08T10:52:38+02:00 ready=1/1
2026-09-08T10:53:44+02:00 ready=1/1
2026-09-08T10:54:50+02:00 ready=1/1
2026-09-08T10:55:56+02:00 ready=1/1
2026-09-08T10:57:02+02:00 ready=1/1
2026-09-08T10:58:08+02:00 ready=1/1
2026-09-08T10:59:11+02:00 ready=1/1
2026-09-08T11:00:18+02:00 ready=1/1
2026-09-08T11:01:24+02:00 ready=1/1
2026-09-08T11:02:30+02:00 ready=1/1
2026-09-08T11:03:36+02:00 ready=1/1
2026-09-08T11:04:42+02:00 ready=1/1
2026-09-08T11:05:48+02:00 ready=1/1
2026-09-08T11:06:51+02:00 ready=1/1
2026-09-08T11:07:57+02:00 ready=1/1
2026-09-08T11:09:03+02:00 ready=1/1
2026-09-08T11:10:09+02:00 ready=1/1
finished 2026-09-08T11:11:16+02:00
samples=21 not_ready=0 query_failed=0
kubelet readiness 503s in window: 0 (probe every 5s)
pod started 2026-09-08T08:34:32Z, uptime=36m, restarts=0
RESULT: survived — continuously ready, uptime 36m > lease TTL 30m

View file

@ -4,7 +4,7 @@ type: workplan
title: "First deployment of canned-prompts on Railiance" title: "First deployment of canned-prompts on Railiance"
domain: agents domain: agents
repo: rapp-canned-prompts repo: rapp-canned-prompts
status: active status: finished
owner: codex owner: codex
topic_slug: practice topic_slug: practice
created: "2026-09-06" created: "2026-09-06"
@ -171,8 +171,7 @@ kept the file current; the engine held the URL it booted with. Fixed in 0.1.5 by
re-reading the credential for every new connection, with `pool_recycle` inside re-reading the credential for every new connection, with `pool_recycle` inside
the lease TTL. the lease TTL.
`readiness_state` was returned to `deployed`, and is now **`verified`** on `readiness_state` is **`verified`** on evidence: continuously ready across a full lease rotation, zero readiness
evidence: continuously ready across a full lease rotation, zero readiness
failures, no restarts. Log at failures, no restarts. Log at
`docs/evidence/RCP-WP-0002-T04-lease-rotation-2026-09-08.log`. `docs/evidence/RCP-WP-0002-T04-lease-rotation-2026-09-08.log`.
@ -193,7 +192,7 @@ is trusted.
```task ```task
id: RCP-WP-0002-T05 id: RCP-WP-0002-T05
status: wait status: done
priority: medium priority: medium
state_hub_task_id: "1252f3a1-12ce-5bc1-b003-3e8999d03459" state_hub_task_id: "1252f3a1-12ce-5bc1-b003-3e8999d03459"
``` ```
@ -201,12 +200,33 @@ state_hub_task_id: "1252f3a1-12ce-5bc1-b003-3e8999d03459"
Blocked on a decision in `canned-prompts`, recorded here because it is the Blocked on a decision in `canned-prompts`, recorded here because it is the
thing that decides what this deployment is *for*. thing that decides what this deployment is *for*.
Today the service authenticates a single shared bearer token proving "the **Done 2026-09-08**, upstream in `canned-prompts` (image 0.2.0, migration
operator". That is adequate for a private in-cluster registry and inadequate for `0003`).
the collaborative prompting platform the operator described: every token holder
is indistinguishable, so § 20.1 namespace ownership can be enforced against
anonymous callers but not attributed among publishers.
This repo must not paper over that with cluster configuration implying finer The decision was already made and research found it rather than my judgement
control than exists. When identity lands upstream, revisit the publish-token supplying it: **DR-3, resolved 2026-07-10** — app-local accounts, platform OIDC
secret and the NetworkPolicy ingress rule, which currently admits any namespace. demand-gated on client SSO requests, instance consolidation, or local-account
toil across more than two apps. None has fired here and no Keycloak is
deployed, so OIDC was ruled out by fleet decision.
App-local publisher tokens, because a registry is consumed by CLIs and agents:
no browser, no session, and a login surface nothing uses is a liability. The
entire authentication boundary stays in `auth.py`, so contract § 2.3 holds and a
later OIDC switch is bounded.
§ 20.1 namespace ownership is now a real access decision — `owner` names a
publisher. A closed namespace with **no** owner admits nobody, including the
operator, because reading a missing owner as "anyone" would invert the point of
closing it.
**Still open, deliberately:** the NetworkPolicy ingress rule admits any
namespace. Publisher identity now gates *writes*, so this is no longer the only
control, but it should narrow once the set of legitimate callers is known.
Recorded rather than tightened on a guess.
**Reversal on record.** I asked `rapp-postgres` not to issue
`creds/canned-prompts-publish`, then asked for it. Both were right in their
moment: with one indistinguishable identity there was nothing worth
authenticating; with real publishers the operator token becomes the bootstrap
path that mints the first one. Requested as a reversal rather than quietly
asking for the opposite of the earlier argument.