Publish reviewed bounded JWT ready handoff and retained owner history

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
tegwick 2026-10-11 18:31:04 +02:00
parent f60e7419a9
commit 0f47e0c666
13 changed files with 2002 additions and 0 deletions

View file

@ -0,0 +1,82 @@
{
"proposal_id": "KEY-WP-0039-T02/private-producer-handoff-v4",
"status": "owner_choice_required",
"native_authority": false,
"native_readiness": false,
"lifecycle_manifest_sha256": "84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14",
"recommended_human": {
"client_id": "netkingdom-bootstrap-console",
"audience": "netkingdom-bootstrap-console",
"scope": "openid",
"callback": "http://127.0.0.1:8876/oidc/callback",
"existing_client_purpose_reuse_admitted": false,
"fresh_mfa_verified": false
},
"coding_agent": {
"client_id": "codex-railiance-platform",
"audience": "codex-railiance-platform",
"scope": "openbao:login",
"subject": "service:codex:railiance-platform",
"tenant": "tenant:platform",
"secret_env": "KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET",
"live_registration_verified": false,
"existing_custody_admission_receipt": null,
"consumer_delivery_coordinates": null,
"alternative_if_missing": "Platform-owned new narrow admission proposal; do not silently provision"
},
"handoff": {
"adapter": "scripts/openbao_negative_private_handoff.py",
"pipe_fd": 3,
"private_tmpfs_jwt_files_approved": false,
"exact_launcher_source_digest": null,
"ssh_transport_admission_receipt": null,
"destination": "railiance01 Linux main-thread V5 stdin",
"no_pty": true,
"caller_files_explicit_consumption": true,
"delivery_timeout_seconds": 5,
"decoded_claim_checks_are_signature_verification": false,
"launcher": "scripts/openbao_negative_private_launcher.py",
"ready_schema": "key39-private-input-ready/v1",
"ready_before_any_token_load_consume_write": true,
"ready_requires_nonce_source_envelope_health_window_match": true,
"marker_is_authenticated_authority": false,
"launcher_or_transport_admitted": false,
"remote_child_sha256": "24b7b803e4eb7e6e7c0700a069dad0ec315ee7eb5538a88b9e56147f8fab5cdd",
"remote_wrapper_sha256": "76ac013d1a676a0dfa58aea1ce87b0c3e72483ccd21f586a22c5475e9132f6c1",
"stdio_alias_rejection": "device/inode aliases of0/1/2 and data/control pipes",
"exclusive_same_uid_custody_required": true,
"atomic_inode_delete_guaranteed": false,
"credential_copy_cleanup_verified": false,
"credential_files_remain_possible": true,
"private_unknown_implies_sticky_consumer_unknown": true,
"preparation_total_seconds": 5,
"original_budget_shared_from_main_through_contract_spawn_ready_and_handoff": true,
"source_files_nonblocking_nofollow_regular_stable": true,
"source_contract_envelope_max_bytes": 65536,
"source_hash_file_max_bytes": 262144
},
"node_route": {
"selected_reviewed_origin": null,
"allowed_v5_origins": [
"http://127.0.0.1:18200",
"http://openbao.openbao.svc:8200"
],
"owner_route_receipt": null,
"public_health_preflight_guard_source_digest": null,
"health_before_tokens_credentials_mutations_restarts": true,
"workstation_observation_is_node_route_evidence": false
},
"decisions_required": [
"Founder existing console reuse versus new client",
"NetKingdom current registration/MFA/callback/runtime/guarded health ordering",
"Platform coding-agent live/custody/consumer admission and node route",
"Exact trusted launcher and private-file allowance",
"Fresh exact founder live proposal decision after all evidence",
"Separate founder directSSH control profile, exact launcher and continuously exclusive sameUID private tmpfs custody; marker is not a grant"
],
"previous_producer_manifest_sha256": "569672ecdb3f1f5b46122183dc3b82e83ff168c07c87db7211ec26bc1ce6184a",
"previous_producer_consumer_refusal_sha256": "a1ed14e6b2db1ae77c3fd638fd7e47b5bd50c25eebba418e31aba89bb4b7f88e",
"lifecycle_proposal_id": "KEY-WP-0039-T02/attended-lifecycle-v9-ready-input",
"previous_pair_source_refusal_sha256": "8353eb8aae11be8ce874887d6a5ca10bf37c6fba73c3f85f0644a7546dd7d33f",
"previous_source_refusal_sha256": "38abf660701194f85934a076a0c01d3047e6bfe790e02ba1b0e4616e356634e6"
}

View file

