2026-10-10 12:29:32 +02:00
---
id: KEY-WP-0039
type: workplan
title: "Negative-check tokens for the secrets-engine OpenBao JWT role"
domain: infotech
repo: key-cape
2026-10-10 13:18:24 +02:00
status: active
2026-10-10 12:29:32 +02:00
flavor: implementation
owner: claude-code
topic_slug: netkingdom
created: "2026-10-10"
2026-10-17 04:33:43 +02:00
updated: "2026-10-17"
2026-10-10 12:29:32 +02:00
depends_on: []
related_repos:
- railiance-platform
- secrets-engine
2026-10-10 12:30:17 +02:00
state_hub_workstream_id: "09c3bddf-6058-5603-8488-cccdb7be4f86"
2026-10-10 12:29:32 +02:00
---
# KEY-WP-0039 - Negative-check tokens for the secrets-engine OpenBao JWT role
## Why
CCR-2026-0038 (railiance-platform RPF-WP-0035-T02) requires the OpenBao role
`secrets-engine-openbao` on `auth/keycape-services` to refuse JWTs with a wrong
`aud` , `sub` , `tenant` , `principal_type` , `roles` or `scope` , a coding-agent JWT
and an expired JWT. The positive login proof passed on 2026-10-10 (secrets-engine
`docs/evidence/2026-10-10-keycape-openbao-probe.json` ). railiance-platform asked
whether KeyCape can issue the negative tokens without touching the
`secrets-engine` registration.
KeyCape signs only what a registration declares. It has no way to mint a token
with arbitrary claims, and adding one would create a forging path in the issuer.
So the negative tokens must come from real, separate registrations that differ
from `secrets-engine` in exactly one property each.
## Boundaries
- The `secrets-engine` registration is not changed.
- Probe clients are confidential `client_credentials` clients with the minimum
60-second lifetime, scopes that grant nothing, and secrets minted into custody
like any other client. They are removed after the proof.
- The probe script prints only accept or refuse booleans per case, never tokens or
secrets. It runs attended.
2026-10-14 18:29:33 +02:00
## T01 — Define the probe registrations
2026-10-10 12:29:32 +02:00
```task
id: KEY-WP-0039-T01
2026-10-10 13:18:24 +02:00
status: done
2026-10-10 12:29:32 +02:00
priority: medium
2026-10-10 12:30:17 +02:00
state_hub_task_id: "4d06b059-3768-53bb-83a4-a9a71c0850b8"
2026-10-10 12:29:32 +02:00
```
Write a non-secret request packet under `docs/` with one probe client per claim
mismatch, each identical to `secrets-engine` except for:
- `aud` : a different access-token resource audience
- `sub` : a different service subject
- `tenant` : a tenant other than `platform`
- `roles` : a role other than `secrets-engine`
- `scope` : a scope outside the role's bound scope
Two cases need no probe client. A service token always carries
`principal_type: service` (`src/internal/server/oidc/token.go` ), so the wrong
`principal_type` case uses a human access token from an attended login. The
coding-agent case uses the existing `codex-railiance-platform` registration (role
`coding-agent` , `docs/openbao-service-auth-contract.md` ) if it is registered live;
T01 confirms that.
The expired-JWT case reuses any probe client: request a token, wait past its
60-second lifetime, then present it.
Acceptance: railiance-platform agrees the packet covers every refusal that
CCR-2026-0038 names.
2026-10-10 13:18:24 +02:00
2026-10-10: railiance-platform agreed that the case list covers every
CCR-2026-0038 claim negative. The remaining CCR checks (capabilities-self deny, no
provider fallback) are theirs and secrets-engine's. Packet written at
`docs/openbao-negative-probe-clients.yaml` . It departs from the agreed list in two
ways, both sent back for re-agreement:
- **Expired case.** A token from another probe already fails a claim, so its
refusal does not show that expiry was checked. It needs a sixth client,
`openbao-probe-expiry` , identical to `secrets-engine-openbao` in every claim. That
makes it a second credential able to log in as secrets-engine for the session.
OpenBao's `expiration_leeway` (150s by default) also extends the wait.
- **Audience pin.** A service token's `aud` is its `clientId` unless `audience` is
set. Every probe except the aud probe therefore pins
`audience: secrets-engine-openbao` , so it fails only on its own claim.
Condition (a), no OpenBao custody, holds. The values still have to reach KeyCape's
environment, because KeyCape resolves `secretRef` at startup. The packet uses a
transient Kubernetes Secret that is deleted in the same session.
2026-10-14 18:29:33 +02:00
## T02 — Register the probe clients, run the attended probe, then remove them
2026-10-10 12:29:32 +02:00
```task
id: KEY-WP-0039-T02
2026-10-14 18:29:33 +02:00
status: wait
depends_on: [KEY-WP-0039-T01, KEY-WP-0038-T02, KEY-WP-0038-T03]
2026-10-17 13:39:02 +02:00
blocking_reason: "Ordered identity gate: Forgejo first SecurityCase registration/claims proof, then NetKingdom registry session and attended human/coding-agent custody; original secrets-engine-openbao registration go remains resolved; probe/coding-client custody and attended readiness are not established."
2026-10-10 12:29:32 +02:00
priority: medium
2026-10-10 12:30:17 +02:00
state_hub_task_id: "03da4c38-1dac-53b1-8b0b-e697df48e9d3"
2026-10-10 12:29:32 +02:00
```
2026-10-11 20:47:54 +02:00
2026-10-11: requalified — live registration go caafe4be was already resolved; owner authorization present. See the-custodian docs/decisions/2026-10-11-security-unblock-decisions.md.
2026-10-10 13:18:24 +02:00
Write the attended script, which prints booleans only.
2026-10-10: script written at `scripts/openbao_negative_probe.py` , with tests in
`scripts/test_openbao_negative_probe.py` . It meets condition (b): one refused
boolean per case plus the refusal class (`claim_mismatch` , `expired` ,
`not_service_principal` ), and no token, secret, claim value or OpenBao error text.
A transport failure or an unexpected response is reported as `inconclusive` , never
as a refusal. A token that OpenBao accepts is revoked at once and fails the run.
Still waiting: railiance-platform's re-agreement on the two departures above, and
an attended registry session with net-kingdom. Register the clients
2026-10-10 12:29:32 +02:00
through the normal registration path, hand the run to railiance-platform, record
a value-free receipt in `docs/evidence/` , and deregister the clients afterwards.
Acceptance: every case is refused, the receipt is committed, and the probe clients
are gone.
2026-10-11 02:21:03 +02:00
2026-10-11 source preparation: T01 remains progress because the exact expiry
client and audience-pin amendments require platform-owner re-agreement; the
prior agreement covered the earlier case list, not this revised packet. The
prepared runner revision adds a valid expiry positive control and immediate
revoke, exact decoded claim-isolation preflight (not signature evidence),
semantic refusal classes, bounded expiry TTL and redirect refusal. Seventeen
local tests pass; original-source semantic regressions demonstrate two false
successes. See `docs/openbao-negative-probe-session-proposal.md` for exact owner
returns, live authority, effective leeway, custody boundaries and cleanup. No
live token, registry or OpenBao action occurred. T02 continues to wait for owner
re-agreement plus separate attended live authorization. MASON-WP-0009-T05
operator/ESO capability and nonmember checks remain independent acceptance.
2026-10-11: Platform independently re-agreed the final amended design (session proposal SHA25623f13d2a5a4204f749f35c5d44ef39d213838cd2fce1c36fb4775254ef1c7f09). Original conditional review and narrow confirmation are retained in railiance-platform/docs/reviews/2026-10-11-keycape-openbao-negative-session-owner-review*. Source acceptance T01 is complete; actual registry/leeway/readiness, founder live go, negative/cleanup and separate capability/no-fallback obligations remain T02 and owner plans.
2026-10-11 15:33:14 +02:00
2026-10-17 13:27:15 +02:00
2026-10-17 Custodian coordinator finalization review (not a KeyCape formal owner
acknowledgment): the [infrastructure assessment ](../../the-custodian/docs/changes/netkingdom-target-2026-10-17/key39-infra-finalization-r1/ASSESSMENT.md )
confirms all 14 executable/test/producer-decision pins and three Platform source
pins still match. Source reviews remain complete: T01/T03 done, T02 wait. Existing
2026-10-17 13:36:07 +02:00
source acceptance remains valid. Resolved registration go caafe4be covers only
the original secrets-engine-openbao client (KEY-WP-0037-T03, deployed 6f79a2af,
NK-WP-0046 exact-match helper); it does not authorize new probe clients or
coding-client custody, and no renewed original-client approval is requested.
The standing attended rule remains separate, for reviewed commands within
existing scope; no new protocol or blanket approval request is introduced. The
2026-10-17 13:27:15 +02:00
remaining sequence is KEY-WP-0038-T02/T03 first-case registration/claims proof,
admission of the existing coding-client proposal with sanitized owner readiness
returns, then one attended negative/revoke/cleanup receipt committed with probe
clients removed. No native acceptance or credential/registration action is
inferred from this coordinator review.
2026-10-11 15:33:14 +02:00
## KeyCape issuer-source compatibility inspection for lifecycle v2
```task
id: KEY-WP-0039-T03
status: done
priority: medium
2026-10-11 18:31:04 +02:00
state_hub_task_id: "54d37ad8-2352-51c2-bb2e-af6070dbbd73"
2026-10-11 15:33:14 +02:00
```
2026-10-11: Completed KeyCape's own issuer-source inspection for
KEY-WP-0039-T02/attended-lifecycle-v2, exact manifest SHA256
6fc0fe47f99a97c11c6e7538f5ea02054335df7d46055d3f84bed4e194aeaaed.
Read AGENTS.md, governing INTENT.md, current client-credentials claim source,
registration fragments, native caller-authentication commands and frozen v2
issuer transport/probe wiring. Seventeen unchanged runner tests pass locally.
This task completes only issuer-source inspection; the resulting narrow
source acknowledgment is in docs/reviews/2026-10-11-key39-lifecycle-v2-keycape-source-ack.json (retained frozen prior acknowledgment).
T01 stays done and T02 stays open for actual native registration, token input,
refusal and cleanup proof. No Secret, token, credential or native environment was accessed; no owner
checkout was changed during this source inspection. Owner source files were
read for the bounded issuer compatibility check.
Current token.go:306-309 returns HTTP 401 invalid_profile_usage with
feature=client_id for a removed confidential client; wrong-secret
feature=Authorization cannot count as removed-registration evidence. The
proposal and packet comments are narrowly corrected against that current
issuer contract. Prior T01/source re-agreement history is preserved; this source
acknowledgment supplies no NetKingdom runtime-owner review or founder live go.
The private token-producer handoff remains a real execution gap under T02.
Existing keycape login/service-token commands require a new private output
file; login also needs a concrete admitted public PKCE client/callback and
attended browser/MFA. The lifecycle expects an in-memory private stdin object
containing human_token and coding_agent_token, but no reviewed file-to-process
or process-to-process producer, admitted human client/callback, custody-injected
coding-agent source, native placement or producer cleanup receipt has been
provided. No unattended token producer or admitted secret route is invented.
Resolve those exact owner contracts before founder native approval; existing
static registration is not live token custody or producer admission.
2026-10-11 same T03 source-inspection refinement for lifecycle V4: completed
KeyCape issuer-facing inspection before the new formal acknowledgment in
docs/reviews/2026-10-11-key39-lifecycle-v4-keycape-source-ack.json. Exact V4
manifest SHA256 d079f85c47d5c2635e1ee633ea4d1346b1737ce2be9ca273f22a38e620f418d8,
executor b4687c2d07819c43b45d0cddcad0488b62eb49175b2a06a43f7806a0838d3a4d.
NetKingdom's independent V4 source review is approved, receipt SHA256
4f4498203a31bd46dbc3715c0df1cbb9eee63bed5b2c1baf430ff3c4a37c13cb.
The V2/V3 unsuccessful reviews and earlier KeyCape acknowledgment remain
retained as one correction trial; they are not extra scored successes.
V4 retains the unchanged issuer runner and six-client claim design, and fixes
finite/nonboolean windows, true total request deadlines, late-known OpenBao
session private revoke/refusal and guarded bounded final Secret deletion.
The issuer-facing acknowledgement covers only stopping late token exchanges,
claim source/shape and preserving token cleanup failure/unknown outcomes; it
does not replace NetKingdom runtime or Platform backend acceptance. Tests: 41
supplied lifecycle, 17 unchanged runner and 17 independent owner checks pass
locally. No native tokens, credentials, issuer mutations or live cleanup were
performed. T01 stays done; T02 stays open and the genuine private token-producer
handoff remains its next source prerequisite before actual founder native go.
2026-10-11 same T03 source-inspection refinement for lifecycle V5: completed
KeyCape's own current issuer-source/claim/cleanup-contract inspection before
any new formal acknowledgment. Current token.go:306-309 still distinguishes
removed-client invalid_profile_usage feature=client_id from wrong-secret
feature=Authorization. The six-client design, audience source and expiry
positive control remain unchanged, and the original runner's 17 tests pass.
Exact V5 manifest SHA256
d1f997624db46693a7126a6eb6435f6b3a353d5bd67dcc8a539683e4b7147285;
executor 3bcceebc845b17492040c76223d77088257c547a2b890198e7b5c2b04a0cd360.
V5 has 46 passing supplied lifecycle checks. It adds a single exceptional
response-close abort under a fixed20ms cap clipped to nonresettable aggregate
cleanup, and to positive original request time remaining, with expired aggregate
zero calls, fixed private errors and truthful known-session revoke/unknown
outcomes. This inspection covers issuer-facing token lifetime and claim
interfaces only; NetKingdom and Platform independently own their runtime and
backend review decisions. Previous V2/V3 Net source refusals and Platform V4
exceptional-close refusal remain retained; KeyCape's V2/V4 acknowledgments are
historical narrow source inspections, never aggregate native approval.
T01 remains done, T02 open. No native actions or credentials occurred. The real
private token-producer/client/callback/coding-agent custody/cleanup handoff gap
stays the next prerequisite; no unattended admission is inferred.
Exact independent V5 source decisions were then verified: NetKingdom approved
receipt SHA256 32a62bd1ca1bd7311965d016d4d6a6e4d9177f3423c63add436d9d309865eacc
(46 supplied +17 runner +21 independent checks); Platform approved receipt
SHA256 ba872dc53061b1dcca9dea1e8897597c394c1f9365e0fc49ee6f2095f57f11e0
(46 supplied +5 independent +17 previously verified runner checks). Those are
foreign owners' own source decisions, not KeyCape runtime/backend reviews or
founder native authority. Formal KeyCape bounded issuer acknowledgment follows
in docs/reviews/2026-10-11-key39-lifecycle-v5-keycape-source-ack.json.
2026-10-11 18:31:04 +02:00
2026-10-11 T02 continuing source preparation: private producer decision packet
`KEY-WP-0039-T02/private-producer-handoff-v1` stages supported existing CLI
flows, selected existing netkingdom-bootstrap-console literal-loopback human
client subject to owner purpose/MFA/listener admission, and the existing
codex-railiance-platform source identity subject to actual live/custody/consumer
admission. No existing coding-agent delivery receipt was found; AppRole tokens
do not substitute for issuer JWTs. A bounded pipe-only adapter for the current
CLI's two caller-owned private files has 18 passing synthetic checks, with
identity-guarded explicit file consumption and fixed value-free failure output.
Decoded claim shape does not prove signatures or authenticated admission.
See docs/openbao-negative-token-producer-decision.md and .json for exact owner
choices and missing receipts. The exact trusted workstation-to-node launcher,
private-file allowance and railiance01 Bao route/public-health guard still need
source review and founder disposition before any token/temporary credential/
mutation/restart. No registration, custody, login, native action or credential
request occurred. V5 and failed review histories retained; T01 stays done and
T02 open. No new work record or native acceptance is inferred.
2026-10-11 same T02 source-preparation correction for
KEY-WP-0039-T02/private-producer-handoff-v2: NetKingdom's exact V1 consumer
refusal remains recorded (no child-ready gate, stdio alias, non-atomic unlink).
V2 has source-pinned private launch/ready handshake compatible with exact
Net V9 manifest84542ddc: fresh nonce/source/envelope/health/window marker before
ANY caller-token file load/consume/write; separate local data/control pipes
reject kernel identity aliases of stdin/stdout/stderr. Adapter read/write budget
only clips downward after readiness. 31 distinct producer/launcher synthetic
checks and 74 compatible consumer supplied checks pass. No SSH/native/login or
credential access was performed. Stat/unlink remains non-atomic and requires
continuously exclusive sameUID custody; the retained race test is a custody
violation counterexample, not a claim of repaired filesystem atomicity. Receipt
keeps atomic delete/copy cleanup unverified and possible copies true. Exact
trusted launcher/directSSH profile/private tmpfs allowance, selected human
client/MFA purpose reuse and coding-agent registration/custody/delivery remain
unadmitted owner choices. Native node route, role/leeway/window/founder decision
and actual negative/cleanup acceptance remain pending. T01done and T02open; no
new task or plan, and V1/V5-V8/current failure histories are not overwritten.
2026-10-11 same T02 producer-preparation correction V3: Platform V2 pair
source refusal RPF-KEY39-PAIR-V2-F01 is retained. Private write uncertainty
now propagates into sticky remote consumer uncertainty before launcher early
return; local SSH termination never proves remote no-effects/recovery. Actual
full-payload then interrupted confirmation and4096-byte partialpipe failures
are retained regressions. 33 distinct source checks pass. Exact Net V9 source
bytes unchanged; new source reviews required, not implicit repin. Native
client/MFA/coding-agent custody/transport/tmpfsfile and actualroute/session
authority remain unadmitted. T01done/T02open; no new task/plan or native action.
2026-10-11 same T02 producer-preparation V4: exact V3 Net consumer refusal
NET-PRODUCER-V3-F01 retained. Actual CLI contract acquisition now bounded
nofollow/nonblocking regular stable reads and one ORIGINAL5-second preparation
budget across contract/source/envelope/SSHspawn/ready/file/delivery phases, not
a renewed launcher allowance. 40 own source tests plus9 retained paired
wrapper/child handshake regressions pass with synthetic/no native transport.
V3stickyremoteunknown/full+partialdelivery regressions retained; Net V9 exact
bytes unchanged. Prior issuer/custody/transport/file/route/readiness-Argo/role/
maintenanceexception/founder choices remain unadmitted. No SSH/network/Secrets/
credentials/native/owner checkout changes; no task/plan duplication. T01done
and T02open; source correction is not native acceptance.
2026-10-11 19:35:51 +02:00
2026-10-11 T02 source-design disposition checkpoint: founder accepted exact
source memo `infd-20261011-key39-source-design-r1` , review
`review-62626f54-0212-4684-9b45-0a7222d61957` version1 at `2026-10-11T17:19:01Z` .
Disposition `disp-870f9c1b-0444-4216-ae7f-f5463d590e36` , approval
`ca118afc-d746-4454-a5b9-9b387b120cd9` ; authenticated person subject
`uid=platform-root,ou=people,dc=netkingdom,dc=local` . Exact canonical public review URL:
`https://decisions.coulomb.social/review?memo_id=review-62626f54-0212-4684-9b45-0a7222d61957` .
Root's authenticated confirmed readback is
`the-custodian/docs/evidence/2026-10-10-security-consolidation/key39-source-design-publication/founder-source-disposition-readback-r1.json` ,
SHA256 `453213194d605336e9c424976f1ac27691def39e225026f0a99628d1cfc97d1d` ; observed
`2026-10-11T17:30:47.080081+00:00` . Source commands SHA256
`36e20813596f3ddbb86e01fd0b838867ece2f4916c5880305cf12cd61b567f89` and source inventory SHA256
`aea196db9e513900d5e7165455d6e9c3dc68749a606dc219ec340ac595642cc0` bind the accepted source direction.
Acceptance covers recommended source preparation for existing bootstrap-console
human-client purpose reuse, returning existing coding-agent custody admission or
preparing a narrow owner proposal, proposed founder directSSH source profile,
and conditional exclusive-owner tmpfs files. It does not establish actual
registration/MFA/listener, coding-agent custody/delivery, transport/file admission,
node-local Bao route, issuer/OpenBao role/leeway/maintenance readiness or fresh
attended native go. The published choice documents remain historical exact
pending proposals; this appended receipt records their later source disposition.
T02 remains wait on external owner custody/admission and separate attended
execution authorization. Source acceptance permits further source preparation;
actual registry, token exchange, negative probe, revoke and cleanup remain pending. T01 and T03
remain done. No native or credential action is authorized by this source receipt.
See docs/proposals/2026-10-11-key39-next-execution-prerequisites.json for exact
owner returns and safe metadata evidence needed before preparing a runnable
attended execution proposal.
2026-10-14 18:29:33 +02:00
2026-10-11 ordered-goal qualification (T02 only): the final source runner already
exists and its 17 local semantic tests pass. No new helper or source protocol is
needed to repeat accepted preparation. Native execution follows the first
Forgejo SecurityCase registration and claims proof (KEY-WP-0038-T02/T03);
only those task metadata were checked, not wait-task bodies. NetKingdom owns the
registry/env/restart session, KeyCape owns issuance/isolation, and Platform owns
leeway/refusal/capability/no-fallback/cleanup proof. The live registration go is
already recorded resolved; do not ask again. Attended human authentication and
owner-held existing coding-agent custody go on the single attended checklist.
No credentials, live registry/API changes or KEY-WP-0040 recovery work occurred.
2026-10-17 04:33:43 +02:00
2026-10-17 Platform owner returns (source-prepared, not admitted):
railiance-platform `docs/proposals/2026-10-17-key39-t02-owner-returns.md`
(commit `0a9617a` ). The coding client `codex-railiance-platform` has no
admission, custody or delivery record. The existing narrow proposal
`docs/proposals/2026-10-11-key39-coding-client-custody-proposal.json` (`9460f6f` )
remains the one to admit, so the coding-agent case stays unrunnable until owners
admit it. The role source (`openbao/auth/secrets-engine-jwt-role.json` ) matches
the packet's claim design. It declares no `expiration_leeway` , so the expiry
probe must assume OpenBao's 150s default until an attended sanitized read
confirms the live value. The node-local Bao origin is not declared in source and
also needs that attended read. T02 stays wait.