Bind native OpenRouter approval to custody and delivery inputs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 5s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a09cbb-87c6-7900-a145-4ce53ba9f1a6
This commit is contained in:
tegwick 2026-09-14 00:54:55 +02:00
parent 0783b50216
commit 7ba1b6223e
16 changed files with 656 additions and 7 deletions

View file

@ -0,0 +1,81 @@
{
"tenant": "tenant:platform",
"subject": {
"id": "secrets-engine",
"type": "service"
},
"action": "apply",
"resource": {
"id": "catalog:openrouter-llm-connect",
"type": "secret-catalog-lane",
"system": "secrets-engine",
"attributes": {
"stage": "prod",
"fields": [],
"policy_targets": [
"se-prod-openrouter-llm-connect"
],
"auth_targets": [
"se-prod-openrouter-llm-connect"
]
}
},
"context": {
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference",
"catalog_target": {
"kind": "kv",
"org": "coulomb",
"repo": "llm-connect",
"mount": "platform",
"path": "workloads/activity-core/llm-connect/llm-connect-provider-secrets",
"fields": [
"OPENROUTER_API_KEY"
],
"mount_management": "existing",
"consumers": [
{
"name": "llm-connect-activity-core",
"auth": "kubernetes",
"claim": "serviceaccount:external-secrets/external-secrets",
"purpose": "sync llm-connect-provider-secrets for the activity-core deployment"
},
{
"name": "intelligence-radar-key-check",
"auth": "approle",
"claim": "catalog:openrouter-llm-connect",
"purpose": "IR-WP-0004 read-only OpenRouter key authentication check; no inference"
}
],
"delivery_modes": [
"exec-env",
"read-check"
],
"delivery_auth": {
"method": "approle",
"management": "engine",
"policy_name": "se-prod-openrouter-llm-connect",
"role_name": "se-prod-openrouter-llm-connect",
"token_ttl": "15m",
"token_max_ttl": "30m",
"secret_id_ttl": "15m",
"secret_id_num_uses": 1,
"token_num_uses": 8
},
"delivery_config": {
"exec_owner": {
"status": "pending",
"owner": "intelligence-radar-key-check",
"reason": "Pin tools/openrouter_key_check.py and its protected Python runtime, exact argv, private cwd and fixed environment after custody-owner admission. The pending binding refuses exec before consume or secret retrieval."
}
},
"auth_capability": {},
"workload_delivery": [
{
"mode": "external-secrets",
"owner": "railiance-platform + llm-connect"
}
]
},
"human_control": true
}
}

View file