@ -0,0 +1,356 @@
# KEY39 private token producer and node-route decision packet
Proposal `KEY-WP-0039-T02/private-producer-handoff-v1`, source preparation only.
Lifecycle V5 is unchanged (manifest d1f997624db46693a7126a6eb6435f6b3a353d5bd67dcc8a539683e4b7147285).
This packet names concrete supported flows and a reviewable local handoff. It
supplies no admitted credential route, authenticated approval or native readiness.
T01 stays done and T02 open; no new workplan or task is created.
## Existing flows and exact owner choice
Choose existing `netkingdom-bootstrap-console` for the human class refusal if
NetKingdom/founder approve this one attended use of their existing client and
literal `http://127.0.0.1:8876/oidc/callback` listener. Its source registration is
public authorization_code, scopes openid/profile/email/groups, default audience
netkingdom-bootstrap-console. Request only `openid`; do not request approval or
OpenBao permissions. `keycape login` verifies RS256 issuer/access audience/scopes,
ID-token client audience/nonce and matching subject. It binds before emitting a
browser URL, validates exact callback host/path/state, uses S256 PKCE, and has a
five-minute attempt bound. The provider handles password/MFA. Fresh deployed
MFA/registration evidence is required; the handoff requires human aal2/mfa=true.
Do not infer MFA from the client fragment: it has no per-client mfaRequired pin.
Do not run the bootstrap console simultaneously on port8876. The same client's
localhost callback is not substituted: the CLI requires a literal loopback IP.
Concrete producer invocation after that decision, on the attended workstation:
```
keycape login --issuer https://kc.coulomb.social \
--client-id netkingdom-bootstrap-console --audience netkingdom-bootstrap-console \
--scope openid --redirect-uri http://127.0.0.1:8876/oidc/callback \
--out /OWNER-PRIVATE-TMPFS-DIR/key39-human.json
```
The private directory is new owner-controlled mode0700 tmpfs outside Git; the
CLI creates the file mode0600 exclusively. No invocation is performed here.
Current browser access-token lifetime is server TokenLifetime; per-client
TokenLifetime is used only for client_credentials. Do not promise a new one-minute
human lifetime by adding that field to a browser registration.
Alternative only if the owner rejects existing-client use: request one separately
reviewed public client `key39-negative-human`, audience of the same name, exact
callback `http://127.0.0.1:8877/oidc/callback`, scopes [openid], grantTypes
[authorization_code], mfaRequired true, no role/serviceSubject/secretRef. That
requires a new source registration, reviewed native merge/rollback and changed
handoff audience binding. It is not part of V5's six temporary clients and must
not silently enter that mutation. The current adapter intentionally refuses it.
Reuse of informed-decision-approver is unsuitable for this CLI: its registered
callback is HTTPS decisions.coulomb.social, not literal loopback. OpenBao admin
is another source-compatible callback but its admin relying-party purpose is
unnecessary for this probe and is not the selected plan.
Coding-agent producer is exactly the existing accepted source identity:
```
keycape service-token --issuer https://kc.coulomb.social \
--client-id codex-railiance-platform --audience codex-railiance-platform \
--scope openbao:login --secret-env KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET \
--out /OWNER-PRIVATE-TMPFS-DIR/key39-agent.json
```
Subject service:codex:railiance-platform, tenant:platform, roles [coding-agent],
principal_type service; fifteen-minute JWT, no refresh or ID token. The secret
must arrive from an existing **admitted** owner-controlled delivery. No client
secret request or generation occurs here. A source fragment is not live
registration or consumer entitlement. The inspected Platform operational identity
is AppRole; its OpenBao token cannot substitute for this JWT. Its historical
coding-agent prose still names tenant:coulomb, whereas current KeyCape source
uses tenant:platform. Platform must reconcile its exact proposed/installed
metadata, not use that historical prose as evidence.
No reviewed coding-agent client-side custody reader/consumer delivery receipt
was found in the inspected CCR/registry sources. Platform must either return
exact existing admission coordinates and fresh live registration/delivery evidence
or own a new narrow custody/issuer/consumer admission proposal. Do not borrow
secrets-engine's credential, widen its role, read raw KV, or mint an ephemeral
coding-agent lookalike to manufacture this case. If unavailable, the joint
session remains blocked and coding-agent refusal inconclusive; V5 requires both
private token inputs and cannot silently skip the case.
## Private handoff adapter
`scripts/openbao_negative_private_handoff.py` adapts the two existing CLI files
to V5 private stdin JSON keys human_token and coding_agent_token. It makes no
network request, login, secret retrieval, registration, deployment or executor
launch. The source is Linux main-thread only. Before file consumption it requires
an inherited **writable pipe FD >=3**, never stdout/stderr, a new owner mode0700
non-symlink directory outside Git, single-link mode0600 regular files owned by
the current UID, bounded reads and unchanged inode/size/timestamps. JSON rejects
duplicate/nonfinite keys; token length is bounded. Both files must be distinct.
A second inode/metadata compare immediately precedes each unlink.
The adapter checks decoded issuer/audience/principal/agent claims and at least
300 seconds remaining lifetime, plus human MFA shape. These are not signature
verification or authenticated custody: its tests deliberately use unsigned
synthetic JWT shapes. The founder must run the pinned current KeyCape CLI and
retain exclusive custody continuously; arbitrary downloaded/preexisting files
are inadmissible despite matching mode or claims. CLI signature verification is
the issuer-verification boundary. Require a fresh remaining-lifetime check before
native execution and ensure token validity through the actual presentation; the
five-minute adapter floor is not a grant for a longer session.
Explicit `--consume-owner-files` authorizes removal of precisely these inspected
caller-owned files. After both load successfully, the adapter consumes them
before writing the pipe and closes its inherited endpoint on every exit. Partial
unlink failure records possible retained files; partial/broken/timed-out delivery
records unknown delivery and must stop before native mutation, with no retry.
Delivery has a hard five-second SIGALRM bound; preexisting timer refuses and
handler/timer state is restored. Receipts contain booleans and fixed failure
codes only; a pipe write completion does not prove downstream validation or native
acceptance. No stdout token path exists. A private pipe still requires a trusted
consumer: the adapter cannot authenticate its peer, approval JSON or native go.
The founder-reviewed launcher must create the pipe and start a pinned destination
wrapper before running the adapter with that endpoint inherited as FD3. The
wrapper may invoke the already approved SSH transport to railiance01 and forward
stdin without PTY, shell tracing, tee, terminal/stdout copies, token argv/env,
logging, agent custody or persistent remote files. The destination reads the
private JSON with V5; no additional file copy. Exact workstation producer and
node wrapper paths, hashes, SSH host identity/transport grant, consumer startup
order, refusal gating and receipt handling must be owner-reviewed first. This
packet does not ship or admit such a launcher and cannot claim a full handoff.
Token files must be consumed before starting V5; on failed preparation the owner
removes remaining exact files. This packet requires founder choice to admit the
two bounded caller-owned JWT files: V5's no-copy rule for generated six client
secrets is unchanged. Python memory/Unix unlink are not secure-zeroization claims;
use an owner tmpfs directory and process termination. Issued JWTs expire normally.
No issuer-side JWT revocation is claimed. Any OpenBao acceptance remains V5's
bounded self-revoke/Platform reconciliation obligation.
## Mandatory route and decision ordering
The child is a Linux main-thread process on railiance01 using its k3s kubeconfig.
Workstation loopback18200 tunnel evidence does not prove node loopback18200;
openbao.openbao.svc normally resolves from Pods, not necessarily the host. Keep
native proposal gated until Platform/NetKingdom verify one of V5's exact origins
**from the actual node process placement**, using a separately reviewed founder
port-forward path if required. Do not expand V5 origins or use workstation role
observations as route proof.
Before any token exchange, temporary credential generation, Secret creation,
registry/env mutation or restart, the owner preflight must run a bounded public
Bao health request from that exact placement to the selected origin. It follows
no redirect or ambient proxy, caps response bytes and total elapsed time, sends
no auth header and prints only normalized initialized/unsealed/health booleans.
Verify acceptable active/standby health semantics independently, current TLS or
local port-forward ownership, no unintended public bind and non-secret issuer
connectivity. No auth, KV/data path or raw error output. The V5 transport currently
allows login/revoke only; this additional public health/route preflight belongs
in the reviewed launcher/NetKingdom guard, not an unreviewed V5 edit.
Owner sequence: select source plan -> independent KeyCape/NetKingdom/Platform
reviews -> approved exact launcher plus route/health preflight -> admitted
producer/custody and human browser attempt -> private-pipe delivery -> destination
validates complete stdin/envelope/source/runtime/role receipts -> native action
only under fresh exact founder authorization -> V5 cleanup/revoke plus producer
cleanup. Any unavailable route/custody/client/complete input keeps T02 open.
## Exact acknowledgments still required
- KeyCape: selected client/claims/CLI verification, lifetime and MFA source;
this packet is preparation, not a formal source acknowledgment of a launcher.
- NetKingdom: actual existing registration/image, client reuse and callback
listener ownership, browser/workstation/node placement, guarded public health
preflight ordering and exact restart/cleanup runtime pins.
- Platform: coding-agent existing custody/consumer entitlement or new proposal,
corrected tenant metadata, route/port-forward ownership, fresh bounded role/
leeway/effective-policy observation, session revoke and unknown reconciliation.
- Founder: existing-client purpose reuse versus new registration, explicit private
tmpfs JWT-file allowance, admitted exact launcher/transport/target/window/cleanup
obligation and actual supervised custody. Source acceptance is not that go.
18 synthetic adapter checks pass: successful private write and file consumption,
stdout/stderr/regular/read-only FD refusal, explicit consumption, symlink/hardlink/
public mode/parent/Git/oversize/duplicate JSON refusal, wrong audience/MFA/tenant/
role/AppRole/expiry refusal, replacement before unlink, hard write timeout with
signal restoration and value-safe partial/broken delivery. Original V5/failed
review histories and all source/current owner records remain retained.
# V2 correction and exact child-ready integration
The V1 packet text above is retained history. Proposal
`KEY-WP-0039-T02/private-producer-handoff-v2` supersedes its unsafe no-ready
adapter and its precise-inode-removal wording. V1's immutable manifest239aaa
and NetKingdom consumer refusal a1ed14e6b2db1ae77c3fd638fd7e47b5bd50c25eebba418e31aba89bb4b7f88e
remain recorded as the same correction trial. The exact compatible consumer is
`KEY-WP-0039-T02/attended-lifecycle-v9-ready-input`, separately pinned below;
V5/V6/V7/V8 source/review history is never implicitly repinned. No owner admission
or founder go is supplied by V2.
The KeyCape launcher is `scripts/openbao_negative_private_launcher.py`. It
validates its own and its adjacent adapter's exact source hashes plus the local
copy of the exact remote envelope. The remote child/wrapper paths and hashes
must occur in that envelope; proposal/target/source owner receipts, finite
window/health pin and founder/file-allowance receipt references must match the
reviewed contract. These fields are procedural constraints only: editable JSON
cannot authenticate approval. The founder must authenticate/retain the actual
exact disposition and own this entire launcher/custody/host context.
The source launcher alone creates SSH stdin/stdout pipes, a fresh random256-bit
nonce and fixed direct SSH argv to railiance01. It uses no PTY, strict existing
host-key checking, batch mode, no agent forwarding, no remote forwarding, finite
connection/keepalive bounds, and a minimal environment that excludes confidential
client credentials. It does not create or request a certificate, token, credential
or route. This is a proposed **separate founder-admitted direct SSH profile**:
the normal warden silent lane has different stdout rules and is not silently
repurposed. The founder/transport owner must review actual node host identity,
SSH certificate/session entitlement and pinned remote paths before execution.
No SSH command was invoked during preparation.
On railiance01 the independently NetKingdom-owned pinned wrapper creates a
local dedicated child-ready pipe and launches the exact pinned Python child
with inherited SSH stdin. No invented extra SSH file-descriptor forwarding is
used. Only after exact source/envelope checks, original action-window start and
pinned public Bao health succeeds does the child emit a bounded value-free
marker to that local pipe, close it, and enter the V8 bounded private receiver.
The wrapper validates that local marker and forwards exactly one newline JSON
marker on SSH stdout. SSH stdout stays open until child completion; Key reads
only to the first newline, never waits for SSH stdout EOF. Child stdout/stderr
stay suppressed; protected receipt remains exclusive on the node.
Ready schema `key39-private-input-ready/v1` has exactly these keys:
schema, session_nonce, proposal_id, target, executor_sha256, envelope_sha256,
bao_health_identity_sha256, valid_until_epoch, receive_budget_seconds. Marker
must bind the new nonce and exact consumer proposal/target/source/envelope/health
pin and epoch; receive budget must be finite nonboolean, positive and <=15s.
Marker size is <=4096 bytes. An old/missing/malformed/mismatched/failed/expired
ready marker produces **zero token file loads, zero consumption, zero private
bytes**, then closes local endpoints. A readiness marker is not authentication,
JWT verification, custody admission, routing authority or a live grant. It is
trusted only because the reviewed launcher captures the intended pinned wrapper
under the separately admitted authenticated host/session context. There is no
standalone adapter CLI accepting a ready file, boolean or user-provided marker.
The adapter validates two distinct kernel pipe identities: private data endpoint
write-only, control endpoint read-only, each FD>=3 and each device/inode distinct
from stdin/stdout/stderr and from each other. Actual duplicates of stdout/stderr
are refused even when their descriptor number is >=3. Captured SSH stdout is a
separate control pipe owned by the launcher; it never becomes token output.
The launch preparation cap is5s. The adapter has one total5s deadline covering
ready wait, caller-file load, cleanup and delivery. After ready this existing
timer only clips downward against its remaining budget, received child budget
and current remaining approval lifetime. Advertised child budget is not compared
as <=current remaining wall time (transport necessarily consumes time); the
actual delivery timer clips to both. Before each write and after completion the
same absolute expiry/monotonic delivery bound is rechecked. No retries or clock
reset; stdin closes to provide complete EOF. A partial write, transport break or
expiry remains unknown and cannot be native proof. Launcher waits only for a
value-free child/transport exit under remaining action +300s cleanup +30s margin;
local transport teardown never proves remote custody or process reconciliation.
Native receipt/unknown-session acceptance remains Platform/NetKingdom's.
## Honest file-cleanup boundary
Owner mode0700/0600, no symlink/hardlink/Git and unchanged identity/size/time
checks remain. **The compare and unlink are not atomic inode-conditioned delete.**
Continuously exclusive same-UID custody of the directory, no concurrent writers
and no attacker sharing that UID are mandatory for this proposed file approach.
No helper boolean can prove that condition. The founder must control the new
private tmpfs directory/process context and retain exclusive custody; no shared
agent/shell/daemon may modify it. Any known interference requires abort and owner
reconciliation before another attempt.
V2 removes V1's exact-inode/atomic implications. Its retained stat-to-unlink race
check deliberately shows that a concurrent same-UID replacement can still be
removed; that is outside the admitted exclusive-custody assumption and is not
represented as a fixed filesystem capability. Even after nominal path removal,
receipts retain `atomic_inode_delete_guaranteed=false`,
`exclusive_same_uid_custody_required=true`, `credential_copy_cleanup_verified=false`
and `credential_files_remain_possible=true`. `caller_path_removal_completed`
means only these unlink calls completed under that assumption. It is not token
copy inventory, secure erase or cleanup proof. Owner verification/process
termination/tmpfs teardown remains required; issued JWTs expire normally.
If that exclusive context cannot be admitted, do not use these private files;
separately implement/review a process-to-process in-memory producer instead.
The existing human-client reuse versus new registration, live MFA, coding-agent
client-side custody/consumer delivery, exact authenticated launcher/SSH profile,
private tmpfs files/exclusive custody, actual node route/provider/role/leeway,
quiet restart window and fresh founder disposition are still unapproved choices.
This source packet does not resolve them. Source-pinned readiness eliminates
premature token transport only within the admitted trusted launcher context.
Exact compatible consumer manifest SHA256 84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14;
child 24b7b803e4eb7e6e7c0700a069dad0ec315ee7eb5538a88b9e56147f8fab5cdd;
node wrapper 76ac013d1a676a0dfa58aea1ce87b0c3e72483ccd21f586a22c5475e9132f6c1.
31 distinct supplied producer/launcher synthetic checks pass; 74 supplied
compatible consumer source checks pass. No actual SSH, login, tokens, custody
or native route was used. Fresh independent consumer and Platform source
reviews of this exact V2 and V9 remain necessary before founder choice.
# V3 remote-unknown reporting correction
Proposal `KEY-WP-0039-T02/private-producer-handoff-v3`. Exact NetKingdom V9
manifest84542ddc and child/wrapper bytes are unchanged; this is only a new Key
launcher reporting revision in the same preparation trial. Platform V2 pair
review finding RPF-KEY39-PAIR-V2-F01 is retained unchanged, SHA256
8353eb8aae11be8ce874887d6a5ca10bf37c6fba73c3f85f0644a7546dd7d33f.
After copying adapter outcome, `private_input_delivery_unknown=true` immediately
sets sticky `consumer_outcome_unknown=true` and `consumer_process_completed=false`
before any failure/early return. A complete payload can reach the remote child
before local write/EOF confirmation times out. Terminating local SSH cannot
prove that no remote operation occurred, that the child stopped or that remote
custody/cleanup completed. No retry or subsequent local success rewrites this
attempt. Native acceptance and unknown resolution stay independent owner duties.
33 distinct checks pass, including actual full kernel-pipe JSON write followed
by SIGALRM interruption before confirmation, and an actual4096-byte partial
write/timeout; both retain remote unknown after local terminate. No actual SSH,
protected consumer or credentials were involved. All V2/V1 source, unsuccessful
reviews and previous narrow issuer acknowledgments remain frozen history.
Exact source return and all prior native/client/custody/transport/file choices
remain required. Source reporting correction is not runtime admission.
# V4 source-acquisition and shared preparation deadline correction
Proposal `KEY-WP-0039-T02/private-producer-handoff-v4`, same trial. The exact
Net V9 manifest84542ddc and child/wrapper are unchanged. NetKingdom V3 consumer
refusal NET-PRODUCER-V3-F01 stays frozen, SHA256
38abf660701194f85934a076a0c01d3047e6bfe790e02ba1b0e4616e356634e6. V1/V2/V3 source and earlier acknowledgments/refusals remain history.
Actual CLI now starts one absolute monotonic5-second preparation deadline before
contract acquisition. Initial source read, source/envelope/hash checks and SSH
spawn then ready/file/consumption/write phase all use only remaining time from
that original deadline. Phase timers may disarm/rearm, but each is clipped to
original remaining time; launch never restarts the budget spent reading contract.
After ready, child receive budget and absolute approval expiry only clip further.
Once private input is delivered, existing separate action/cleanup completion
wait remains; it cannot renew preparation or mutation authority.
Contract/envelope reads use bounded4096-byte chunks, at most65536 bytes, absolute
paths, no observed symlink ancestry, O_NOFOLLOW/O_NONBLOCK, single-link regular
files with no group/world write, and stable device/inode/UID/mode/link/size/time
comparisons. FIFOs/devices/symlinks/empty/oversized files refuse before private
file access/SSH. Source digest reads share that path with at most262144 bytes.
All actual CLI source acquisition runs under the finite remaining preparation
alarm; a stalled filesystem call cannot escape this total deadline. Observed
path/source races refuse; continuously trusted exclusive custody remains required
and no atomic pathname/exec protection or authenticated metadata grant is claimed.
40 distinct producer/launcher checks pass, including actual CLI FIFO/symlink/
oversize refusal, delayed regular read under the hard timer with restored signals,
a main contract-read delay followed by launch delay that cannot renew the budget,
source drift/chunk bounds and earlier actual full/partialwrite stickyunknown.
Nine retained real paired handshake regressions also pass using actual pinned
Net wrapper and child main with only local fake SSH/health/execute substitutions:
no network, Kubernetes, protected credentials or native mutation. The original
Net fixture files are copied unchanged except the Key stage path, solely as
source regression evidence, never a new foreign formal owner review.
Fresh exact independent pair source returns and all unadmitted human/MFA/client/
coding-agent custody/consumer/directSSH/exclusive tmpfs/route/provider/role/leeway/
readiness-Argo/maintenance-exception/founder/native-acceptance duties still gate
use. No source-only helper choice, ready marker or editable approval JSON supplies
that authority. T01done/T02open; actual native outcome remains pending.

View file

@ -0,0 +1,100 @@
{
"schema": "founder-source-design-choice/v1",
"proposal_id": "KEY-WP-0039-T02/founder-source-design-v1",
"status": "pending_founder_source_direction_only",
"submitted": false,
"memo_sha256": "1816e48b44eb874e4c97db82ee56ed27c23083ddcfc322d9de9876132e802688",
"source_pair": {
"key_producer_manifest_sha256": "d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e",
"net_consumer_manifest_sha256": "84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14",
"net_qualified_consumer_review_sha256": "9566955b77db4a0b041887ef4a6aff6c7a02ef30cc0727a4deb6c29bbdc79518",
"platform_fresh_exact_pair_source_return": "required separately"
},
"choices": [
{
"id": "human_producer",
"recommended": "existing_bootstrap_console_purpose_reuse_source_direction",
"options": [
"existing_bootstrap_console_purpose_reuse_source_direction",
"new_narrow_public_client_source_proposal",
"defer"
],
"selected": null,
"exact_existing_client": "netkingdom-bootstrap-console",
"exact_audience": "netkingdom-bootstrap-console",
"scope": "openid",
"callback": "http://127.0.0.1:8876/oidc/callback",
"pending": [
"Net owner purpose reuse/live registration",
"Sole intended workstation CLI listener; no existing port8876 occupant",
"Actual provider MFA receipt; verified aal2/mfa claims"
]
},
{
"id": "coding_agent",
"recommended": "return_existing_admission_or_prepare_narrow_platform_proposal",
"options": [
"return_existing_admission_or_prepare_narrow_platform_proposal",
"defer"
],
"selected": null,
"client_audience": "codex-railiance-platform",
"subject": "service:codex:railiance-platform",
"tenant": "tenant:platform",
"scope": "openbao:login",
"custody_admission_receipt": null,
"consumer_coordinates": null,
"new_ccr_number": null,
"approle_jwt_substitution_allowed": false
},
{
"id": "transport",
"recommended": "retain_proposed_founder_direct_ssh_source_profile",
"options": [
"retain_proposed_founder_direct_ssh_source_profile",
"redesign_and_review",
"defer"
],
"selected": null,
"host": "railiance01",
"compatible_with_warden_silent_lane": false,
"authenticated_host_session_entitlement_receipt": null,
"runtime_paths": null,
"granted": false
},
{
"id": "private_material",
"recommended": "conditionally_retain_exclusive_owner_tmpfs_file_source_design",
"options": [
"conditionally_retain_exclusive_owner_tmpfs_file_source_design",
"review_in_memory_producer_design",
"defer"
],
"selected": null,
"exclusive_same_uid_custody_verified": false,
"file_allowance_receipt": null,
"atomic_unlink_claimed": false,
"secure_zeroization_claimed": false
}
],
"permitted_effect_of_source_direction": "Owner source/design preparation and exact independent review only",
"cost_and_risk_scope": {
"external_spend_authorized_eur": 0,
"native_cost_risk_decision": "separate future scoped proposal required",
"source_risks": [
"Purpose reuse/MFA/callback listener unadmitted",
"Coding-agent custody missing",
"Distinct SSH profile/session identity unadmitted",
"SameUID private-file exclusivity non-atomic/no zeroization",
"Provider/plugin/role/leeway and readiness/Argo/maintenanceexception facts pending"
]
},
"native_authorized": false,
"credentials_or_login_authorized": false,
"ssh_or_portforward_authorized": false,
"registrations_or_restart_authorized": false,
"architecture_whole_v0_9_accepted": false,
"agent_autonomy_promoted": false,
"standing_privilege_or_default_flip": false,
"KEY39_T02_closed": false
}

View file

@ -0,0 +1,158 @@
# Founder source-design choice for KEY39 private input
Proposal ID: `KEY-WP-0039-T02/founder-source-design-v1`.
Disposition: pending founder choice. Scope: source-design direction only.
Recommended: retain the existing bootstrap-console human client for one attended
negative-class producer, require Platform to return exact existing coding-agent
admission or a new narrow owner proposal, and retain the reviewed direct SSH
ready-channel design for later separate admission. Approving that direction
allows owner source preparation and review. It does not allow a login, credential
request/read, client registration, port-forward, SSH session, native preflight,
issuer restart or mutation.
## Exact source under consideration
Key producer V4 manifest:
`d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e`,
`/tmp/keycape-jwt-producer-handoff-v4-stage/manifest.json`.
Net consumer V9 manifest:
`84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14`,
`/tmp/keycape-jwt-ready-v9-stage/manifest.json`.
Launcher `46e57504b3185cc13f1656901a0ca02cc3887527cb09566e270f57b76099ab9c`;
adapter `faf63a3e9504dcbb46847a114275f83d508521e095410a47f92f02b86ba82b1b`;
child `24b7b803e4eb7e6e7c0700a069dad0ec315ee7eb5538a88b9e56147f8fab5cdd`;
node wrapper `76ac013d1a676a0dfa58aea1ce87b0c3e72483ccd21f586a22c5475e9132f6c1`.
NetKingdom's exact qualified consumer source agreement:
`9566955b77db4a0b041887ef4a6aff6c7a02ef30cc0727a4deb6c29bbdc79518`.
Its 40 maker and 13 independent checks establish source behavior with synthetic
transport/health/private tokens. Platform's fresh exact-pair source return is
required separately. KeyCape's issuer/interface judgment stays inside its INTENT
Tooling boundary. No source return is a protected-operation entitlement.
## Choices to record
| Choice | Recommended source direction | Alternative and consequence |
|---|---|---|
| Human producer | Owner-permitted reuse of `netkingdom-bootstrap-console` for one attended CLI session; request `openid` only. | If NetKingdom rejects purpose reuse, propose public `key39-negative-human`, audience same name, literal callback `http://127.0.0.1:8877/oidc/callback`, scopes [openid], authorization_code, mfaRequired true. This needs a new source/registration/rollback packet and changed adapter audience. No registration is implied. |
| Coding-agent input | Require Platform's exact existing `codex-railiance-platform` live registration and client-side custody/consumer delivery receipts. | If missing, stop this native case and let Platform prepare a narrow custody/issuer/consumer admission proposal with coordinates/owners settled first. No invented CCR number or entitlement; AppRole is not a JWT substitute. |
| Transport source profile | Retain proposed founder-owned direct SSH captured-control profile to railiance01, with pinned child/wrapper/envelope and exact-child-ready gate. | If that profile cannot be independently admitted, keep the native session gated and redesign/review a compatible transport. Do not reuse the warden silent lane or eager shell piping. |
| Caller-token material | Source-design option: two owner-created private tmpfs files, mode0700 directory/mode0600 single-link files, then explicit consumption and pipe-only transfer. | If continuously exclusive same-UID custody cannot be established, do not use the file design; separately review an in-memory producer. Source approval does not admit either custody mechanism. |
No answer, partial answer or rejected choice defaults to a gated native session.
The recommendation is a direction for source preparation, not an automatic
registration, credential generation or admission.
## Human identity, callback and MFA contract
Exact candidate client/audience: `netkingdom-bootstrap-console`.
Issuer: `https://kc.coulomb.social`. Requested scope: `openid`.
Literal callback: `http://127.0.0.1:8876/oidc/callback`.
The current source registration is public authorization_code and lists this
literal callback separately from localhost. KeyCape CLI requires literal
loopback, binds `127.0.0.1:8876` before emitting its browser URL, and accepts
only GET, exact Host `127.0.0.1:8876`, exact path `/oidc/callback`, one matching
state and one code. Fresh state/nonce/S256 PKCE, five-minute attempt timeout,
RS256 discovery/JWKS verification, access audience/requested scopes and ID-token
client audience/nonce/matching subject remain the existing source contracts.
Do not alias localhost, change a callback string or redirect a browser to the
node. Producer and browser are on the founder-owned workstation.
Before any future attempt, NetKingdom must confirm this exact client is live,
accept its proposed CLI purpose reuse, establish that no bootstrap console or
other listener owns port8876, and identify the sole intended CLI listener/process
in the attended workstation context. Bind failure stops, never kills or adopts
another listener. A public callback and source registration alone are not that
runtime evidence.
This registration has no per-client mfaRequired pin. Earlier deployment-default
MFA statements are historical, not current proof. The future owner receipt must
confirm actual provider/client MFA behavior; producer handoff requires verified
human claims `assurance.level=aal2` and `assurance.mfa=true`, not an unenforced
caller label. The CLI cryptographically verifies returned tokens; the adapter's
decoded shape check does not. A human token may differ on audience/tenant/roles
as well as principal_type, so this is human-class refusal, not isolated proof
of principal_type enforcement. Browser access-token lifetime uses the server
lifetime; adding per-client tokenLifetime does not shorten that flow.
## Coding-agent contract and actual missing custody
Exact accepted source identity:
client/audience `codex-railiance-platform`, subject
`service:codex:railiance-platform`, tenant `tenant:platform`, roles [coding-agent],
principal_type service, scope `openbao:login`, fifteen-minute JWT.
Secret reference name: `KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET`.
This is a reference, never a value or a request for one.
Source acceptance does not prove the client is live or supply consumer-side
secret injection. No admitted coding-agent custody/consumer receipt was found
in the inspected source set. Platform must return exact existing admission and
fresh registration/delivery ownership or prepare a separate narrow proposal.
Historical Platform coding-agent prose names tenant:coulomb and describes an
operational AppRole; it cannot supersede current tenant:platform issuer source
or manufacture the requested JWT. Do not skip this case, borrow secrets-engine's
credential, retrieve raw KV, widen an AppRole/policy or make a temporary coding-
agent lookalike. Full KEY39 native evidence remains incomplete until settled.
## Proposed source profile and trust limits
The source launcher creates captured stdin/data and stdout/control pipes for a
fixed direct SSH command to railiance01: no PTY, strict existing host-key checking,
batch mode, no agent forwarding or remote forwarding, bounded connect/keepalive
and credential-excluding environment. The node wrapper creates a local ready
pipe; SSH does not forward arbitrary extra file descriptors. Child/wrapper/
envelope hashes, exact target `sso/keycape`, proposal, fresh nonce, public-health
identity hash, original finite window and receive budget bind the returned marker.
No marker means zero caller-token loads/consumption/private bytes. Caller STDIO
aliases are refused by kernel pipe identity. Source acquisition and handoff share
one original five-second preparation budget; V8's bounded complete EOF receive
and original action/cleanup limits remain. Uncertain delivery stays remote
consumer uncertainty after local SSH termination.
This captured control stdout profile is **incompatible with the existing warden
silent-output lane**. It is not an exception inferred from shell prefixes or
source review. Future direct SSH admission must name the authenticated founder
identity/session/certificate entitlement, exact host key/transport/runtime paths,
producer/consumer process identities and custody/window/cleanup obligations.
No certificate, credential, SSH access or profile activation is requested here.
The ready marker synchronizes source readiness; it does not authenticate a peer,
issuer, provider, founder decision or privileged grant by itself.
The file option requires continuously exclusive same-UID directory custody, no
concurrent writer and owner tmpfs/process teardown. Stat/unlink is non-atomic.
Receipts explicitly keep atomic delete and copy cleanup unverified and possible
copies true. Unix unlink/Python memory are not secure-zeroization guarantees;
remaining or unknown copies/sessions require owner reconciliation. If these
assumptions cannot be established, the file option must remain unused.
## Facts still required before a separate native decision
NetKingdom/Platform must verify the actual same-node route. Workstation
loopback18200 does not prove node loopback18200; Pod DNS is not assumed for the
host. A public health cluster digest detects changes but does not authenticate
the provider. Actual admitted route/Service/cluster identity, freshly observed
installed JWT plugin, role/config/effective policies and all expiration,
clock-skew and not-before leeway interactions are pending native facts.
Issuer readiness_state, actual Argo ownership and production-tier mapping must
be established authoritatively. Absence of a declaration is not nonproduction.
If adopted/production-approved, temporary direct CAS changes require an explicit
reviewed one-use maintenance exception, close-down entry and reconciliation.
Headroom, quiet restart window, exact runtime revision, approved temporary names
and cleanup/recovery remain required.
Future native founder go must be a distinct authenticated scoped disposition for
exact approved source/runtime/target/window/route/producer/credential custody and
bounded abort/revoke/restoration/recovery duties. Source-design approval today
cannot be replayed as that go. Actual eight refusals including expiry positive
control, revoked unexpected acceptance, baseline restoration/removed clients/
temporary-object absence/private-copy reconciliation remain required afterward.
This memo approves no architecture-wide v0.9 acceptance, agent autonomy promotion,
standing privilege/default flip, routing activation, native KEY39 closure,
Platform/Mason acceptance or Secrets Engine full adoption. It leaves T01done and
T02open under the existing work record, with all failed/revised source history.

View file