@ -0,0 +1,66 @@
{
"schema_version": 1,
"target": "disposable local processes; synthetic credentials",
"started_at": "2026-09-13T22:42:40.649405+00:00",
"keycape_image": "forgejo.coulomb.social/coulomb/key-cape@sha256:7ff54c54e63ee172ae9e6e7fd2da96e427352f712343d74626ee6fe0f6f82611",
"approval_engine_commit": "a0a602976eef818f36dde35f76f7f2e589bd051b",
"flex_auth_commit": "25712f2aad9c695ce4ce1060490432d2ffbf80ce",
"keycape_contract_commit": "6bcc2a5919799ceef68bd942d4f460ea24c87181",
"consumer_source_sha256": {
"approval_auth.py": "6f3b033e7928e1c527bc19f5a1e01bf243540769a8646bd8cd47268da25637b5",
"approval_consume.py": "4515c74dbe1cea030cdccebf17b27642ad4f67f2aaee4f3a87e4bb2b9cfad295",
"approval_claim.py": "20b728d2d3e14ffc89fa21a137716015875f9a05c6af7ff48d07cf48d89503a9",
"authorization.py": "3ffcc76404af7d97d79219a5ed6fa6040516477857f530c8d5a5e45e38871def",
"config.py": "2f2f1b60664d89bbb806aed0c768378923062077740e1f96e4c359238eb06955",
"service_auth.py": "653723ef5babce2157771416d93cb15cdbb7caca3c45509c3730520c55e4515c",
"cli.py": "1147d0e60850cfc38ee21e8564f51656d364ddc3cd8d6353a0c2dd6a0b78b8ec",
"catalog.py": "247c29314bcf86b3439d756ed911df62fb43c3c498b18ce5403704986a501b18",
"exec_owner.py": "10c21e7e37dd3d0aad41c4bb15df8f4a69c22d9046105a981a9613a91cd4c145",
"exec_delivery.py": "b142b60d875acf3dea1ba3ae99182a7ed7328d955dee5be2d12c977fc5646e8e",
"routing.py": "9d5050d7494a207394ce8251d8aac574ca0c08e3252639b5f05b373d6e35a076"
},
"limitations": [
"standalone Flex Auth source, not deployed pin",
"local Approval Engine source, not deployed image",
"no live custody or client-side read grant",
"no OpenBao effect or model execution",
"positive human entry seeded in disposable store; no human JWT/PKCE proof"
],
"checks": {
"operator_issued_and_approved_via_verified_jwt": true,
"wrong_action_refused_before_consume": true,
"producer_origin_join_with_carried_claim": true,
"actual_consumer_claim_check_consume": true,
"same_digest_retry_idempotent": true,
"different_digest_refused": true,
"spent_claim_refused": true,
"operator_consume_scope_denied_by_issuer": true,
"wrong_secret_refused": true,
"no_access_token_file_created": true,
"registry_override_accepts_exact_submission": true,
"same_enriched_result_different_submission_refused": true,
"real_dual_control_denial_then_claim_check_consume": true,
"declared_control_refuses_real_keycape_service_bind": true,
"undeclared_control_refused_before_real_pdp_consume_backend": true,
"catalog_path_change_refused_before_consume_backend": true,
"catalog_mount_change_refused_before_consume_backend": true,
"catalog_owner_change_refused_before_consume_backend": true,
"catalog_limits_change_refused_before_consume_backend": true,
"exec_owner_substitution_refused_before_consume_backend": true,
"exec_owner_changed_environment_replay_refused_by_real_pdp_join": true,
"exec_owner_real_cli_consumes_before_fixture_backend": true,
"exec_owner_actual_child_excludes_parent_credentials": true,
"exec_owner_digest_preserved_by_real_evaluator": true,
"declared_human_intent_preserved_by_real_evaluator": true,
"declared_human_fixture_consumed_before_owner_delivery": true
},
"flex_auth_binary_sha256": "d05d90212da8d762effb2b1b547aed29ab704791646714773d3fb57721a9b937",
"producer_input_sha256": {
"policy_package.md": "657fa9312c9dcabee059ec31c89ee13396fe9aa54d852edc9e6559a74bbc139a",
"registry_snapshot.json": "37fba44ec0e0fd9b1e17a05ad1b7e4f9bb6ec9e0fc0bb3133e8af2ac6f832d7c"
},
"exec_owner_scope": "Synthetic recipient/backend with real KeyCape, Approval Engine, Flex Auth and Secrets Engine CLI; not native custody or human approval proof",
"status": "passed",
"cleanup_complete": true,
"finished_at": "2026-09-13T22:43:02.850912+00:00"
}

View file

@ -0,0 +1,22 @@
{
"image": "sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd",
"pod": "flex-auth-secrets-engine-6467b96c6f-ncl5t",
"scope": "PDP evaluation only; synthetic claim, no approval consume or OpenBao access",
"checks": {
"native_request_preserved": true,
"missing_caller_refused": true,
"wrong_caller_refused": true,
"foreign_owner_representation_refused": true,
"wrong_tenant_denied": true,
"recipient_cannot_be_lifecycle_subject": true,
"producer_approval_digest_pair": true,
"changed_path_cannot_reuse_approval_digest": true,
"changed_mount_cannot_reuse_approval_digest": true,
"changed_repo_cannot_reuse_approval_digest": true,
"other_deployment_specs_unchanged": true
},
"decision_id": "decision:e8bec2d72f7df007",
"forward_stopped": true,
"caller_token_handling": "10 minute audience-bound tokens held in memory only; expire at issuer, not revoked by dropping local references",
"consumer_validation": "Actual secrets-engine validate_decision_envelope accepted the live response against the exact submission and v2 pin."
}

View file

@ -0,0 +1,20 @@
Plan for lane 'openrouter-llm-connect' (stage=prod)
decision: <none>
stage role: secrets-engine-prod
consumer policy: se-prod-openrouter-llm-connect
consumer approle: se-prod-openrouter-llm-connect
actions:
[kv-mount-check] platform (type=kv-v2, management=existing, mutation=none)
[policy] se-prod-openrouter-llm-connect (paths=platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets)
[approle] se-prod-openrouter-llm-connect (token_policies=se-prod-openrouter-llm-connect, auth=approle, token_ttl=15m, token_max_ttl=30m, token_num_uses=8, secret_id_ttl=15m, secret_id_num_uses=1)
generated consumer policy (HCL):
# Generated by secrets-engine for policy "se-prod-openrouter-llm-connect"
path "platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets" {
capabilities = ["read"]
}
path "platform/metadata/workloads/activity-core/llm-connect/llm-connect-provider-secrets" {
capabilities = ["read"]
}