@ -0,0 +1,74 @@
{
"schema": "owner-source-review/v1",
"review_id": "KEY-ACK-20261011-KEY39-V9-PRODUCER-V4",
"reviewer": "codex acting in KeyCape issuer-owner scope",
"role_scope": "KeyCape INTENT authentication/issuance/claims and caller token lifecycle only",
"decision": "approved",
"qualification": "Exact bounded issuer/private interface source compatibility only; all native/transport/custody/founder admissions remain false",
"consumer_proposal_id": "KEY-WP-0039-T02/attended-lifecycle-v9-ready-input",
"consumer_manifest_sha256": "84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14",
"producer_proposal_id": "KEY-WP-0039-T02/private-producer-handoff-v4",
"producer_manifest_sha256": "d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e",
"work_record": {
"task": "KEY-WP-0039-T03",
"status": "done",
"same_task_refinement": true,
"current_owner_work_record_sha256": "57d5f1a9cd5d15737d47a9273bf01355ba818b2748e1a43fd7ff2138bed50f4f",
"completed_inspection_receipt_path": "/tmp/keycape-jwt-v9-v4-owner-decision-stage/key-cape/docs/reviews/2026-10-11-key39-v9-v4-keycape-work-record.json",
"completed_inspection_receipt_sha256": "b5074fdc22eb8f62ae035254bfb8311272cf8a7ec6ed14b60eebd14f5ef4046c",
"completed_before_formal_acknowledgment": true
},
"scope_accepted": [
"Original finite source/window/public health gates precede nonce-bound ready and complete bounded private input; action window is not renewed",
"V4 actual CLI regular bounded nofollow/nonblock stable source acquisition starts under one ORIGINAL5s preparation budget shared with launch/ready/filewrite",
"Exact child/wrapper/envelope/health/window source marker matches private Key reader before ANY token load/consume/write; fixed owner-created SSH data/control pipes and stdio alias refusal",
"Private uncertain write remains sticky remote uncertainty after local transport teardown; full/partial failure histories retained",
"Existing issuer/client claim design, original runner and explicit unauthenticated shape/ready metadata limits unchanged",
"Non-atomic unlink requires continuous exclusive sameUID custody; copy cleanup remains unverified/possible"
],
"findings": [],
"fresh_qualified_net_consumer_review": {
"path": "/tmp/netkingdom-key39-producer-v4-consumer-review-stage/owner-review.json",
"sha256": "9566955b77db4a0b041887ef4a6aff6c7a02ef30cc0727a4deb6c29bbdc79518",
"source_only": true,
"not_a_KeyCape_Net_runtime_review": true
},
"validation": {
"key_source_tests_retained": 40,
"net_exact_pair_independent_checks": 13,
"own_fresh_interface_tests": 3,
"all_passed": true,
"own_checks_path": "/tmp/keycape-jwt-v9-v4-owner-decision-stage/evidence/test_keycape_ready_interface.py",
"own_checks_sha256": "ba85e5ff2cda5c7c2cc86f50bde67bca027e2e63be1c5195f06764b8e1cd5716",
"synthetic_unsigned_private_fixtures_only": true,
"native_or_credentials": false
},
"excluded": [
"Net formal runtime/route/port-forward/restarts/cleanup acceptance",
"Platform formal provider/plugin/role/policy/leeway/custody/PEP/backend acceptance",
"Founders actual identity/session/source/runtime/route/window/native decision",
"Human client purpose/MFA/listener and coding-agent live custody/consumer admission",
"Direct SSH profile, file allowance/exclusive UID context, authenticated transport/runtime authority",
"Whole architecture v0.9 acceptance, autonomy promotion, standing privileges/default flips or native task closure"
],
"pending_platform_exact_pair_return": "Required separately; old V2pairrefusal is not repinned",
"founder_source_design_memo": {
"path": "/tmp/keycape-jwt-v9-v4-owner-decision-stage/key-cape/docs/proposals/2026-10-11-key39-founder-source-design-decision.md",
"sha256": "1816e48b44eb874e4c97db82ee56ed27c23083ddcfc322d9de9876132e802688",
"status": "unsubmitted source-direction choice only",
"native_go": false
},
"sources_receipt_sha256": "2a7a587264ceeb902040417d0bc5c329af461590d8bc99edf818ec5699f0a5b0",
"prior_v2_bound_ack_sha256": "8293e18dcffe7b8e0748880753974219b99d347a173f75a32cc1aad2b4c30f95",
"preserved_refusals": [
"a1ed14e6b2db1ae77c3fd638fd7e47b5bd50c25eebba418e31aba89bb4b7f88e",
"8353eb8aae11be8ce874887d6a5ca10bf37c6fba73c3f85f0644a7546dd7d33f",
"38abf660701194f85934a076a0c01d3047e6bfe790e02ba1b0e4616e356634e6"
],
"same_trial_no_additional_scored_success": true,
"native_authority_granted": false,
"native_route_observed": false,
"private_producer_admission": false,
"founder_design_disposition_submitted": false,
"KEY39_T02_closed": false
}

View file

@ -0,0 +1,168 @@
{
"owner": "key-cape",
"consumer_manifest_path": "/tmp/keycape-jwt-ready-v9-stage/manifest.json",
"consumer_manifest_sha256": "84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14",
"producer_manifest_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/manifest.json",
"producer_manifest_sha256": "d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e",
"qualified_net_consumer_review_path": "/tmp/netkingdom-key39-producer-v4-consumer-review-stage/owner-review.json",
"qualified_net_consumer_review_sha256": "9566955b77db4a0b041887ef4a6aff6c7a02ef30cc0727a4deb6c29bbdc79518",
"exact_consumer_entries": [
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/openbao-negative-session.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/openbao-negative-session.py",
"original_sha256": "da4e0ab767e0c3bebb48bcf5ab578b50845d9fa7211a6771661a0e1baa4314ab",
"staged_sha256": "24b7b803e4eb7e6e7c0700a069dad0ec315ee7eb5538a88b9e56147f8fab5cdd",
"previous_frozen_staged_sha256": "da4e0ab767e0c3bebb48bcf5ab578b50845d9fa7211a6771661a0e1baa4314ab"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/test_openbao_negative_session.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/test_openbao_negative_session.py",
"original_sha256": "01e23f2b4fc77824a161a57acb3a52d19aad846b3b6c0fd3abd81afa1dc2985c",
"staged_sha256": "01e23f2b4fc77824a161a57acb3a52d19aad846b3b6c0fd3abd81afa1dc2985c",
"previous_frozen_staged_sha256": "01e23f2b4fc77824a161a57acb3a52d19aad846b3b6c0fd3abd81afa1dc2985c"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/test_openbao_node_route.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/test_openbao_node_route.py",
"original_sha256": "9f3d8d4297c5ef68f6c6bf7ca21e981e37d7eceb836a60bc254d33b0f5129047",
"staged_sha256": "1c57053be6e8472174e4034fdfbf34b3e1729f5e239b3a9af89d9e59a08d6cb6",
"previous_frozen_staged_sha256": "9f3d8d4297c5ef68f6c6bf7ca21e981e37d7eceb836a60bc254d33b0f5129047"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/openbao-negative-node-route.md",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/openbao-negative-node-route.md",
"original_sha256": "a04c94512efec7a524b15a3eec61d86de5a41df872e59a3114093063a11e75a0",
"staged_sha256": "cad3e3dc481d45295cc014e48285e81614911dfb4a10523883f3044f6085f363",
"previous_frozen_staged_sha256": "a04c94512efec7a524b15a3eec61d86de5a41df872e59a3114093063a11e75a0"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/test_openbao_private_input.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/test_openbao_private_input.py",
"original_sha256": "a59c2cd4ec895c1718d52fd12f64666f1be45ae423fde476755b6d77a89280c2",
"staged_sha256": "84277edb5bd7858885173dea802b6bdc4f0f0c7785d6e200ee9a98d8553891a1",
"previous_frozen_staged_sha256": "a59c2cd4ec895c1718d52fd12f64666f1be45ae423fde476755b6d77a89280c2"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/openbao-negative-node-wrapper.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/openbao-negative-node-wrapper.py",
"original_sha256": null,
"staged_sha256": "76ac013d1a676a0dfa58aea1ce87b0c3e72483ccd21f586a22c5475e9132f6c1"
},
{
"repo": "net-kingdom",
"path": "sso-mfa/k8s/keycape/test_openbao_private_ready.py",
"staged_path": "/tmp/keycape-jwt-ready-v9-stage/net-kingdom/sso-mfa/k8s/keycape/test_openbao_private_ready.py",
"original_sha256": null,
"staged_sha256": "8a7a033b1c509ba21397d1d74580c44f24592045b2b9de50fe87638607224277"
}
],
"exact_producer_entries": [
{
"repo": "key-cape",
"path": "docs/openbao-negative-token-producer-decision.json",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/docs/openbao-negative-token-producer-decision.json",
"original_sha256": null,
"staged_sha256": "7b3e4a53ac4af33c780f16c3f1aa9cde0154040ad2747a8d361dd79bbb7f435c",
"previous_frozen_staged_sha256": "ee5dccb8d3b263584127edff73a6f9292b29eb2725f982cdfdbd784141bdd98f"
},
{
"repo": "key-cape",
"path": "docs/openbao-negative-token-producer-decision.md",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/docs/openbao-negative-token-producer-decision.md",
"original_sha256": null,
"staged_sha256": "38e4c9660ca57a1fb6e5ff04f214af61dd1a58abf564a5ed22216d909e27fc73",
"previous_frozen_staged_sha256": "50994f0882bac8c78227e8d8669f8be7ab9a07a8a35f1f8cc0bc5caeac275aa3"
},
{
"repo": "key-cape",
"path": "scripts/openbao_negative_private_handoff.py",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/scripts/openbao_negative_private_handoff.py",
"original_sha256": null,
"staged_sha256": "faf63a3e9504dcbb46847a114275f83d508521e095410a47f92f02b86ba82b1b",
"previous_frozen_staged_sha256": "faf63a3e9504dcbb46847a114275f83d508521e095410a47f92f02b86ba82b1b"
},
{
"repo": "key-cape",
"path": "scripts/openbao_negative_private_launcher.py",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/scripts/openbao_negative_private_launcher.py",
"original_sha256": null,
"staged_sha256": "46e57504b3185cc13f1656901a0ca02cc3887527cb09566e270f57b76099ab9c",
"previous_frozen_staged_sha256": "2a54568df541c38d43ca2482f037761770e6df206fb1cb88c1222ed7291f5e98"
},
{
"repo": "key-cape",
"path": "scripts/test_openbao_negative_private_handoff.py",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/scripts/test_openbao_negative_private_handoff.py",
"original_sha256": null,
"staged_sha256": "e4eb600718e7d93b0e801ac3ab1427af9895a6e5d877c1134369e049e0849797",
"previous_frozen_staged_sha256": "e4eb600718e7d93b0e801ac3ab1427af9895a6e5d877c1134369e049e0849797"
},
{
"repo": "key-cape",
"path": "scripts/test_openbao_negative_private_launcher.py",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/scripts/test_openbao_negative_private_launcher.py",
"original_sha256": null,
"staged_sha256": "243426a85075b3447adeb2ca320a13711409744f71837a06699de6ad5b04ee9d",
"previous_frozen_staged_sha256": "243426a85075b3447adeb2ca320a13711409744f71837a06699de6ad5b04ee9d"
},
{
"repo": "key-cape",
"path": "scripts/test_openbao_negative_private_preparation.py",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/scripts/test_openbao_negative_private_preparation.py",
"original_sha256": null,
"staged_sha256": "8e4dd327c4a339a0151ecba57db5987965b5d536ca18123fb7c74a047a241548"
},
{
"repo": "key-cape",
"path": "workplans/KEY-WP-0039-openbao-negative-probe-tokens.md",
"staged_path": "/tmp/keycape-jwt-producer-handoff-v4-stage/key-cape/workplans/KEY-WP-0039-openbao-negative-probe-tokens.md",
"original_sha256": "57d5f1a9cd5d15737d47a9273bf01355ba818b2748e1a43fd7ff2138bed50f4f",
"staged_sha256": "f6113d269f127976518acb48eca818fd5d6f12421f4e4c742e8a84f49a14360b",
"previous_frozen_staged_sha256": "1385f0b692a031fd52046e1dd98c42ff7a5a4ca4d1c340551ec8751a07e80ee6"
}
],
"completed_inspection_receipt_sha256": "b5074fdc22eb8f62ae035254bfb8311272cf8a7ec6ed14b60eebd14f5ef4046c",
"founder_source_memo_sha256": "1816e48b44eb874e4c97db82ee56ed27c23083ddcfc322d9de9876132e802688",
"founder_source_choices_sha256": "d2f6e2fc733d8092a27a1dafb2f77601cbff398c5606b12bb053b4cd7bcd4091",
"current_key_source_pins": [
{
"path": "AGENTS.md",
"sha256": "77c8e1ac762e7c101cd09a3aa184993309ed057821bd53fb0d318979a45c9315"
},
{
"path": "INTENT.md",
"sha256": "b22cb440691bb399b064ee10ab1a03e1e07838da1051bf6235fbfe2cf820eb10"
},
{
"path": "src/internal/authclient/cli.go",
"sha256": "376a8e0d1d60825a8b3ef21d371e3fc353c0a34e461712a6899e264278edbe7f"
},
{
"path": "src/internal/authclient/client.go",
"sha256": "61fb150349c5d3714450a90834c59af9a579a8a649c4149297a402cfcf6e39c5"
},
{
"path": "src/internal/server/oidc/token.go",
"sha256": "8422cc9dbd39c88dfe835b43f6262cb120bc0d2e5b08898a151167b7555368d3"
},
{
"path": "config/service-clients.example.yaml",
"sha256": "b7e17698a0946f387c481b7e27fe9ddea22cdd9db2e34e32a50457e02a34b18e"
},
{
"path": "docs/native-authentication.md",
"sha256": "378a5fa8174580bde811b716ec8e987339013b9f8d7725cb398fa3b9f8d95655"
},
{
"path": "workplans/KEY-WP-0039-openbao-negative-probe-tokens.md",
"sha256": "57d5f1a9cd5d15737d47a9273bf01355ba818b2748e1a43fd7ff2138bed50f4f"
}
],
"current_net_human_fragment_source_pin": "5f727f3146016184da867ce3c304ac0b19f7ceee63c479f6ea2606f7183640f5"
}

View file