View file

@ -1,3 +1,15 @@
> Current protocol correction (2026-09-14): follow claim → validated PDP Check →
> CAS consume, as implemented in docs/approval-consumption.md. ActionAuthorization
> is deferred and never ratified. The OpenRouter-specific current implementation,
> live PDP receipt and remaining service/reader gates are in
> docs/openrouter-native-access.md (SECRETS-WP-0010).
> Current protocol correction (2026-09-14): follow claim → validated PDP Check →
> CAS consume, as implemented in docs/approval-consumption.md. ActionAuthorization
> is deferred and never ratified. The OpenRouter-specific current implementation,
> live PDP receipt and remaining service/reader gates are in
> docs/openrouter-native-access.md (SECRETS-WP-0010).
# Native lane cutover (SECRETS-WP-0006-T05 / T06)
Status: procedure only. Live apply is still fail-closed until
@ -44,7 +56,7 @@ Provenance CCR: `CCR-2026-0003` (existing workload lane only).
Required before OpenBao:
1. Canonical ActionAuthorization for `action=apply`, resource
1. Live approval-claim, validated PDP Check and CAS consume for `action=apply`, resource
`catalog:openrouter-llm-connect`, stage `prod`, exact policy/auth targets
`se-prod-openrouter-llm-connect`.
2. Successful approval-engine CAS consume of that request digest

View file

@ -0,0 +1,82 @@
# OpenRouter native preparation — 2026-09-14
SECRETS-WP-0010 implements the bounded owner packet from IR-WP-0004,
message `cfab5355-b0f9-4868-b4e6-61ea42c54b0f`.
## Implemented
Every action request now includes a deep copy of the non-secret catalog target
in `context.catalog_target`: custody mount/path, owning org/repo, declared fields,
consumers, mount management, delivery modes/config/auth and workload delivery.
The existing action, stage, purpose and human-control fields remain bound.
Approval object identifiers are excluded so issuance does not change its own
approval-free digest. Changed targets or token limits require a new approval;
existing approvals created before this change cannot authorize new submissions.
This binds proposed inputs; it does not turn catalog metadata into a grant.
Plans now expose all AppRole limits, including the secret-ID TTL and use count.
The OpenRouter plan checks the existing mount and writes only the exact-path
policy and AppRole `se-prod-openrouter-llm-connect`. Limits: token TTL 15m, maximum
30m, secret-ID TTL 15m/single use, eight token uses. No KV mutation or ESO change.
See the non-secret plan and claim-free request under `docs/evidence/2026-09-14-*`.
Those are review inputs, not issued approvals; regenerate after configuring the
actual recipient because its target binding changes.
`tools/openrouter_key_check.py` is the first proposed recipient. It performs one
TLS-verified GET to the fixed endpoint, ignores proxy configuration, follows no
redirects and makes no inference request. It emits only a fixed result and HTTP
status; no provider fields, labels, response bodies, key values or exception text.
The endpoint is OpenRouter's documented
[current-key information API](https://openrouter.ai/docs/api/api-reference/api-keys/get-current-key).
A successful check does not reconcile radar's existing spend reservation.
`docs/proposals/openrouter-key-check.yaml` is an inactive proposed catalog overlay.
It retains the existing lane id/KV/policy/AppRole and ESO consumer, declares human
control, and names the key-check recipient with a pending exec-owner binding.
The active `catalog/openrouter-llm-connect.yaml` remains limited to its admitted
llm-connect purpose. The proposal is outside the active catalog and pending exec
refuses before consume/backend. Do not copy it into the active catalog until
custody-owner admission and the exact protected recipient installation are reviewed.
## Verification
410 tests passed, including disposable OpenBao coverage. New tests cover changed
path, mount, owner, consumer, limits, fields and delivery mode replay; frozen
request inputs; complete plan limits; and sanitized key-check success/errors,
redirect refusal, malformed/oversized responses and transport cleanup.
The actual local KeyCape + Approval Engine + compiled Flex Auth exercise passed
26 checks, including changed catalog target refusal before consume/backend and
exact child isolation. Its human approval and backend are explicit synthetic
fixtures, not native production evidence.
Flex Auth's dedicated native pin was promoted to Helm revision 4 with the existing
published image `sha256:05a03a8790c2210c48ea92391441c77ddf640d0cd32f5ec09838f5393171fcbd`.
Eleven live evaluation checks passed, including current replay/approval binding;
other PDP deployment specs are unchanged. The separate local and live receipts
state their scope and cleanup. This removes the outdated PDP image dependency.
## Remaining admitted execution sequence (SECRETS-WP-0010-T03)
1. Complete APPROVAL-WP-0002-T01/T03/T05 and its identity/audit dependencies;
its declared namespace currently has no StatefulSet, pod or Service. Complete
RPF-WP-0035-T06 / CCR-2026-0019 client-side reader admission for the secrets-engine
approval-client. Keep secrets outside Git and use the existing attended
procedure in `docs/approval-service-auth.md`; do not read the verifier's Secret.
2. Have the custody owner admit this exact read-only recipient. Install and pin
its Python runtime and script, exact argv, private working directory and fixed
environment via `docs/exec-owner-binding.md`. Obtain the scoped attended
platform authority; no standing bootstrap credential or sibling identity.
3. Render the finalized request, use the evaluator-origin digest to create a
declared-human-control approval, obtain the real human entry, observe claim,
validate Check and CAS-consume before apply. `ActionAuthorization` is deferred,
not a missing API to implement. CCR-2026-0003 is provenance, not this approval.
4. Apply only the reviewed policy/AppRole. Verify correct-reader access, unrelated
identity and unrelated path denials, all fields, role limits, native session
revocation and llm-connect ESO/application health. No raw provider value in
evidence. Obtain a separate exact exec approval for the pinned key check.
5. Only after verified native readiness should SECRETS-WP-0006-T06 retire the
interim route. Rollback removes only the new policy/AppRole; preserve KV/ESO.
6. Trial delivery requires its own reviewed, pinned radar recipient/config and
approval. Reconcile the existing USD 0.023712 reservation in campaign
`ir-openrouter-pilot-20260913`; preserve the authorized USD 10 ceiling. This
task did not execute the key check or spend campaign funds.

View file

@ -0,0 +1,87 @@
# PROPOSED reviewed-input template; not active catalog or credential admission.
# SECRETS-WP-0010; retain the existing KV and AppRole names.
id: openrouter-llm-connect
kind: kv
org: coulomb
repo: llm-connect
stage: prod
description: >-
OpenRouter provider credential used by llm-connect for activity-core. The
proposed native recipient checks key authentication only; trial delivery
requires a separate reviewed recipient and exact-action approval.
mount: platform
path: workloads/activity-core/llm-connect/llm-connect-provider-secrets
mount_management: existing
fields:
- OPENROUTER_API_KEY
consumers:
- name: llm-connect-activity-core
auth: kubernetes
claim: serviceaccount:external-secrets/external-secrets
purpose: sync llm-connect-provider-secrets for the activity-core deployment
- name: intelligence-radar-key-check
auth: approle
claim: catalog:openrouter-llm-connect
purpose: IR-WP-0004 read-only OpenRouter key authentication check; no inference
workload_delivery:
- mode: external-secrets
owner: railiance-platform + llm-connect
delivery_modes: [exec-env, read-check]
delivery_auth:
method: approle
management: engine
policy_name: se-prod-openrouter-llm-connect
role_name: se-prod-openrouter-llm-connect
token_ttl: 15m
token_max_ttl: 30m
secret_id_ttl: 15m
secret_id_num_uses: 1
token_num_uses: 8
approval:
model: ccr
human_control: true
purpose: IR-WP-0004 read-only OpenRouter key authentication check; no inference
decision_ref: CCR-2026-0003
notes: >-
CCR-2026-0003 approves the existing workload lane. A live native AppRole
apply remains gated by SECRETS-WP-0006-T05 review and operator approval.
First native-cutover candidate (docs/native-lane-cutover.md); not an
authorization to apply.
verification:
positive: approved delivery AppRole can read OPENROUTER_API_KEY without printing it
negative: unrelated token is denied on platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets
risk:
classification: high
notes: provider key can incur spend and remains valid outside OpenBao until revoked at OpenRouter
rotation:
owner: railiance-platform + llm-connect provider operator
expectation: >-
Mint a replacement at OpenRouter, update every live cluster copy, wait for
ESO refresh, restart llm-connect, verify, and revoke the old provider key.
ttl: provider-defined
deactivation:
owner: railiance-platform + llm-connect
expectation: >-
Disable the front door and workload read path, remove materialized Secrets,
stop consumers, and revoke the provider key at OpenRouter.
audit:
evidence: CCR id, actor, exact path, field name, provider key identifier if non-secret, timestamps, and pass/fail only
delivery_config:
exec_owner:
status: pending
owner: intelligence-radar-key-check
reason: >-
Pin tools/openrouter_key_check.py and its protected Python runtime, exact
argv, private cwd and fixed environment after custody-owner admission.
The pending binding refuses exec before consume or secret retrieval.