@ -0,0 +1,32 @@
{
"record_kind": "completed-owner-source-inspection",
"workplan": "KEY-WP-0039",
"task": "KEY-WP-0039-T03",
"same_completed_task_refinement": true,
"status": "done",
"established_before_formal_source_acknowledgment": true,
"current_owner_work_record_path": "/home/worsch/key-cape/workplans/KEY-WP-0039-openbao-negative-probe-tokens.md",
"current_owner_work_record_sha256": "57d5f1a9cd5d15737d47a9273bf01355ba818b2748e1a43fd7ff2138bed50f4f",
"exact_net_manifest_sha256": "84542ddcff00932fc7ce22dcb2626be8942a3c006c5098a62fdd6b2478d0cd14",
"exact_producer_manifest_sha256": "d6f641dc1e4aae7d36658d4199d89af14d2fd7a4bd4e526856eb340234f2d33e",
"scope": "KeyCape issuer/private caller-token interface only, not Net or Platform formal role",
"completed_checks": [
"Exact source/manifest entries verified",
"Fresh qualified Net consumer source review verified exact95\u2026sha and pair fields",
"Three actual child emitter + current Key V4 reader tests pass without token file loads on wrong/expired marker",
"Current CLI issuer/client/callback/MFA source inspected",
"Source-design choices separated from native authority; staged existing T02 notes untouched"
],
"validation": {
"key_maker_checks_retained": 40,
"net_independent_exact_pair_checks": 13,
"own_fresh_interface_checks": 3,
"no_network_credentials_native_or_owner_checkout_writes": true
},
"prior_v2_bound_ack_preserved_sha256": "8293e18dcffe7b8e0748880753974219b99d347a173f75a32cc1aad2b4c30f95",
"producer_T02_notes_preserved_not_applied": true,
"states_retained": {
"T01": "done",
"T02": "open"
}
}

View file

@ -0,0 +1,266 @@
#!/usr/bin/env python3
"""Owner-held verified KeyCape CLI files -> inherited pipe; never normal output.
No login, secret retrieval, network, executor launch or authenticated admission.
Decoded claims below are shape/lifetime checks, not signature verification.
"""
import argparse
import base64
import contextlib
import fcntl
import json
import math
import os
from pathlib import Path
import signal
import stat
import threading
import time
MAX_FILE = 32768
MAX_TOKEN = 16384
class Refused(Exception):
pass
def need(condition, code):
if not condition:
raise Refused(code)
def unique(pairs):
out = {}
for key, value in pairs:
need(key not in out, 'duplicate_json_key')
out[key] = value
return out
def decode(raw):
try:
return json.loads(raw, object_pairs_hook=unique,
parse_constant=lambda _: (_ for _ in ()).throw(Refused('nonfinite_json')))
except Refused:
raise
except Exception:
raise Refused('invalid_json') from None
@contextlib.contextmanager
def deadline(seconds):
need(type(seconds) in (int, float) and math.isfinite(seconds) and 0 < seconds <= 5,
'invalid_delivery_budget')
need(threading.current_thread() is threading.main_thread(), 'main_thread_required')
need(signal.getitimer(signal.ITIMER_REAL) == (0.0, 0.0), 'existing_timer_refused')
previous = signal.getsignal(signal.SIGALRM)
def expired(*_):
raise Refused('delivery_timeout')
try:
signal.signal(signal.SIGALRM, expired)
signal.setitimer(signal.ITIMER_REAL, seconds)
yield
finally:
signal.setitimer(signal.ITIMER_REAL, 0)
signal.signal(signal.SIGALRM, previous)
READY_SCHEMA = 'key39-private-input-ready/v1'
READY_KEYS = {'schema','session_nonce','proposal_id','target','executor_sha256',
'envelope_sha256','bao_health_identity_sha256','valid_until_epoch',
'receive_budget_seconds'}
def finite(value):
try:
return type(value) in (int,float) and math.isfinite(value)
except (OverflowError,ValueError):
return False
def endpoint(fd, writable):
need(type(fd) is int and fd >= 3, 'private_pipe_fd_required')
try:
identity = os.fstat(fd)
mode = fcntl.fcntl(fd,fcntl.F_GETFL) & os.O_ACCMODE
need(stat.S_ISFIFO(identity.st_mode) and mode ==
(os.O_WRONLY if writable else os.O_RDONLY), 'private_pipe_fd_required')
for standard in (0,1,2):
try:
current = os.fstat(standard)
except OSError:
continue
need((identity.st_dev,identity.st_ino) != (current.st_dev,current.st_ino),
'stdio_pipe_alias_refused')
return identity.st_dev,identity.st_ino
except OSError:
raise Refused('private_pipe_fd_required') from None
def wait_ready(fd, expected):
need(isinstance(expected,dict) and set(expected) == READY_KEYS - {'schema','receive_budget_seconds'},
'expected_child_pins_required')
need(finite(expected['valid_until_epoch']) and expected['valid_until_epoch'] > time.time(),
'ready_window_expired')
raw = b''
while len(raw) < 4096:
chunk = os.read(fd,1)
need(chunk, 'child_ready_missing')
if chunk == b'\n':
break
raw += chunk
else:
raise Refused('child_ready_oversized')
marker = decode(raw)
need(isinstance(marker,dict) and set(marker) == READY_KEYS
and marker.get('schema') == READY_SCHEMA, 'child_ready_invalid')
need(all(marker.get(key) == value for key,value in expected.items()), 'child_ready_mismatch')
need(finite(marker['valid_until_epoch']) and finite(marker['receive_budget_seconds'])
and 0 < marker['receive_budget_seconds'] <= 15
and marker['valid_until_epoch'] > time.time(),
'ready_window_expired')
return marker
def claims(token, kind, now):
need(isinstance(token, str) and 0 < len(token) <= MAX_TOKEN, 'invalid_token_shape')
parts = token.split('.')
need(len(parts) == 3 and all(parts), 'invalid_token_shape')
try:
obj = decode(base64.urlsafe_b64decode(parts[1] + '=' * (-len(parts[1]) % 4)))
need(isinstance(obj, dict), 'invalid_token_shape')
exp, iat = obj.get('exp'), obj.get('iat')
need(type(exp) in (int,float) and type(iat) in (int,float)
and math.isfinite(exp) and math.isfinite(iat)
and iat <= now + 30 and iat < exp and exp >= now + 300, 'token_window_invalid')
need(obj.get('iss') == 'https://kc.coulomb.social', 'token_source_invalid')
if kind == 'human':
need(obj.get('principal_type') == 'human'
and obj.get('aud') == 'netkingdom-bootstrap-console'
and isinstance(obj.get('sub'), str) and obj['sub'], 'human_shape_invalid')
assurance = obj.get('assurance', {})
need(isinstance(assurance,dict) and assurance.get('level') == 'aal2'
and assurance.get('mfa') is True, 'human_mfa_shape_invalid')
else:
need(obj.get('principal_type') == 'service'
and obj.get('aud') == 'codex-railiance-platform'
and obj.get('sub') == 'service:codex:railiance-platform'
and obj.get('tenant') == 'tenant:platform'
and obj.get('roles') == ['coding-agent']
and obj.get('scope') == 'openbao:login', 'coding_agent_shape_invalid')
except Refused:
raise
except Exception:
raise Refused('invalid_token_shape') from None
return token
def load(path, kind, now):
p = Path(path)
need(p.is_absolute() and p.parent.resolve() == p.parent, 'private_path_required')
need(not any((ancestor / '.git').is_file() or (ancestor / '.git' / 'HEAD').exists()
for ancestor in p.parents), 'git_path_refused')
directory = os.open(p.parent, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
try:
ds = os.fstat(directory)
need(ds.st_uid == os.getuid() and stat.S_IMODE(ds.st_mode) == 0o700,
'private_directory_required')
fd = os.open(p.name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=directory)
try:
original = os.fstat(fd)
need(stat.S_ISREG(original.st_mode) and original.st_uid == os.getuid()
and stat.S_IMODE(original.st_mode) == 0o600 and original.st_nlink == 1
and 0 < original.st_size <= MAX_FILE, 'private_file_required')
raw = b''
while len(raw) <= MAX_FILE:
chunk = os.read(fd, MAX_FILE + 1 - len(raw))
if not chunk:
break
raw += chunk
need(len(raw) <= MAX_FILE, 'private_file_oversized')
after = os.fstat(fd)
need((original.st_size,original.st_mtime_ns,original.st_ctime_ns) ==
(after.st_size,after.st_mtime_ns,after.st_ctime_ns), 'private_file_changed')
obj = decode(raw)
need(isinstance(obj,dict) and obj.get('token_type','').lower() == 'bearer',
'invalid_cli_token_file')
token = claims(obj.get('access_token'), kind, now)
return token, directory, p.name, original
finally:
os.close(fd)
except BaseException:
os.close(directory)
raise
def consume(item):
# Comparison is not atomic inode-conditioned unlink. Continuous exclusive
# same-UID directory custody is mandatory; concurrent writers are outside scope.
_, directory, name, original = item
current = os.stat(name, dir_fd=directory, follow_symlinks=False)
need((current.st_dev,current.st_ino,current.st_uid,current.st_nlink,current.st_size,
current.st_mtime_ns,current.st_ctime_ns) ==
(original.st_dev,original.st_ino,original.st_uid,original.st_nlink,original.st_size,
original.st_mtime_ns,original.st_ctime_ns), 'private_file_changed')
os.unlink(name, dir_fd=directory)
def deliver(human_path, agent_path, fd, *, ready_fd=None, expected=None,
consume_owner_files=False, budget=5):
receipt = {'adapter_performs_native_backend_actions': False, 'native_accepted': False,
'private_input_delivery_confirmed': False, 'caller_path_removal_completed': False,
'exclusive_same_uid_custody_required': True, 'atomic_inode_delete_guaranteed': False,
'child_ready_matched': False,
'credential_files_remain_possible': True, 'credential_copy_cleanup_verified': False,
'private_input_delivery_unknown': False}
items = []
writing = False
try:
need(consume_owner_files is True, 'explicit_owner_file_consumption_required')
data_identity = endpoint(fd,True)
control_identity = endpoint(ready_fd,False)
need(data_identity != control_identity, 'data_control_pipe_alias_refused')
need(isinstance(expected,dict) and finite(expected.get('valid_until_epoch')),
'expected_child_pins_required')
budget = min(budget, expected['valid_until_epoch'] - time.time())
with deadline(budget):
marker = wait_ready(ready_fd,expected)
receipt['child_ready_matched'] = True
remaining_alarm = signal.getitimer(signal.ITIMER_REAL)[0]
remaining = min(remaining_alarm, marker['receive_budget_seconds'],
expected['valid_until_epoch'] - time.time())
need(remaining > 0, 'ready_window_expired')
# Clip the existing timer; never restart or extend its original budget.
signal.setitimer(signal.ITIMER_REAL, remaining)
delivery_deadline = time.monotonic() + remaining
now = time.time()
items.append(load(human_path, 'human', now))
items.append(load(agent_path, 'coding-agent', now))
need((items[0][3].st_dev,items[0][3].st_ino) !=
(items[1][3].st_dev,items[1][3].st_ino), 'distinct_files_required')
payload = json.dumps({'human_token':items[0][0], 'coding_agent_token':items[1][0]},
separators=(',', ':')).encode() + b'\n'
# Unlink inspected caller-owned inodes; Python memory is not a zeroization guarantee.
need(time.time() < expected['valid_until_epoch'] and
time.monotonic() < delivery_deadline, 'ready_window_expired')
for item in items:
consume(item)
receipt.update(caller_path_removal_completed=True)
writing = True
offset = 0
while offset < len(payload):
need(time.time() < expected['valid_until_epoch'] and
time.monotonic() < delivery_deadline, 'ready_window_expired')
written = os.write(fd, payload[offset:])
need(written > 0, 'private_delivery_failed')
offset += written
need(time.time() < expected['valid_until_epoch'] and
time.monotonic() < delivery_deadline, 'ready_window_expired')
receipt['private_input_delivery_confirmed'] = True
except Refused as error:
receipt['failure_code'] = str(error)
except Exception:
receipt['failure_code'] = 'private_delivery_failed'
finally:
if writing and not receipt['private_input_delivery_confirmed']:
receipt['private_input_delivery_unknown'] = True
for item in items:
os.close(item[1])
# Launcher owns these endpoints: EOF even after partial delivery.
for owned in {fd,ready_fd}:
if type(owned) is int and owned >= 3:
try:
os.close(owned)
except OSError:
pass
return receipt
# Deliberately no standalone ready-file/ready-boolean CLI. Only the reviewed
# source launcher supplies its own captured child-control endpoint and exact pins.

View file

@ -0,0 +1,238 @@
#!/usr/bin/env python3
"""Founder-held, source-pinned direct SSH launcher; no credentials on normal IO.
Ready marker is a procedural readiness check, NEVER authenticated live authority.
Use only after exact source/host/transport/client/custody/file allowance admission.
"""
import argparse
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import re
import secrets
import shlex
import subprocess
import stat
import time
ADAPTER = Path(__file__).with_name('openbao_negative_private_handoff.py')
spec = importlib.util.spec_from_file_location('private_handoff', ADAPTER)
handoff = importlib.util.module_from_spec(spec)
spec.loader.exec_module(handoff)
PROPOSAL = 'KEY-WP-0039-T02/attended-lifecycle-v9-ready-input'
TARGET = 'sso/keycape'
PREPARATION_TOTAL_SECONDS = 5
MAX_PUBLIC_BYTES = 65536
MAX_SOURCE_BYTES = 262144
CONTRACT_KEYS = {'schema','proposal_id','target','remote_host','remote_wrapper_path',
'remote_wrapper_sha256','remote_child_path','remote_child_sha256','remote_envelope_path',
'local_envelope_path','remote_receipt_path','founder_decision_id',
'private_tmpfs_file_allowance_receipt','local_launcher_sha256','local_adapter_sha256'}
def read_stable(path, limit):
# Always called under the shared preparation timer in the actual CLI graph.
# NONBLOCK + regular-file check refuses FIFO/device. Resolution refuses
# observed symlink ancestors; metadata compares detect observed source drift.
p = Path(path)
handoff.need(p.is_absolute() and p.resolve() == p, 'source_regular_path_required')
fd = os.open(p,os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
try:
before = os.fstat(fd)
handoff.need(stat.S_ISREG(before.st_mode) and before.st_nlink == 1
and not stat.S_IMODE(before.st_mode) & 0o022
and 0 < before.st_size <= limit, 'source_file_invalid')
chunks,size = [],0
while size <= limit:
chunk = os.read(fd,min(4096,limit+1-size))
if not chunk:
break
size += len(chunk)
handoff.need(size <= limit,'source_file_oversized')
chunks.append(chunk)
after = os.fstat(fd)
fields = lambda v:(v.st_dev,v.st_ino,v.st_uid,v.st_mode,v.st_nlink,
v.st_size,v.st_mtime_ns,v.st_ctime_ns)
handoff.need(fields(before) == fields(after) and size == before.st_size,
'source_file_changed')
return b''.join(chunks)
finally:
os.close(fd)
def digest(path):
return hashlib.sha256(read_stable(path,MAX_SOURCE_BYTES)).hexdigest()
def remaining_preparation(preparation_deadline):
handoff.need(handoff.finite(preparation_deadline),'preparation_window_invalid')
remaining = preparation_deadline-time.monotonic()
handoff.need(0 < remaining <= PREPARATION_TOTAL_SECONDS,'preparation_window_expired')
return remaining
def pin(value):
return isinstance(value,str) and re.fullmatch('[0-9a-f]{64}',value) is not None
def remote_path(value):
handoff.need(isinstance(value,str) and len(value) <= 256
and re.fullmatch('/[A-Za-z0-9_./-]+',value) is not None
and '..' not in Path(value).parts and not value.endswith('/'), 'remote_path_invalid')
return value
def read_public(path):
raw = read_stable(path,MAX_PUBLIC_BYTES)
obj = handoff.decode(raw)
handoff.need(isinstance(obj,dict),'source_contract_invalid')
return raw,obj
def validate_contract(contract):
handoff.need(isinstance(contract,dict) and set(contract) == CONTRACT_KEYS
and contract['schema'] == 'key39-private-launch-contract/v1'
and contract['proposal_id'] == PROPOSAL and contract['target'] == TARGET
and contract['remote_host'] == 'railiance01','source_contract_invalid')
for field in ('remote_wrapper_path','remote_child_path','remote_envelope_path','remote_receipt_path'):
remote_path(contract[field])
handoff.need(len({contract[key] for key in ('remote_wrapper_path','remote_child_path',
'remote_envelope_path','remote_receipt_path')}) == 4,'remote_paths_must_differ')
for field in ('remote_wrapper_sha256','remote_child_sha256','local_launcher_sha256','local_adapter_sha256'):
handoff.need(pin(contract[field]),'source_pin_required')
handoff.need(digest(__file__) == contract['local_launcher_sha256']
and digest(ADAPTER) == contract['local_adapter_sha256'],'local_source_pin_changed')
handoff.need(all(isinstance(contract[k],str) and 0 < len(contract[k]) <= 256
for k in ('founder_decision_id','private_tmpfs_file_allowance_receipt')),
'founder_receipt_required')
raw,envelope = read_public(contract['local_envelope_path'])
handoff.need(envelope.get('proposal_id') == PROPOSAL and envelope.get('target') == TARGET
and envelope.get('disposition') == 'approved'
and envelope.get('founder_decision_id') == contract['founder_decision_id'],
'source_envelope_mismatch')
expiry = envelope.get('valid_until_epoch')
window = envelope.get('maximum_session_seconds')
handoff.need(handoff.finite(expiry) and type(window) is int and 420 <= window <= 900
and 0 < expiry-time.time() <= window,'source_window_invalid')
health = envelope.get('bao_health_identity_sha256')
handoff.need(pin(health),'source_health_pin_required')
hashes = envelope.get('source_hashes',{})
handoff.need(isinstance(hashes,dict) and
hashes.get(contract['remote_child_path']) == contract['remote_child_sha256'] and
hashes.get(contract['remote_wrapper_path']) == contract['remote_wrapper_sha256'],
'remote_source_pin_missing')
owners = envelope.get('owner_acknowledgments',{})
handoff.need(isinstance(owners,dict) and all(isinstance(owners.get(k),str) and owners[k]
for k in ('key-cape','net-kingdom','railiance-platform')),'owner_source_receipts_required')
return hashlib.sha256(raw).hexdigest(),envelope
def launch_and_deliver(contract,human_path,agent_path,*,consume_owner_files=False,
preparation_deadline=None):
receipt = {'native_accepted':False,'authenticated_authority_established_by_helper':False,
'child_ready_matched':False,'private_input_delivery_confirmed':False,
'consumer_process_completed':False,'consumer_outcome_unknown':False}
process = None
owned_fds = set()
if preparation_deadline is None:
preparation_deadline = time.monotonic() + PREPARATION_TOTAL_SECONDS
try:
with handoff.deadline(remaining_preparation(preparation_deadline)):
envelope_hash,envelope = validate_contract(contract)
nonce = secrets.token_hex(32)
expected = {'session_nonce':nonce,'proposal_id':PROPOSAL,'target':TARGET,
'executor_sha256':contract['remote_child_sha256'],'envelope_sha256':envelope_hash,
'bao_health_identity_sha256':envelope['bao_health_identity_sha256'],
'valid_until_epoch':envelope['valid_until_epoch']}
command = ['python3',contract['remote_wrapper_path'],
'--child',contract['remote_child_path'],'--child-sha256',contract['remote_child_sha256'],
'--envelope',contract['remote_envelope_path'],'--envelope-sha256',envelope_hash,
'--receipt',contract['remote_receipt_path'],'--session-nonce',nonce]
argv = ['ssh','-T','-oBatchMode=yes','-oStrictHostKeyChecking=yes',
'-oForwardAgent=no','-oClearAllForwardings=yes','-oConnectTimeout=5',
'-oServerAliveInterval=5','-oServerAliveCountMax=1',
'railiance01',shlex.join(command)]
# Do not pass arbitrary confidential producer environment to SSH.
allowed = ('PATH','HOME','USER','LOGNAME','LANG','LC_ALL','SSH_AUTH_SOCK')
environment = {key:os.environ[key] for key in allowed if key in os.environ}
process = subprocess.Popen(argv,stdin=subprocess.PIPE,stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,env=environment,close_fds=True)
remaining_preparation(preparation_deadline)
# Distinct process-owned pipes; no arbitrary caller ready file or boolean.
write_fd = os.dup(process.stdin.fileno()); owned_fds.add(write_fd)
ready_fd = os.dup(process.stdout.fileno()); owned_fds.add(ready_fd)
process.stdin.close()
# Close parent's duplicate read endpoint; only owned ready_fd is used.
process.stdout.close()
delivery = handoff.deliver(human_path,agent_path,write_fd,ready_fd=ready_fd,
expected=expected,consume_owner_files=consume_owner_files,
budget=remaining_preparation(preparation_deadline))
owned_fds.clear() # deliver owns and closes both endpoints
receipt.update(delivery)
# Private bytes may already have reached the remote child even if local
# write completion/EOF confirmation failed. Local SSH teardown proves no
# remote no-effects or cleanup outcome; never clear this unknown here.
if delivery['private_input_delivery_unknown']:
receipt['consumer_outcome_unknown'] = True
receipt['consumer_process_completed'] = False
if not delivery['private_input_delivery_confirmed']:
return receipt
# Value-free exit status only; child receipt and native acceptance remain owner duties.
wait_budget = max(0,min(envelope['valid_until_epoch']-time.time(),
envelope['maximum_session_seconds']-180)) + 330
try:
rc = process.wait(timeout=wait_budget)
except subprocess.TimeoutExpired:
receipt.update(failure_code='consumer_completion_unconfirmed',consumer_outcome_unknown=True)
return receipt
receipt['consumer_process_completed'] = rc == 0
receipt['consumer_outcome_unknown'] = rc != 0
if rc != 0:
receipt['failure_code'] = 'consumer_completion_unconfirmed'
except handoff.Refused as error:
receipt['failure_code'] = str(error)
except Exception:
receipt['failure_code'] = 'private_launcher_incomplete'
if receipt['private_input_delivery_confirmed']:
receipt['consumer_outcome_unknown'] = True
finally:
for fd in owned_fds:
try:
os.close(fd)
except OSError:
pass
if process is not None:
# Local teardown never claims remote process/custody reconciliation.
try:
if process.poll() is None:
process.terminate()
try:
process.wait(timeout=1)
except subprocess.TimeoutExpired:
process.kill()
process.wait(timeout=1)
for stream in (process.stdin,process.stdout):
if stream is not None:
stream.close()
except Exception:
receipt['transport_cleanup_unconfirmed'] = True
receipt['consumer_outcome_unknown'] = True
return receipt
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--contract',required=True)
parser.add_argument('--human-file',required=True)
parser.add_argument('--agent-file',required=True)
parser.add_argument('--consume-owner-files',action='store_true')
args = parser.parse_args()
preparation_deadline = time.monotonic() + PREPARATION_TOTAL_SECONDS
try:
with handoff.deadline(remaining_preparation(preparation_deadline)):
_,contract = read_public(args.contract)
receipt = launch_and_deliver(contract,args.human_file,args.agent_file,
consume_owner_files=args.consume_owner_files,preparation_deadline=preparation_deadline)
except handoff.Refused as error:
receipt = {'native_accepted':False,'private_input_delivery_confirmed':False,
'failure_code':str(error)}
except Exception:
receipt = {'native_accepted':False,'private_input_delivery_confirmed':False,
'failure_code':'private_launcher_contract_invalid'}
print(json.dumps(receipt,separators=(',',':')))
return 0 if receipt.get('consumer_process_completed') is True else 1
if __name__ == '__main__':
raise SystemExit(main())

View file

@ -0,0 +1,228 @@
import base64
import importlib.util
import json
import os
from pathlib import Path
import signal
import tempfile
import time
import unittest
from unittest.mock import patch
REAL_WRITE=os.write
spec = importlib.util.spec_from_file_location('handoff',Path(__file__).with_name('openbao_negative_private_handoff.py'))
s = importlib.util.module_from_spec(spec);spec.loader.exec_module(s)
def jwt(kind='human', **changes):
obj={'iss':'https://kc.coulomb.social','iat':time.time()-1,'exp':time.time()+700,
'principal_type':'human','aud':'netkingdom-bootstrap-console','sub':'fixture-person',
'assurance':{'level':'aal2','mfa':True}}
if kind == 'agent':
obj.update(principal_type='service',aud='codex-railiance-platform',
sub='service:codex:railiance-platform',tenant='tenant:platform',
roles=['coding-agent'],scope='openbao:login')
obj.update(changes)
body=base64.urlsafe_b64encode(json.dumps(obj).encode()).decode().rstrip('=')
return 'fixture.'+body+'.fixture'
class Tests(unittest.TestCase):
def setUp(self):
self.tmp=tempfile.TemporaryDirectory();self.dir=Path(self.tmp.name)
self.h=self.dir/'human.json';self.a=self.dir/'agent.json'
self.write(self.h,jwt());self.write(self.a,jwt('agent'))
def tearDown(self):
self.tmp.cleanup()
def write(self,p,token):
p.write_text(json.dumps({'access_token':token,'token_type':'Bearer','expires_in':700}));p.chmod(0o600)
def run_delivery(self,**kw):
r,w=os.pipe();cr,cw=os.pipe()
expected=self.expected()
REAL_WRITE(cw,json.dumps(dict(expected,schema=s.READY_SCHEMA,receive_budget_seconds=10)).encode()+b'\n')
os.close(cw)
receipt=s.deliver(kw.pop("human_path",str(self.h)),str(self.a),w,ready_fd=cr,expected=expected,consume_owner_files=True,**kw)
raw=os.read(r,65536);os.close(r)
return receipt,raw
def expected(self):
return {'session_nonce':'1'*64,'proposal_id':'KEY-WP-0039-T02/attended-lifecycle-v9-ready-input',
'target':'sso/keycape','executor_sha256':'2'*64,'envelope_sha256':'3'*64,
'bao_health_identity_sha256':'4'*64,'valid_until_epoch':time.time()+600}
def test_success_only_private_pipe_and_consumes_owned_files(self):
receipt,raw=self.run_delivery()
obj=json.loads(raw)
self.assertEqual(set(obj),{'human_token','coding_agent_token'})
self.assertTrue(receipt['private_input_delivery_confirmed'])
self.assertFalse(receipt['native_accepted'])
self.assertNotIn('fixture',json.dumps(receipt))
self.assertFalse(self.h.exists());self.assertFalse(self.a.exists())
def test_stdout_stderr_and_regular_fd_refused_before_file_consumption(self):
for fd in (1,2):
receipt=s.deliver(str(self.h),str(self.a),fd,consume_owner_files=True)
self.assertEqual(receipt['failure_code'],'private_pipe_fd_required')
with tempfile.TemporaryFile() as f:
dup=os.dup(f.fileno())
receipt=s.deliver(str(self.h),str(self.a),dup,consume_owner_files=True)
self.assertEqual(receipt['failure_code'],'private_pipe_fd_required')
self.assertEqual(f.tell(),0)
self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
def test_read_only_pipe_refused_before_consuming_files(self):
r,w=os.pipe()
receipt=s.deliver(str(self.h),str(self.a),r,consume_owner_files=True)
os.close(w)
self.assertEqual(receipt['failure_code'],'private_pipe_fd_required')
self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
def test_git_worktree_refused_before_delivery(self):
marker=self.dir/'.git';marker.write_text('gitdir: fixture')
receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'git_path_refused');self.assertFalse(raw)
def test_symlinked_parent_refused(self):
alias=self.dir/'alias';alias.symlink_to(self.dir,target_is_directory=True)
receipt,raw=self.run_delivery(human_path=str(alias/'human.json'))
self.assertEqual(receipt['failure_code'],'private_path_required')
self.assertFalse(raw);self.assertTrue(self.h.exists())
def test_explicit_consumption_required(self):
r,w=os.pipe();receipt=s.deliver(str(self.h),str(self.a),w)
self.assertEqual(receipt['failure_code'],'explicit_owner_file_consumption_required')
self.assertEqual(os.read(r,10),b'');os.close(r);self.assertTrue(self.h.exists())
def test_symlink_refused_no_delivery(self):
target=self.dir/'target';self.h.rename(target);self.h.symlink_to(target)
receipt,raw=self.run_delivery();self.assertFalse(raw)
self.assertFalse(receipt['private_input_delivery_confirmed']);self.assertTrue(target.exists())
def test_hardlinked_file_refused(self):
os.link(self.h,self.dir/'extra');receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_file_required');self.assertFalse(raw)
def test_public_mode_refused(self):
self.a.chmod(0o644);receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_file_required');self.assertFalse(raw)
def test_public_directory_refused(self):
self.dir.chmod(0o755);receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_directory_required');self.assertFalse(raw)
def test_oversize_file_refused_before_delivery(self):
self.a.write_bytes(b'x'*(s.MAX_FILE+1));receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_file_required');self.assertFalse(raw)
def test_wrong_human_audience_or_missing_mfa_refused(self):
for changes in ({'aud':'openbao-admin'},{'assurance':{'level':'aal1','mfa':False}}):
self.write(self.h,jwt(**changes));receipt,raw=self.run_delivery()
self.assertFalse(raw);self.assertFalse(receipt['private_input_delivery_confirmed'])
def test_approle_string_or_wrong_coding_claim_refused(self):
for token in ('hvs.not-a-jwt',jwt('agent',tenant='tenant:coulomb'),jwt('agent',roles=['secrets-engine'])):
self.write(self.a,token);receipt,raw=self.run_delivery()
self.assertFalse(raw);self.assertFalse(receipt['private_input_delivery_confirmed'])
def test_expired_bool_or_infinite_timestamp_refused(self):
for expiry in (time.time()-1,True,float('inf')):
self.write(self.a,jwt('agent',exp=expiry));receipt,raw=self.run_delivery()
self.assertFalse(raw);self.assertFalse(receipt['private_input_delivery_confirmed'])
def test_duplicate_json_refused(self):
self.a.write_text('{"token_type":"Bearer","access_token":"a","access_token":"b"}')
receipt,raw=self.run_delivery();self.assertEqual(receipt['failure_code'],'duplicate_json_key');self.assertFalse(raw)
def test_file_replacement_before_consumption_not_unlinked(self):
original=s.consume
def replace(item):
self.h.unlink();self.write(self.h,jwt())
return original(item)
with patch.object(s,'consume',side_effect=replace):receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_file_changed');self.assertFalse(raw);self.assertTrue(self.h.exists())
def test_blocked_partial_write_is_bounded_unknown_and_timer_restored(self):
previous=signal.getsignal(signal.SIGALRM);started=time.monotonic()
with patch.object(s.os,'write',side_effect=lambda *args:time.sleep(0.1)):
receipt,raw=self.run_delivery(budget=0.01)
self.assertLess(time.monotonic()-started,0.06)
self.assertEqual(receipt['failure_code'],'delivery_timeout')
self.assertTrue(receipt['private_input_delivery_unknown']);self.assertFalse(raw)
self.assertFalse(self.h.exists());self.assertFalse(self.a.exists())
self.assertEqual(signal.getitimer(signal.ITIMER_REAL),(0.0,0.0));self.assertIs(signal.getsignal(signal.SIGALRM),previous)
def test_broken_pipe_fixed_error_no_raw_exception(self):
with patch.object(s.os,'write',side_effect=RuntimeError('protected raw value')):
receipt,raw=self.run_delivery()
self.assertEqual(receipt['failure_code'],'private_delivery_failed')
self.assertTrue(receipt['private_input_delivery_unknown']);self.assertNotIn('protected',json.dumps(receipt));self.assertFalse(raw)
if __name__ == '__main__':unittest.main()
class ReadyTests(unittest.TestCase):
setUp=Tests.setUp
tearDown=Tests.tearDown
write=Tests.write
expected=Tests.expected
run_delivery=Tests.run_delivery
# Concrete ready-channel counterexamples; base safety cases run only once.
def with_marker(self, marker, budget=0.05):
r,w=os.pipe();cr,cw=os.pipe();expected=self.expected()
raw=marker(expected) if callable(marker) else marker
REAL_WRITE(cw,raw);os.close(cw)
with patch.object(s,'load',wraps=s.load) as load:
receipt=s.deliver(str(self.h),str(self.a),w,ready_fd=cr,expected=expected,
consume_owner_files=True,budget=budget)
calls=load.call_count
data=os.read(r,65536);os.close(r)
return receipt,data,calls
def test_no_child_ready_or_mismatch_means_zero_file_load_and_private_bytes(self):
for marker in (b'', b'not-json\n', lambda e:json.dumps(dict(e,schema=s.READY_SCHEMA,
receive_budget_seconds=10,session_nonce='0'*64)).encode()+b'\n',
lambda e:json.dumps(dict(e,schema=s.READY_SCHEMA,receive_budget_seconds=True)).encode()+b'\n'):
receipt,data,calls=self.with_marker(marker)
self.assertFalse(receipt['private_input_delivery_confirmed']);self.assertFalse(data)
self.assertEqual(calls,0);self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
def test_no_ready_eof_hard_timeout_zero_file_load_or_consumption(self):
r,w=os.pipe();cr,cw=os.pipe();started=time.monotonic()
try:
with patch.object(s,'load') as load:
receipt=s.deliver(str(self.h),str(self.a),w,ready_fd=cr,expected=self.expected(),
consume_owner_files=True,budget=0.01)
load.assert_not_called()
self.assertLess(time.monotonic()-started,0.06)
self.assertEqual(receipt['failure_code'],'delivery_timeout');self.assertFalse(os.read(r,10))
self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
finally:os.close(cw);os.close(r)
def test_stdout_and_stderr_pipe_duplicates_refused(self):
for standard in (1,2):
r,w=os.pipe();backup=os.dup(standard)
try:
os.dup2(w,standard);duplicate=os.dup(standard)
receipt=s.deliver(str(self.h),str(self.a),duplicate,consume_owner_files=True)
finally:os.dup2(backup,standard);os.close(backup);os.close(w)
self.assertEqual(receipt['failure_code'],'stdio_pipe_alias_refused')
self.assertEqual(os.read(r,10),b'');os.close(r)
self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
def test_data_and_control_same_pipe_refused(self):
r,w=os.pipe();readback=os.dup(r)
receipt=s.deliver(str(self.h),str(self.a),w,ready_fd=r,expected=self.expected(),consume_owner_files=True)
self.assertEqual(receipt['failure_code'],'data_control_pipe_alias_refused')
self.assertEqual(os.read(readback,10),b'');os.close(readback)
def test_oversize_ready_refused_before_load(self):
receipt,data,calls=self.with_marker(b'x'*4096+b'\n')
self.assertEqual(receipt['failure_code'],'child_ready_oversized');self.assertFalse(data);self.assertEqual(calls,0)
def test_received_short_budget_clips_timer_before_token_load(self):
marker=lambda e:json.dumps(dict(e,schema=s.READY_SCHEMA,receive_budget_seconds=0.01)).encode()+b'\n'
original=s.load
def delayed(*args):time.sleep(0.1);return original(*args)
started=time.monotonic()
with patch.object(s,'load',side_effect=delayed):receipt,data,calls=self.with_marker(marker)
self.assertLess(time.monotonic()-started,0.06);self.assertFalse(data)
self.assertEqual(receipt['failure_code'],'delivery_timeout');self.assertTrue(self.h.exists())
def test_real_partial_write_stays_unknown_and_conservative_cleanup(self):
import fcntl
self.write(self.h,jwt(padding='h'*7000));self.write(self.a,jwt('agent',padding='a'*7000))
r,w=os.pipe();fcntl.fcntl(w,fcntl.F_SETPIPE_SZ,4096)
cr,cw=os.pipe();e=self.expected();REAL_WRITE(cw,json.dumps(dict(e,schema=s.READY_SCHEMA,
receive_budget_seconds=10)).encode()+b'\n');os.close(cw)
receipt=s.deliver(str(self.h),str(self.a),w,ready_fd=cr,expected=e,consume_owner_files=True,budget=0.015)
data=os.read(r,65536);os.close(r)
self.assertEqual(len(data),4096);self.assertTrue(receipt['private_input_delivery_unknown'])
self.assertFalse(receipt['private_input_delivery_confirmed'])
self.assertTrue(receipt['credential_files_remain_possible'])
self.assertFalse(receipt['credential_copy_cleanup_verified'])
def test_stat_unlink_race_retained_as_exclusive_custody_violation_not_atomic_claim(self):
original=s.os.stat;replaced=[]
def race(path,*args,**kwargs):
current=original(path,*args,**kwargs)
if path=='human.json' and kwargs.get('dir_fd') is not None and not replaced:
self.h.unlink();self.write(self.h,jwt(sub='replacement-fixture'))
replaced.append(True)
return current
with patch.object(s.os,'stat',side_effect=race):receipt,data=self.run_delivery()
self.assertTrue(replaced);self.assertFalse(self.h.exists())
self.assertTrue(receipt['caller_path_removal_completed'])
self.assertFalse(receipt['atomic_inode_delete_guaranteed'])
self.assertTrue(receipt['exclusive_same_uid_custody_required'])
self.assertTrue(receipt['credential_files_remain_possible'])
self.assertFalse(receipt['credential_copy_cleanup_verified'])

View file

@ -0,0 +1,145 @@
import importlib.util
import json
import os
from pathlib import Path
import shlex
import tempfile
import time
import unittest
from unittest.mock import patch
spec=importlib.util.spec_from_file_location('launcher',Path(__file__).with_name('openbao_negative_private_launcher.py'))
l=importlib.util.module_from_spec(spec);spec.loader.exec_module(l)
spec=importlib.util.spec_from_file_location('fixtures',Path(__file__).with_name('test_openbao_negative_private_handoff.py'))
f=importlib.util.module_from_spec(spec);spec.loader.exec_module(f)
class FakeProcess:
def __init__(self,argv,contract,envelope_hash,envelope,marker='valid'):
self.argv=argv;self.rc=None;self.terminated=False;self.waits=[]
self.read_data,w=os.pipe();self.stdin=os.fdopen(w,'wb',buffering=0)
r,cw=os.pipe();self.stdout=os.fdopen(r,'rb',buffering=0)
args=shlex.split(argv[-1]);nonce=args[args.index('--session-nonce')+1]
ready={'schema':'key39-private-input-ready/v1','session_nonce':nonce,
'proposal_id':l.PROPOSAL,'target':l.TARGET,'executor_sha256':contract['remote_child_sha256'],
'envelope_sha256':envelope_hash,'bao_health_identity_sha256':envelope['bao_health_identity_sha256'],
'valid_until_epoch':envelope['valid_until_epoch'],'receive_budget_seconds':15}
if marker=='wrong':ready['session_nonce']='0'*64
if marker!='missing':os.write(cw,json.dumps(ready).encode()+b'\n')
os.close(cw)
def wait(self,timeout):
self.waits.append(timeout);self.rc=-15 if self.terminated else 0;return self.rc
def poll(self):return self.rc
def terminate(self):self.terminated=True
def kill(self):self.terminated=True
class Tests(unittest.TestCase):
def setUp(self):
self.tmp=tempfile.TemporaryDirectory();self.dir=Path(self.tmp.name)
self.h=self.dir/'human.json';self.a=self.dir/'agent.json'
for p,token in ((self.h,f.jwt()),(self.a,f.jwt('agent'))):
p.write_text(json.dumps({'access_token':token,'token_type':'Bearer'}));p.chmod(0o600)
self.envelope={'proposal_id':l.PROPOSAL,'target':l.TARGET,'disposition':'approved',
'founder_decision_id':'fixture-founder','valid_until_epoch':time.time()+600,
'maximum_session_seconds':900,'bao_health_identity_sha256':'4'*64,
'source_hashes':{'/run/key39/child.py':'2'*64,'/run/key39/wrapper.py':'3'*64},
'owner_acknowledgments':{k:'fixture-source' for k in ('key-cape','net-kingdom','railiance-platform')}}
self.e=self.dir/'envelope.json';self.e.write_text(json.dumps(self.envelope))
self.contract={'schema':'key39-private-launch-contract/v1','proposal_id':l.PROPOSAL,
'target':l.TARGET,'remote_host':'railiance01','remote_wrapper_path':'/run/key39/wrapper.py',
'remote_wrapper_sha256':'3'*64,'remote_child_path':'/run/key39/child.py',
'remote_child_sha256':'2'*64,'remote_envelope_path':'/run/key39/approved.json',
'local_envelope_path':str(self.e),'remote_receipt_path':'/run/key39/receipt.json',
'founder_decision_id':'fixture-founder','private_tmpfs_file_allowance_receipt':'fixture-file-allowance',
'local_launcher_sha256':l.digest(l.__file__),'local_adapter_sha256':l.digest(l.ADAPTER)}
self.processes=[]
def tearDown(self):
for p in self.processes:
os.close(p.read_data)
self.tmp.cleanup()
def run_launcher(self,marker='valid'):
def popen(argv,**kwargs):
_,envelope=l.read_public(self.e)
self.assertEqual(kwargs['stdin'],l.subprocess.PIPE)
self.assertEqual(kwargs['stdout'],l.subprocess.PIPE)
self.assertEqual(kwargs['stderr'],l.subprocess.DEVNULL)
self.assertNotIn('KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET',kwargs['env'])
self.assertIn('-oStrictHostKeyChecking=yes',argv);self.assertIn('-T',argv)
p=FakeProcess(argv,self.contract,l.digest(self.e),envelope,marker);self.processes.append(p);return p
with patch.object(l.subprocess,'Popen',side_effect=popen) as spawn, \
patch.dict(os.environ,{'KEYCAPE_CODEX_RAILIANCE_PLATFORM_CLIENT_SECRET':'PRIVATE-FIXTURE'}):
receipt=l.launch_and_deliver(self.contract,str(self.h),str(self.a),consume_owner_files=True)
return receipt,spawn.call_count
def test_complete_pinned_child_marker_then_private_pipe_delivery_no_actual_ssh(self):
receipt,count=self.run_launcher();self.assertEqual(count,1)
self.assertTrue(receipt['child_ready_matched']);self.assertTrue(receipt['consumer_process_completed'])
self.assertFalse(receipt['native_accepted']);self.assertFalse(receipt['authenticated_authority_established_by_helper'])
raw=os.read(self.processes[0].read_data,65536);self.assertEqual(set(json.loads(raw)),{'human_token','coding_agent_token'})
self.assertNotIn('fixture-person',json.dumps(receipt));self.assertFalse(self.h.exists());self.assertFalse(self.a.exists())
def test_missing_or_wrong_marker_retains_files_and_writes_zero_tokens(self):
for marker in ('missing','wrong'):
receipt,count=self.run_launcher(marker)
self.assertEqual(count,1);self.assertFalse(receipt['child_ready_matched'])
self.assertEqual(os.read(self.processes[-1].read_data,65536),b'')
self.assertTrue(self.h.exists());self.assertTrue(self.a.exists())
def test_changed_local_source_pin_refuses_before_transport_and_file_read(self):
self.contract['local_adapter_sha256']='0'*64
receipt,count=self.run_launcher();self.assertEqual(count,0)
self.assertEqual(receipt['failure_code'],'local_source_pin_changed');self.assertTrue(self.h.exists())
def test_wrong_host_or_remote_command_path_refuses_before_transport(self):
for field,value in (('remote_host','other-node'),('remote_wrapper_path','/tmp/x;cat'),
('remote_child_path','/run/key39/../child.py')):
old=self.contract[field];self.contract[field]=value
receipt,count=self.run_launcher();self.contract[field]=old
self.assertEqual(count,0);self.assertFalse(receipt['private_input_delivery_confirmed']);self.assertTrue(self.h.exists())
def test_expired_or_wrong_founder_source_contract_no_spawn_no_file_access(self):
for key,value in (('valid_until_epoch',time.time()-1),('founder_decision_id','other')):
current=json.loads(self.e.read_text());current[key]=value;self.e.write_text(json.dumps(current))
receipt,count=self.run_launcher();self.assertEqual(count,0);self.assertTrue(self.h.exists())
self.e.write_text(json.dumps(self.envelope))
def test_full_pipe_payload_then_confirmation_timeout_keeps_remote_unknown(self):
original_deliver=l.handoff.deliver
original_write=os.write
def interrupted_delivery(*args,**kwargs):
kwargs['budget']=0.01
def write_then_stall(fd,payload):
written=original_write(fd,payload)
time.sleep(0.1)
return written
with patch.object(l.handoff.os,'write',side_effect=write_then_stall):
return original_deliver(*args,**kwargs)
with patch.object(l.handoff,'deliver',side_effect=interrupted_delivery):
receipt,count=self.run_launcher()
self.assertEqual(count,1)
data=os.read(self.processes[0].read_data,65536)
self.assertEqual(set(json.loads(data)),{'human_token','coding_agent_token'})
self.assertTrue(receipt['private_input_delivery_unknown'])
self.assertFalse(receipt['private_input_delivery_confirmed'])
self.assertTrue(receipt['consumer_outcome_unknown'])
self.assertFalse(receipt['consumer_process_completed'])
self.assertTrue(self.processes[0].terminated)
self.assertFalse(self.h.exists());self.assertFalse(self.a.exists())
self.assertFalse(receipt['native_accepted'])
def test_real_partial_pipe_write_unknown_is_sticky_after_local_terminate(self):
import fcntl
for p,token in ((self.h,f.jwt(padding='h'*7000)),(self.a,f.jwt('agent',padding='a'*7000))):
p.write_text(json.dumps({'access_token':token,'token_type':'Bearer'}));p.chmod(0o600)
original_process=FakeProcess
original_deliver=l.handoff.deliver
def small_pipe(*args,**kwargs):
proc=original_process(*args,**kwargs)
fcntl.fcntl(proc.stdin.fileno(),fcntl.F_SETPIPE_SZ,4096)
return proc
def bounded(*args,**kwargs):
kwargs['budget']=0.015
return original_deliver(*args,**kwargs)
with patch.dict(globals(),{'FakeProcess':small_pipe}),patch.object(l.handoff,'deliver',side_effect=bounded):
receipt,count=self.run_launcher()
data=os.read(self.processes[0].read_data,65536)
self.assertEqual(len(data),4096)
self.assertTrue(receipt['private_input_delivery_unknown'])
self.assertTrue(receipt['consumer_outcome_unknown'])
self.assertFalse(receipt['consumer_process_completed'])
self.assertTrue(self.processes[0].terminated)
self.assertFalse(receipt['native_accepted'])
if __name__=='__main__':unittest.main()

View file

@ -0,0 +1,91 @@
import importlib.util
import io
import json
import os
from pathlib import Path
import signal
import subprocess
import sys
import tempfile
import time
import unittest
from unittest.mock import patch
spec=importlib.util.spec_from_file_location('prep_launcher',Path(__file__).with_name('openbao_negative_private_launcher.py'))
l=importlib.util.module_from_spec(spec);spec.loader.exec_module(l)
class Tests(unittest.TestCase):
def actual_cli(self,path):
started=time.monotonic()
result=subprocess.run([sys.executable,l.__file__,'--contract',str(path),
'--human-file','/NEVER-READ-HUMAN','--agent-file','/NEVER-READ-AGENT'],
capture_output=True,timeout=0.4)
self.assertEqual(result.returncode,1);self.assertEqual(result.stderr,b'')
self.assertLess(time.monotonic()-started,0.25)
value=json.loads(result.stdout);self.assertFalse(value['native_accepted'])
self.assertFalse(value['private_input_delivery_confirmed'])
return value
def test_actual_main_fifo_refused_without_waiting_for_writer(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'contract.fifo';os.mkfifo(path,0o600)
self.assertEqual(self.actual_cli(path)['failure_code'],'source_file_invalid')
def test_actual_main_symlink_contract_refused(self):
with tempfile.TemporaryDirectory() as folder:
original=Path(folder)/'contract.json';original.write_text('{}')
path=Path(folder)/'alias';path.symlink_to(original)
self.assertEqual(self.actual_cli(path)['failure_code'],'source_regular_path_required')
def test_actual_main_oversize_contract_refused(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'contract.json';path.write_bytes(b'x'*(l.MAX_PUBLIC_BYTES+1))
self.assertEqual(self.actual_cli(path)['failure_code'],'source_file_invalid')
def main_with(self,path,**patches):
out=io.StringIO()
argv=['launcher','--contract',str(path),'--human-file','/NEVER-READ-HUMAN',
'--agent-file','/NEVER-READ-AGENT']
with patch.object(sys,'argv',argv),patch.object(sys,'stdout',out), \
patch.object(l.subprocess,'Popen') as spawn,patch.object(l.handoff,'load') as load:
rc=l.main();spawn.assert_not_called();load.assert_not_called()
self.assertEqual(rc,1)
return json.loads(out.getvalue())
def test_actual_main_slow_regular_read_has_hard_total_bound_and_signal_restore(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'contract.json';path.write_text('{}')
original=l.os.read
def slow(fd,size):time.sleep(0.1);return original(fd,size)
previous=signal.getsignal(signal.SIGALRM);started=time.monotonic()
with patch.object(l,'PREPARATION_TOTAL_SECONDS',0.01),patch.object(l.os,'read',side_effect=slow):
receipt=self.main_with(path)
self.assertEqual(receipt['failure_code'],'delivery_timeout')
self.assertLess(time.monotonic()-started,0.06)
self.assertEqual(signal.getitimer(signal.ITIMER_REAL),(0.0,0.0));self.assertIs(signal.getsignal(signal.SIGALRM),previous)
def test_actual_main_launch_does_not_renew_budget_spent_acquiring_contract(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'contract.json';path.write_text('{}')
original=l.read_public
def acquire(path):time.sleep(0.02);return original(path)
def slow_validate(contract):time.sleep(0.02);return '0'*64,{}
started=time.monotonic()
with patch.object(l,'PREPARATION_TOTAL_SECONDS',0.03), \
patch.object(l,'read_public',side_effect=acquire), \
patch.object(l,'validate_contract',side_effect=slow_validate):
receipt=self.main_with(path)
self.assertEqual(receipt['failure_code'],'delivery_timeout');self.assertLess(time.monotonic()-started,0.065)
def test_observed_source_change_refused_and_reads_are_bounded(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'contract.json';path.write_text('{}')
original=l.os.read;changed=[];sizes=[]
def mutate(fd,size):
sizes.append(size)
if not changed:path.write_text('{"x":1}');changed.append(True)
return original(fd,size)
with patch.object(l.os,'read',side_effect=mutate):
with self.assertRaisesRegex(l.handoff.Refused,'source_file_changed'):l.read_public(path)
self.assertTrue(all(0<size<=4096 for size in sizes))
def test_source_digest_fifo_and_symlink_refuse(self):
with tempfile.TemporaryDirectory() as folder:
path=Path(folder)/'source.fifo';os.mkfifo(path,0o600)
with self.assertRaisesRegex(l.handoff.Refused,'source_file_invalid'):l.digest(path)
regular=Path(folder)/'source.py';regular.write_text('fixture')
alias=Path(folder)/'alias';alias.symlink_to(regular)
with self.assertRaisesRegex(l.handoff.Refused,'source_regular_path_required'):l.digest(alias)
if __name__=='__main__':unittest.main()

View file

@ -145,6 +145,7 @@ operator/ESO capability and nonmember checks remain independent acceptance.
id: KEY-WP-0039-T03
status: done
priority: medium
state_hub_task_id: "54d37ad8-2352-51c2-bb2e-af6070dbbd73"
```
2026-10-11: Completed KeyCape's own issuer-source inspection for
@ -231,3 +232,66 @@ SHA256 ba872dc53061b1dcca9dea1e8897597c394c1f9365e0fc49ee6f2095f57f11e0
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 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.