Record reviewed case source evidence (5/13)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Reject generated-only commits / generated-commit-guard (push) Successful in 10s

This commit is contained in:
codex 2026-10-17 22:32:57 +02:00
parent 42e18ef0c8
commit 5c456215ea
20 changed files with 2762 additions and 0 deletions

View file

@ -0,0 +1,157 @@
"""Kernel admission against the real 1.3 successor type (NK-WP-0048-T16 candidate).
Unlike test_admit_1_2_adapter_descriptors.py, nothing is patched into the type's
execution_descriptors: the map tested here is the one committed in
security-case-type-revisions/1.3. The type is `proposed`, so the kernel must refuse
it as it stands. Warden's BrowserInputs also pins each type version's parameter
fingerprint and knows only 1.1 and 1.2 (ops-warden case_inputs.PARAMETER_PINS), so an
acknowledged 1.3 is still refused until ops-warden adds a 1.3 pin. That is an
ops-warden owner change, and it is not made here. The tests show that 1.3's
parameters carry 1.2's pinned fingerprint, and that with only that one pin added in
memory the committed map admits exactly the composed descriptors and nothing else.
Trust is fixture-only, nothing is dispatched, and none of this is owner admission
or an acknowledgment.
"""
from dataclasses import replace
import hashlib
import importlib.util
import json
import os
from pathlib import Path
import tempfile
import unittest
from unittest import mock
import yaml
from warden.case_run import Adapter, Executor, Journal, digest
from warden.case_receipt_state import Refused
import warden.case_inputs as inputs
ROOT = Path(__file__).parent
REPO = ROOT.parents[2]
spec = importlib.util.spec_from_file_location('compose_13_admit', ROOT / 'compose-1.2-descriptors.py')
c = importlib.util.module_from_spec(spec)
spec.loader.exec_module(c)
TYPE_DIR = REPO / 'security-case-type-revisions/1.3/oidc-browser-relying-party'
TYPE_BYTES = (TYPE_DIR / 'type.yaml').read_bytes()
ARTIFACT = json.loads((ROOT / 'descriptor-composition-1.3.candidate.json').read_text())
EVIDENCE = {'fixture-acceptance', 'fixture-materialization', 'fixture-descriptor', 'fixture-session'}
def unused(*_):
raise AssertionError('admission must not dispatch')
def parameter_fingerprint(type_bytes):
params = yaml.safe_load(type_bytes)['spec']['parameters']
return hashlib.sha256(json.dumps(params, sort_keys=True, separators=(',', ':')).encode()).hexdigest()
def pinned_13():
"""Warden's parameter pins plus the one 1.3 entry ops-warden would have to add."""
return mock.patch.dict(inputs.PARAMETER_PINS, {'1.3': parameter_fingerprint(TYPE_BYTES)})
def with_status(status):
"""The committed 1.3 type with only its status changed."""
typ = yaml.safe_load(TYPE_BYTES)
typ['spec']['status'] = status
return yaml.safe_dump(typ).encode()
class Admit13TypeTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
case = yaml.safe_load((TYPE_DIR / 'examples/forgejo.yaml').read_bytes())
case['spec'].update(status='materialized', acceptance={
'at': '2026-10-17', 'record': 'fixture-only acceptance, not an owner record',
'by': [{'name': 'fixture', 'role': 'owner'}, {'name': 'fixture', 'role': 'founder'}]})
self.case_source = yaml.safe_dump(case).encode()
self.descriptors = dict(c.adapter_descriptors(ARTIFACT['check_config_digest'],
ARTIFACT['params']['consumer_owner_repo'],
version='1.3'))
def admit(self, desc, type_source, *, actor=None, lane=None):
desc_bytes = c.encode(desc)
adapter = Adapter(desc.adapter, desc.adapter_source, unused, unused)
executor = Executor(Journal(Path(self.temp.name) / desc.step),
{adapter.reference: adapter},
lambda purpose, source, evidence: evidence in EVIDENCE,
browser_inputs=inputs.BrowserInputs(REPO))
with mock.patch.dict(os.environ):
os.environ.pop('WARDEN_AGENT_ID', None)
return executor.admit(self.case_source, type_source, desc_bytes,
b'fixture-only-catalog', principal='founder', actor=actor or desc.actor,
lane=lane or desc.lane,
acceptance_evidence='fixture-acceptance',
materialization_evidence='fixture-materialization',
descriptor_evidence='fixture-descriptor', session_evidence='fixture-session')
def test_committed_map_is_exactly_the_composed_set(self):
committed = yaml.safe_load(TYPE_BYTES)['spec']['execution_descriptors']
composed = {s: digest(c.encode(d)) for s, d in self.descriptors.items()}
self.assertEqual(len(composed), 7)
self.assertEqual(committed, composed)
self.assertEqual(committed, ARTIFACT['execution_descriptors'])
def test_proposed_type_is_refused_as_it_stands(self):
self.assertEqual(yaml.safe_load(TYPE_BYTES)['spec']['status'], 'proposed')
for step, desc in self.descriptors.items():
with self.subTest(step=step), self.assertRaisesRegex(Refused, 'type is not acknowledged'):
self.admit(desc, TYPE_BYTES)
def test_warden_has_no_1_3_parameter_pin_yet(self):
self.assertNotIn('1.3', inputs.PARAMETER_PINS)
# 1.3 keeps 1.2's parameters, so the missing pin is 1.2's fingerprint.
self.assertEqual(parameter_fingerprint(TYPE_BYTES), inputs.PARAMETER_PINS['1.2'])
acknowledged = with_status('acknowledged')
for step, desc in self.descriptors.items():
with self.subTest(step=step), self.assertRaisesRegex(
Refused, 'failed exact-version validation'):
self.admit(desc, acknowledged)
def test_committed_map_admits_every_descriptor_once_acknowledged_and_pinned(self):
acknowledged = with_status('acknowledged')
for step, desc in self.descriptors.items():
with self.subTest(step=step), pinned_13():
admitted, invocation, _ = self.admit(desc, acknowledged)
self.assertEqual(admitted, desc)
self.assertEqual((invocation.step, invocation.actor, invocation.target),
(desc.step, desc.actor, 'forgejo'))
def test_descriptor_outside_the_map_is_refused(self):
acknowledged = with_status('acknowledged')
mint = self.descriptors['mint-secret']
for changed in (replace(mint, lane='other-lane'), replace(mint, retry_safe=True)):
with self.subTest(changed=changed), pinned_13(), self.assertRaisesRegex(
Refused, 'no exact acknowledged machine descriptor'):
self.admit(changed, acknowledged)
def test_mint_secret_admits_only_a_human_actor(self):
# Moved from test_admit_1_2_adapter_descriptors.py (NK48-R1-F1) in r5.
acknowledged = with_status('acknowledged')
mint = self.descriptors['mint-secret']
self.assertEqual((mint.effect, mint.actor), ('mint', 'human'))
with pinned_13(), self.assertRaisesRegex(Refused, 'principal actor or lane mismatch'):
self.admit(mint, acknowledged, actor='agent')
def test_wrong_lane_is_refused(self):
# Moved from test_admit_1_2_adapter_descriptors.py in r5.
acknowledged = with_status('acknowledged')
for step, desc in self.descriptors.items():
with self.subTest(step=step), pinned_13(), self.assertRaisesRegex(
Refused, 'principal actor or lane mismatch'):
self.admit(desc, acknowledged, lane='wrong-lane')
def test_earlier_versions_carry_no_execution_map(self):
for version in ('1.2',):
path = REPO / f'security-case-type-revisions/{version}/oidc-browser-relying-party/type.yaml'
with self.subTest(version=version):
self.assertNotIn('execution_descriptors', yaml.safe_load(path.read_bytes())['spec'])
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,69 @@
# NK48-R5-F2 issuer store implementation candidate
The missing issuer store is now a concrete **proposed Platform source contract**,
not a discovered existing grant. Neither patch has been applied to a canonical
checkout. Independent Platform review remains necessary before the conditional
NetKingdom patch can be integrated; F2 is not declared closed here.
The proposed reference is cluster-scoped `ClusterSecretStore
openbao-keycape-{client_id}-issuer`, with no metadata namespace and use restricted
to `sso`. For Forgejo, it binds role `external-secrets-keycape-forgejo` to the
existing CCR0041 identity `external-secrets/external-secrets`, audience `openbao`.
The exact store/provider/ExternalSecret/key/property/target source is in
`platform-candidate/manifests/templates/keycape-issuer-eso.yaml`; its hash is
recorded in `review.json` and the conditional type text. The new `-issuer` name
is an implementation proposal: it does not reuse the Apps consumer SecretStore
or claim that CCR0041 admitted this store name. It preserves type IDs ending in
`-` without changing parameters. ClusterSecretStore names use DNS subdomain
names; the existing adapter's 63-character target reference bound is retained.
`platform.candidate.patch` adds only that explicit template, a pure metadata
render/validation helper, eight focused fixture tests and an owner contract doc.
It contains no Kubernetes/OpenBao API client, apply/delete command, credentials,
receipt issuer or catalog grant. Store provisioning is separate owner work; the
delivery lane gets only the ExternalSecret document. The template is multi-doc
review source and must not be applied through the delivery lane. Its strict spec
comparison intentionally refuses drift; installed ESO schema/defaulting and
trusted observation authenticity still belong to the real owner binding.
`netkingdom-entry-point.conditional.patch` changes **only** the issuer
`deliver-secret.entry_point` at NetKingdom 3236d500. The prior type is byte-equal
to r5's e75fe941 reviewed type. It names the proposed exact kind/name/scope and
owner template digest. Parameters, descriptors, modes, lanes, other follow-through,
materialization, verification, acceptance, and every rollback entry are unchanged.
The root coordinator can combine this text with F3 after Platform source review,
then regenerate the existing combined artifact. No source owner acknowledgment,
case/type pin, catalog mutation or default revision switch has occurred.
Eight tests / 42 negative subcases passed using public synthetic metadata:
independently fixed Forgejo mapping; wrong kind/name/namespace; role, server,
mount, SA/audience or allowed-namespace drift; consumer-store substitution;
remoteRef/property/target drift; malformed/unready observations; rejected caller
store/path overrides; detached ExternalSecret-only render; type-compatible trailing
dash. Both exact patches passed `git apply --check` in disposable scratch.
See `focused-tests.*` and `structural-and-patch-checks.json`. These checks are not
native delivery, signed evidence, API defaulting, issuer auth or isolation proof.
The source basis is pinned in `source-pins.json`: r5 F2 at coordinator review
lines 429–439; Platform RPF-1.3-C1 explicitly requires a named store and the
lane definition explicitly calls for a fixed client-derived Platform constant;
CCR0041 grants the Forgejo role/SA/audience but declares no store name;
Platform's historical issuer `eso.draft.yaml` supplies ClusterSecretStore,
namespace restriction, serviceAccountRef.audiences and fixed target/remoteRef
conventions; the scaffold also renders ClusterSecretStore and mount-relative
remoteRefs but requires a caller-supplied owner config store_name. The scaffold's
historical audience location differs: the candidate follows the issuer draft,
and makes no claim about the actual installed schema.
Bounded source search: Platform, NetKingdom and Mason public YAML/Python/JSON/MD
for `openbao-keycape-forgejo` and `external-secrets-keycape-forgejo`, plus Platform
issuer/store/scaffold files. Existing hits name the separate consumer store,
role/policy or old type text. No fixed Forgejo issuer store declaration was found.
This is a public-source finding, not a live-cluster absence claim. No Kubernetes,
SSH, Bao, credential route, Secret or private archive was accessed.
The next source step is independent Platform review of the exact new declaration,
then coordinator integration of the accepted text with F3. RPF-1.3-T4's actual
capabilities, authentic metadata receipts, per-attempt revocation, guarded
created-only rollback and Warden catalog routing remain its existing owner work.
No new task, UUID, protocol, policy gate or human approval request is created.

View file

@ -0,0 +1,12 @@
{
"net-kingdom": {
"HEAD": "3236d5000e52e0643f33906a26a7825aa0b67465",
"status_porcelain_v1": " M .custodian-brief.md\n M WORK-RECORDS.md\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture/\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-inventory.jsonl\n?? docs/evidence/2026-10-15-cadence-adoption/hourly-observation-monitor.json\n?? intakes/NET-IN-0005-single-use-setup-link-mail-handoff.md\n",
"index_sha256": "47bcf3291b9613706337c2493c33a065ab089c0c5bbbe545de5f462b67b007a3"
},
"railiance-platform": {
"HEAD": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"status_porcelain_v1": "M .custodian-brief.md\n M WORK-RECORDS.md\n",
"index_sha256": "40f766948f7774c6215ab562e50b4154e9bbdcfbf3a14488625c95afc9cf6fe6"
}
}

View file

@ -0,0 +1,10 @@
{
"schema": "custodian.source-test-result.v1",
"scope": "synthetic public metadata only; no API, native, credential, receipt-authenticity or isolation proof",
"command": "python3 -B platform-candidate/tests/test_keycape_issuer_eso.py",
"tests": 8,
"subtests": 42,
"passed": true,
"python": "3.12.3",
"pyyaml": "6.0.1"
}

View file

@ -0,0 +1,13 @@
test_delivery_document_is_only_external_and_detached (fixture.FixedIssuerContract.test_delivery_document_is_only_external_and_detached) ... ok
test_external_drift_refuses (fixture.FixedIssuerContract.test_external_drift_refuses) ... ok
test_independent_forgejo_binding (fixture.FixedIssuerContract.test_independent_forgejo_binding) ... ok
test_missing_or_unready_refuses (fixture.FixedIssuerContract.test_missing_or_unready_refuses) ... ok
test_no_caller_store_or_path_override (fixture.FixedIssuerContract.test_no_caller_store_or_path_override) ... ok
test_store_drift_refuses (fixture.FixedIssuerContract.test_store_drift_refuses) ... ok
test_type_admitted_trailing_dash_is_preserved (fixture.FixedIssuerContract.test_type_admitted_trailing_dash_is_preserved) ... ok
test_valid_ready_metadata_allows_extra_controller_metadata (fixture.FixedIssuerContract.test_valid_ready_metadata_allows_extra_controller_metadata) ... ok
----------------------------------------------------------------------
Ran 8 tests in 0.247s
OK

View file

@ -0,0 +1,20 @@
{
"schema": "custodian.source-packet-manifest.v1",
"sha256": {
"OWNER-REVIEW.md": "sha256:7983fd841f09bc7584047426912c33d568c97b4c1126776f99aac42b34d2b742",
"canonical-source-readonly-state.json": "sha256:129d6926bb996e510ab4b41d30e738096b53b71de1fb2dd470fe0ac94848cbec",
"focused-tests.json": "sha256:8de5862a8d752dce0b3b96a9275e42952a99415a18d3f67c06bf9f5b6008d0e3",
"focused-tests.txt": "sha256:aab46c51d87198ad4be6dd3078f61286e2faf1ef4d76fa14298698388f78ab24",
"netkingdom-entry-point.conditional.patch": "sha256:6784a21fbd10bd62712be2e0f4929034601c94629aa74ccaa2e93fc815eecd61",
"platform-candidate/docs/keycape-issuer-eso-contract.md": "sha256:7f59e59b17c58252982931ac61fe50dd7a07340add6c437fe48af36971eafe68",
"platform-candidate/manifests/templates/keycape-issuer-eso.yaml": "sha256:e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743",
"platform-candidate/scripts/keycape_issuer_eso.py": "sha256:21c5797280c2a7825dbda8ac970d34a0cdef4c6458f68bce0b1c12407f122a87",
"platform-candidate/tests/test_keycape_issuer_eso.py": "sha256:223d4c5b349062b9f93e6af79e8d5feda44377ba41a11726f6f2b762691e8308",
"platform.candidate.patch": "sha256:a490df7dee41e15351da8d2906e1342edebb533984befe3d9ae74d952dbb091b",
"review.json": "sha256:d99db9ab4f326308cde464129bbbb7573434e500fd03c130a37a590bac3643a4",
"source-pins.json": "sha256:6e896b6196a0aca01ddaf433b4d14cc041fc0296c5dd6404c3a698b941b61bd8",
"structural-and-patch-checks.json": "sha256:a3dc4cd405c412d4369986cc6736cd2d9eed02d4b86d95d62d5a9914106fdb14",
"type.before.yaml": "sha256:e75fe94110ef9fb7fb18072fe2856941b33507c99cb406d36576046481485d0a",
"type.candidate.yaml": "sha256:ef02ddae3167bdd1558193a5f6db0379fb8cc84207531706d5ef35caabc3684f"
}
}

View file

@ -0,0 +1,16 @@
--- a/security-case-type-revisions/1.3/oidc-browser-relying-party/type.yaml
+++ b/security-case-type-revisions/1.3/oidc-browser-relying-party/type.yaml
@@ -269,8 +269,11 @@
when: client_type == confidential
entry_point: reviewed adapter railiance-platform/keycape-deliver-secret, dispatched
by Warden's case kernel; Platform's deliver capability applies ExternalSecret
- sso/keycape-{client_id}-client (key client-secret) through the ESO store for
- role external-secrets-keycape-{client_id}, from bao:platform/workloads/keycape/{client_id}
+ sso/keycape-{client_id}-client (key client-secret) through fixed ClusterSecretStore
+ openbao-keycape-{client_id}-issuer (cluster-scoped, restricted to namespace sso),
+ defined by Platform-controlled manifests/templates/keycape-issuer-eso.yaml
+ (sha256:e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743),
+ using role external-secrets-keycape-{client_id}, from bao:platform/workloads/keycape/{client_id}
auth: Platform's own delivery path on lane platform-secret-delivery, inside the human
aal2 session; ESO reads custody through role external-secrets-keycape-{client_id};
Warden holds no Platform credential, and no value leaves custody

View file

@ -0,0 +1,68 @@
# Proposed fixed issuer ESO contract — RPF-1.3-T4 / NK48-R5-F2
Status: proposed source; not admitted, deployed, or owner-acknowledged. This is a
new Platform declaration for review, not an existing Forgejo grant discovery.
The only substitution in `manifests/templates/keycape-issuer-eso.yaml`
(sha256:e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743) is the admitted `client_id`. The proposed issuer
store is **ClusterSecretStore `openbao-keycape-{client_id}-issuer`**, cluster
scoped (no metadata namespace), restricted by conditions to ExternalSecrets in
`sso`. For Forgejo it is `openbao-keycape-forgejo-issuer`. The suffix makes the
issuer purpose explicit and keeps type-admitted IDs ending in `-` representable.
The store's DNS subdomain name can exceed 63 characters; the existing adapter's
63-character target Secret reference bound is preserved (client ID at most 48).
No type parameter is added or changed.
The provider is `http://openbao.openbao.svc:8200`, KV v2 mount `platform`,
Kubernetes auth mount `kubernetes`, role `external-secrets-keycape-{client_id}`,
serviceAccountRef `external-secrets/external-secrets`, audience `openbao`.
CCR-2026-0041 already records that Forgejo role/identity/audience, not this new
store name or an unrestricted client family grant. Other clients still require
their own existing owner-controlled role/case admission.
The ExternalSecret is `sso/keycape-{client_id}-client`, references precisely that
ClusterSecretStore, refreshes every 5m and targets the same name with Owner
creation and Retain remote deletion. Its only data entry maps `client-secret`
from remoteRef `workloads/keycape/{client_id}`, property `CLIENT_SECRET`. The
provider mount plus mount-relative remoteRef equals custody reference
`platform/workloads/keycape/{client_id}`; do not double-prefix `platform/`.
This is distinct from the Apps-owned consumer namespace SecretStore
`openbao-keycape-{client_id}-consumer` and its dedicated consumer identity.
Store provisioning belongs to Platform's separate owner-controlled path. The
proposed `platform-secret-delivery` lane retains ONLY create/get/watch/delete on
the exact ExternalSecret in `sso`; this source does not delegate store creation
or Secret read/list. Never apply the multi-document template through that lane.
The pure `scripts/keycape_issuer_eso.py` module exposes only the ExternalSecret
document through `external_secret()` and validates fixed public observations
through `require_fixed_store()` and `require_ready_delivery()`. It performs no
API call and issues no evidence/receipt. It is not a real capability or admission
boundary; a caller-supplied observation alone establishes no authenticity.
The existing RPF-1.3-T4 delivery binding must validate the case/client binding,
verify this exact preexisting store's public identity/spec/Ready state, apply or
compare the exact ExternalSecret, and wait for matching spec plus Ready=True.
The proposed helper accepts extra controller metadata but deliberately refuses
spec drift. Actual API defaulting/normalization and installed ESO schema support
must be checked in that implementation; these fixtures establish no native
compatibility or credential isolation. ESO's shared controller remains trusted.
No Secret bodies, values, arbitrary remoteRefs, or raw errors may enter receipts.
Existing owner requirements remain: closed `netkingdom.deliver-secret.v1`
metadata receipt with authenticated before/after UID/resourceVersion provenance,
unchanged objects reported NO_CHANGE, attempt-session revocation, and created-only
rollback guarded by exact UID/resourceVersion (drift or uncertain ownership goes
to owner reconciliation). The helper neither deletes a target Secret nor creates
an OpenBao role/policy nor changes CCR-0041. These capabilities and catalog routing
remain unimplemented/unaccepted under RPF-1.3-T4. Independent Platform source
review of this declaration precedes adopting the conditional NetKingdom type
text; no descriptor acceptance, acknowledgment, pin, grant, catalog or native
permission is inferred.
Grounding: CCR-2026-0041 exact role/identity; the approved historical
`docs/provisioning-windows/2026-10-04-1000/keycape/eso.draft.yaml` issuer
ClusterSecretStore and target pattern; `scripts/catalog_lane_scaffold.py`
ClusterSecretStore/namespace restriction and mount-relative remoteRef model;
RPF-1.3-C1 and RPF-1.3-T4 in the frozen owner review. The scaffold's historical
audience field placement differs from the issuer draft; this candidate uses
the issuer draft's serviceAccountRef.audiences, not a claim of installed support.

View file

@ -0,0 +1,46 @@
# PROPOSED SOURCE ONLY — RPF-1.3-T4 / NK48-R5-F2; not admitted or applied.
# Platform controls this template. Only admitted client_id is substituted.
# Provision the store through Platform's separate reviewed owner path; the
# platform-secret-delivery lane applies ONLY the ExternalSecret document.
apiVersion: external-secrets.io/v1
kind: ClusterSecretStore
metadata:
name: openbao-keycape-{client_id}-issuer
spec:
provider:
vault:
server: http://openbao.openbao.svc:8200
path: platform
version: v2
auth:
kubernetes:
mountPath: kubernetes
role: external-secrets-keycape-{client_id}
serviceAccountRef:
name: external-secrets
namespace: external-secrets
audiences:
- openbao
conditions:
- namespaces:
- sso
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: keycape-{client_id}-client
namespace: sso
spec:
refreshInterval: 5m
secretStoreRef:
kind: ClusterSecretStore
name: openbao-keycape-{client_id}-issuer
target:
name: keycape-{client_id}-client
creationPolicy: Owner
deletionPolicy: Retain
data:
- secretKey: client-secret
remoteRef:
key: workloads/keycape/{client_id}
property: CLIENT_SECRET

View file

@ -0,0 +1,70 @@
"""Proposed fixed issuer ESO source contract for RPF-1.3-T4 / NK48-R5-F2.
Pure public metadata only. No API/credential/Secret access or apply path. This
new declaration requires independent Platform review before type integration.
The delivery lane may use only external_secret(); store provisioning is a
separate owner action and is never delegated by this module.
"""
from __future__ import annotations
from copy import deepcopy
from pathlib import Path
import re
import yaml
ROOT = Path(__file__).resolve().parents[1]
TEMPLATE = ROOT / 'manifests/templates/keycape-issuer-eso.yaml'
class Refused(ValueError):
"""Fixed issuer metadata differs; never return an owner delivery receipt."""
def documents(client_id: str) -> tuple[dict, dict]:
# Match the frozen type client_id pattern and existing adapter's derived bound.
# No caller can supply a store name/kind/namespace or an OpenBao path.
if not isinstance(client_id, str) or not re.fullmatch(r'[a-z0-9][a-z0-9-]{1,62}', client_id):
raise Refused('bounded admitted client_id required')
if len('keycape-' + client_id + '-client') > 63:
raise Refused('derived issuer reference exceeds existing adapter bound')
store, external = yaml.safe_load_all(TEMPLATE.read_text().format(client_id=client_id))
return store, external
def external_secret(client_id: str) -> dict:
"""The ONLY document the proposed delivery capability may apply."""
return deepcopy(documents(client_id)[1])
def _matching_public_resource(observed: dict, expected: dict) -> None:
if not isinstance(observed, dict):
raise Refused('public resource observation required')
metadata = observed.get('metadata')
if not isinstance(metadata, dict):
raise Refused('resource metadata required')
expected_namespace = expected['metadata'].get('namespace')
namespace_matches = (metadata.get('namespace') == expected_namespace
if expected_namespace else metadata.get('namespace') in (None, ''))
if (observed.get('apiVersion') != expected['apiVersion']
or observed.get('kind') != expected['kind']
or metadata.get('name') != expected['metadata']['name']
or not namespace_matches
or observed.get('spec') != expected['spec']):
raise Refused('fixed issuer resource differs')
status = observed.get('status')
conditions = status.get('conditions', []) if isinstance(status, dict) else []
if not isinstance(conditions, list) or not any(
isinstance(c, dict) and c.get('type') == 'Ready' and c.get('status') == 'True'
for c in conditions):
raise Refused('fixed issuer resource not ready')
def require_fixed_store(observed: dict, client_id: str) -> None:
"""Refuse a missing/drifted/not-ready store; never create it through delivery."""
_matching_public_resource(observed, documents(client_id)[0])
def require_ready_delivery(observed: dict, client_id: str) -> None:
"""Spec equality and Ready precede a created/NO_CHANGE owner receipt."""
_matching_public_resource(observed, documents(client_id)[1])

View file

@ -0,0 +1,129 @@
"""Public metadata fixtures only: no API, credentials, or native calls."""
import copy
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
import keycape_issuer_eso as contract
class FixedIssuerContract(unittest.TestCase):
def observations(self):
resources = contract.documents("forgejo")
for resource in resources:
resource["metadata"].update(uid="public-fixture-uid", resourceVersion="7")
resource["status"] = {"conditions": [{"type": "Ready", "status": "True"}]}
return resources
def test_independent_forgejo_binding(self):
# Independent owner-source example: CCR0041 role/SA/audience and the
# existing issuer ESO draft's provider/target/relative key convention.
store, external = contract.documents("forgejo")
self.assertEqual(store["kind"], "ClusterSecretStore")
self.assertEqual(store["metadata"], {"name": "openbao-keycape-forgejo-issuer"})
self.assertEqual(store["spec"], {
"provider": {"vault": {
"server": "http://openbao.openbao.svc:8200", "path": "platform", "version": "v2",
"auth": {"kubernetes": {"mountPath": "kubernetes",
"role": "external-secrets-keycape-forgejo",
"serviceAccountRef": {"name": "external-secrets", "namespace": "external-secrets",
"audiences": ["openbao"]}}}}},
"conditions": [{"namespaces": ["sso"]}]})
self.assertEqual(external["metadata"], {"name": "keycape-forgejo-client", "namespace": "sso"})
self.assertEqual(external["spec"], {
"refreshInterval": "5m",
"secretStoreRef": {"kind": "ClusterSecretStore", "name": "openbao-keycape-forgejo-issuer"},
"target": {"name": "keycape-forgejo-client", "creationPolicy": "Owner", "deletionPolicy": "Retain"},
"data": [{"secretKey": "client-secret", "remoteRef": {
"key": "workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]})
def test_valid_ready_metadata_allows_extra_controller_metadata(self):
store, external = self.observations()
contract.require_fixed_store(store, "forgejo")
contract.require_ready_delivery(external, "forgejo")
def test_store_drift_refuses(self):
changes = [
("kind", "SecretStore"),
("metadata.namespace", "sso"),
("metadata.name", "caller-store"),
("spec.provider.vault.server", "https://wrong.invalid"),
("spec.provider.vault.path", "tenant"),
("spec.provider.vault.auth.kubernetes.role", "external-secrets-keycape-sibling"),
("spec.provider.vault.auth.kubernetes.serviceAccountRef.audiences", ["wrong"]),
("spec.provider.vault.auth.kubernetes.serviceAccountRef.namespace", "sso"),
("spec.conditions", [{"namespaces": ["sso", "other"]}]),
]
for path, value in changes:
with self.subTest(path=path):
store = self.observations()[0]
mutate(store, path, value)
with self.assertRaises(contract.Refused):
contract.require_fixed_store(store, "forgejo")
def test_external_drift_refuses(self):
changes = [
("metadata.namespace", ""), ("metadata.namespace", None), ("metadata.namespace", "other"),
("metadata.name", "keycape-sibling-client"),
("spec.secretStoreRef.kind", "SecretStore"),
("spec.secretStoreRef.name", "openbao-keycape-forgejo-consumer"),
("spec.target.name", "other"), ("spec.target.creationPolicy", "Merge"),
("spec.target.deletionPolicy", "Delete"),
("spec.data", [{"secretKey": "client-secret", "remoteRef": {
"key": "platform/workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]),
("spec.data", [{"secretKey": "wrong", "remoteRef": {
"key": "workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]),
("spec.data", [{"secretKey": "client-secret", "remoteRef": {
"key": "workloads/keycape/forgejo", "property": "wrong"}}]),
]
for path, value in changes:
with self.subTest(path=path, value=value):
external = self.observations()[1]
mutate(external, path, value)
with self.assertRaises(contract.Refused):
contract.require_ready_delivery(external, "forgejo")
def test_missing_or_unready_refuses(self):
for check, index in [(contract.require_fixed_store, 0), (contract.require_ready_delivery, 1)]:
for status in [None, {}, [], "bad", {"conditions": None},
{"conditions": [{"type": "Ready", "status": "False"}]}]:
with self.subTest(check=check.__name__, status=status):
observed = self.observations()[index]
observed["status"] = status
with self.assertRaises(contract.Refused):
check(observed, "forgejo")
for malformed in [None, [], {}, {"metadata": None}]:
with self.assertRaises(contract.Refused):
check(malformed, "forgejo")
def test_no_caller_store_or_path_override(self):
for invalid in ["", "f", "../forgejo", "forgejo/sibling", "Forgejo", "forgejo\n", "-forgejo", "f" * 49, None]:
with self.subTest(invalid=invalid), self.assertRaises(contract.Refused):
contract.documents(invalid)
with self.assertRaises(TypeError):
contract.external_secret("forgejo", store_name="caller-store")
def test_type_admitted_trailing_dash_is_preserved(self):
self.assertEqual(contract.external_secret("forgejo-")["metadata"]["name"],
"keycape-forgejo--client")
self.assertEqual(contract.documents("forgejo-")[0]["metadata"]["name"],
"openbao-keycape-forgejo--issuer")
def test_delivery_document_is_only_external_and_detached(self):
external = contract.external_secret("forgejo")
self.assertEqual(external["kind"], "ExternalSecret")
external["spec"]["secretStoreRef"]["name"] = "tampered"
self.assertEqual(contract.external_secret("forgejo")["spec"]["secretStoreRef"]["name"],
"openbao-keycape-forgejo-issuer")
def mutate(resource, path, value):
parts = path.split(".")
for key in parts[:-1]:
resource = resource[key]
resource[parts[-1]] = copy.deepcopy(value)
if __name__ == "__main__":
unittest.main(verbosity=2)

View file

@ -0,0 +1,325 @@
--- /dev/null
+++ b/docs/keycape-issuer-eso-contract.md
@@ -0,0 +1,68 @@
+# Proposed fixed issuer ESO contract — RPF-1.3-T4 / NK48-R5-F2
+
+Status: proposed source; not admitted, deployed, or owner-acknowledged. This is a
+new Platform declaration for review, not an existing Forgejo grant discovery.
+
+The only substitution in `manifests/templates/keycape-issuer-eso.yaml`
+(sha256:e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743) is the admitted `client_id`. The proposed issuer
+store is **ClusterSecretStore `openbao-keycape-{client_id}-issuer`**, cluster
+scoped (no metadata namespace), restricted by conditions to ExternalSecrets in
+`sso`. For Forgejo it is `openbao-keycape-forgejo-issuer`. The suffix makes the
+issuer purpose explicit and keeps type-admitted IDs ending in `-` representable.
+The store's DNS subdomain name can exceed 63 characters; the existing adapter's
+63-character target Secret reference bound is preserved (client ID at most 48).
+No type parameter is added or changed.
+
+The provider is `http://openbao.openbao.svc:8200`, KV v2 mount `platform`,
+Kubernetes auth mount `kubernetes`, role `external-secrets-keycape-{client_id}`,
+serviceAccountRef `external-secrets/external-secrets`, audience `openbao`.
+CCR-2026-0041 already records that Forgejo role/identity/audience, not this new
+store name or an unrestricted client family grant. Other clients still require
+their own existing owner-controlled role/case admission.
+
+The ExternalSecret is `sso/keycape-{client_id}-client`, references precisely that
+ClusterSecretStore, refreshes every 5m and targets the same name with Owner
+creation and Retain remote deletion. Its only data entry maps `client-secret`
+from remoteRef `workloads/keycape/{client_id}`, property `CLIENT_SECRET`. The
+provider mount plus mount-relative remoteRef equals custody reference
+`platform/workloads/keycape/{client_id}`; do not double-prefix `platform/`.
+This is distinct from the Apps-owned consumer namespace SecretStore
+`openbao-keycape-{client_id}-consumer` and its dedicated consumer identity.
+
+Store provisioning belongs to Platform's separate owner-controlled path. The
+proposed `platform-secret-delivery` lane retains ONLY create/get/watch/delete on
+the exact ExternalSecret in `sso`; this source does not delegate store creation
+or Secret read/list. Never apply the multi-document template through that lane.
+The pure `scripts/keycape_issuer_eso.py` module exposes only the ExternalSecret
+document through `external_secret()` and validates fixed public observations
+through `require_fixed_store()` and `require_ready_delivery()`. It performs no
+API call and issues no evidence/receipt. It is not a real capability or admission
+boundary; a caller-supplied observation alone establishes no authenticity.
+
+The existing RPF-1.3-T4 delivery binding must validate the case/client binding,
+verify this exact preexisting store's public identity/spec/Ready state, apply or
+compare the exact ExternalSecret, and wait for matching spec plus Ready=True.
+The proposed helper accepts extra controller metadata but deliberately refuses
+spec drift. Actual API defaulting/normalization and installed ESO schema support
+must be checked in that implementation; these fixtures establish no native
+compatibility or credential isolation. ESO's shared controller remains trusted.
+No Secret bodies, values, arbitrary remoteRefs, or raw errors may enter receipts.
+
+Existing owner requirements remain: closed `netkingdom.deliver-secret.v1`
+metadata receipt with authenticated before/after UID/resourceVersion provenance,
+unchanged objects reported NO_CHANGE, attempt-session revocation, and created-only
+rollback guarded by exact UID/resourceVersion (drift or uncertain ownership goes
+to owner reconciliation). The helper neither deletes a target Secret nor creates
+an OpenBao role/policy nor changes CCR-0041. These capabilities and catalog routing
+remain unimplemented/unaccepted under RPF-1.3-T4. Independent Platform source
+review of this declaration precedes adopting the conditional NetKingdom type
+text; no descriptor acceptance, acknowledgment, pin, grant, catalog or native
+permission is inferred.
+
+Grounding: CCR-2026-0041 exact role/identity; the approved historical
+`docs/provisioning-windows/2026-10-04-1000/keycape/eso.draft.yaml` issuer
+ClusterSecretStore and target pattern; `scripts/catalog_lane_scaffold.py`
+ClusterSecretStore/namespace restriction and mount-relative remoteRef model;
+RPF-1.3-C1 and RPF-1.3-T4 in the frozen owner review. The scaffold's historical
+audience field placement differs from the issuer draft; this candidate uses
+the issuer draft's serviceAccountRef.audiences, not a claim of installed support.
--- /dev/null
+++ b/manifests/templates/keycape-issuer-eso.yaml
@@ -0,0 +1,46 @@
+# PROPOSED SOURCE ONLY — RPF-1.3-T4 / NK48-R5-F2; not admitted or applied.
+# Platform controls this template. Only admitted client_id is substituted.
+# Provision the store through Platform's separate reviewed owner path; the
+# platform-secret-delivery lane applies ONLY the ExternalSecret document.
+apiVersion: external-secrets.io/v1
+kind: ClusterSecretStore
+metadata:
+ name: openbao-keycape-{client_id}-issuer
+spec:
+ provider:
+ vault:
+ server: http://openbao.openbao.svc:8200
+ path: platform
+ version: v2
+ auth:
+ kubernetes:
+ mountPath: kubernetes
+ role: external-secrets-keycape-{client_id}
+ serviceAccountRef:
+ name: external-secrets
+ namespace: external-secrets
+ audiences:
+ - openbao
+ conditions:
+ - namespaces:
+ - sso
+---
+apiVersion: external-secrets.io/v1
+kind: ExternalSecret
+metadata:
+ name: keycape-{client_id}-client
+ namespace: sso
+spec:
+ refreshInterval: 5m
+ secretStoreRef:
+ kind: ClusterSecretStore
+ name: openbao-keycape-{client_id}-issuer
+ target:
+ name: keycape-{client_id}-client
+ creationPolicy: Owner
+ deletionPolicy: Retain
+ data:
+ - secretKey: client-secret
+ remoteRef:
+ key: workloads/keycape/{client_id}
+ property: CLIENT_SECRET
--- /dev/null
+++ b/scripts/keycape_issuer_eso.py
@@ -0,0 +1,70 @@
+"""Proposed fixed issuer ESO source contract for RPF-1.3-T4 / NK48-R5-F2.
+
+Pure public metadata only. No API/credential/Secret access or apply path. This
+new declaration requires independent Platform review before type integration.
+The delivery lane may use only external_secret(); store provisioning is a
+separate owner action and is never delegated by this module.
+"""
+from __future__ import annotations
+
+from copy import deepcopy
+from pathlib import Path
+import re
+
+import yaml
+
+ROOT = Path(__file__).resolve().parents[1]
+TEMPLATE = ROOT / 'manifests/templates/keycape-issuer-eso.yaml'
+
+
+class Refused(ValueError):
+ """Fixed issuer metadata differs; never return an owner delivery receipt."""
+
+
+def documents(client_id: str) -> tuple[dict, dict]:
+ # Match the frozen type client_id pattern and existing adapter's derived bound.
+ # No caller can supply a store name/kind/namespace or an OpenBao path.
+ if not isinstance(client_id, str) or not re.fullmatch(r'[a-z0-9][a-z0-9-]{1,62}', client_id):
+ raise Refused('bounded admitted client_id required')
+ if len('keycape-' + client_id + '-client') > 63:
+ raise Refused('derived issuer reference exceeds existing adapter bound')
+ store, external = yaml.safe_load_all(TEMPLATE.read_text().format(client_id=client_id))
+ return store, external
+
+
+def external_secret(client_id: str) -> dict:
+ """The ONLY document the proposed delivery capability may apply."""
+ return deepcopy(documents(client_id)[1])
+
+
+def _matching_public_resource(observed: dict, expected: dict) -> None:
+ if not isinstance(observed, dict):
+ raise Refused('public resource observation required')
+ metadata = observed.get('metadata')
+ if not isinstance(metadata, dict):
+ raise Refused('resource metadata required')
+ expected_namespace = expected['metadata'].get('namespace')
+ namespace_matches = (metadata.get('namespace') == expected_namespace
+ if expected_namespace else metadata.get('namespace') in (None, ''))
+ if (observed.get('apiVersion') != expected['apiVersion']
+ or observed.get('kind') != expected['kind']
+ or metadata.get('name') != expected['metadata']['name']
+ or not namespace_matches
+ or observed.get('spec') != expected['spec']):
+ raise Refused('fixed issuer resource differs')
+ status = observed.get('status')
+ conditions = status.get('conditions', []) if isinstance(status, dict) else []
+ if not isinstance(conditions, list) or not any(
+ isinstance(c, dict) and c.get('type') == 'Ready' and c.get('status') == 'True'
+ for c in conditions):
+ raise Refused('fixed issuer resource not ready')
+
+
+def require_fixed_store(observed: dict, client_id: str) -> None:
+ """Refuse a missing/drifted/not-ready store; never create it through delivery."""
+ _matching_public_resource(observed, documents(client_id)[0])
+
+
+def require_ready_delivery(observed: dict, client_id: str) -> None:
+ """Spec equality and Ready precede a created/NO_CHANGE owner receipt."""
+ _matching_public_resource(observed, documents(client_id)[1])
--- /dev/null
+++ b/tests/test_keycape_issuer_eso.py
@@ -0,0 +1,129 @@
+"""Public metadata fixtures only: no API, credentials, or native calls."""
+import copy
+import sys
+import unittest
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
+import keycape_issuer_eso as contract
+
+
+class FixedIssuerContract(unittest.TestCase):
+ def observations(self):
+ resources = contract.documents("forgejo")
+ for resource in resources:
+ resource["metadata"].update(uid="public-fixture-uid", resourceVersion="7")
+ resource["status"] = {"conditions": [{"type": "Ready", "status": "True"}]}
+ return resources
+
+ def test_independent_forgejo_binding(self):
+ # Independent owner-source example: CCR0041 role/SA/audience and the
+ # existing issuer ESO draft's provider/target/relative key convention.
+ store, external = contract.documents("forgejo")
+ self.assertEqual(store["kind"], "ClusterSecretStore")
+ self.assertEqual(store["metadata"], {"name": "openbao-keycape-forgejo-issuer"})
+ self.assertEqual(store["spec"], {
+ "provider": {"vault": {
+ "server": "http://openbao.openbao.svc:8200", "path": "platform", "version": "v2",
+ "auth": {"kubernetes": {"mountPath": "kubernetes",
+ "role": "external-secrets-keycape-forgejo",
+ "serviceAccountRef": {"name": "external-secrets", "namespace": "external-secrets",
+ "audiences": ["openbao"]}}}}},
+ "conditions": [{"namespaces": ["sso"]}]})
+ self.assertEqual(external["metadata"], {"name": "keycape-forgejo-client", "namespace": "sso"})
+ self.assertEqual(external["spec"], {
+ "refreshInterval": "5m",
+ "secretStoreRef": {"kind": "ClusterSecretStore", "name": "openbao-keycape-forgejo-issuer"},
+ "target": {"name": "keycape-forgejo-client", "creationPolicy": "Owner", "deletionPolicy": "Retain"},
+ "data": [{"secretKey": "client-secret", "remoteRef": {
+ "key": "workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]})
+
+ def test_valid_ready_metadata_allows_extra_controller_metadata(self):
+ store, external = self.observations()
+ contract.require_fixed_store(store, "forgejo")
+ contract.require_ready_delivery(external, "forgejo")
+
+ def test_store_drift_refuses(self):
+ changes = [
+ ("kind", "SecretStore"),
+ ("metadata.namespace", "sso"),
+ ("metadata.name", "caller-store"),
+ ("spec.provider.vault.server", "https://wrong.invalid"),
+ ("spec.provider.vault.path", "tenant"),
+ ("spec.provider.vault.auth.kubernetes.role", "external-secrets-keycape-sibling"),
+ ("spec.provider.vault.auth.kubernetes.serviceAccountRef.audiences", ["wrong"]),
+ ("spec.provider.vault.auth.kubernetes.serviceAccountRef.namespace", "sso"),
+ ("spec.conditions", [{"namespaces": ["sso", "other"]}]),
+ ]
+ for path, value in changes:
+ with self.subTest(path=path):
+ store = self.observations()[0]
+ mutate(store, path, value)
+ with self.assertRaises(contract.Refused):
+ contract.require_fixed_store(store, "forgejo")
+
+ def test_external_drift_refuses(self):
+ changes = [
+ ("metadata.namespace", ""), ("metadata.namespace", None), ("metadata.namespace", "other"),
+ ("metadata.name", "keycape-sibling-client"),
+ ("spec.secretStoreRef.kind", "SecretStore"),
+ ("spec.secretStoreRef.name", "openbao-keycape-forgejo-consumer"),
+ ("spec.target.name", "other"), ("spec.target.creationPolicy", "Merge"),
+ ("spec.target.deletionPolicy", "Delete"),
+ ("spec.data", [{"secretKey": "client-secret", "remoteRef": {
+ "key": "platform/workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]),
+ ("spec.data", [{"secretKey": "wrong", "remoteRef": {
+ "key": "workloads/keycape/forgejo", "property": "CLIENT_SECRET"}}]),
+ ("spec.data", [{"secretKey": "client-secret", "remoteRef": {
+ "key": "workloads/keycape/forgejo", "property": "wrong"}}]),
+ ]
+ for path, value in changes:
+ with self.subTest(path=path, value=value):
+ external = self.observations()[1]
+ mutate(external, path, value)
+ with self.assertRaises(contract.Refused):
+ contract.require_ready_delivery(external, "forgejo")
+
+ def test_missing_or_unready_refuses(self):
+ for check, index in [(contract.require_fixed_store, 0), (contract.require_ready_delivery, 1)]:
+ for status in [None, {}, [], "bad", {"conditions": None},
+ {"conditions": [{"type": "Ready", "status": "False"}]}]:
+ with self.subTest(check=check.__name__, status=status):
+ observed = self.observations()[index]
+ observed["status"] = status
+ with self.assertRaises(contract.Refused):
+ check(observed, "forgejo")
+ for malformed in [None, [], {}, {"metadata": None}]:
+ with self.assertRaises(contract.Refused):
+ check(malformed, "forgejo")
+
+ def test_no_caller_store_or_path_override(self):
+ for invalid in ["", "f", "../forgejo", "forgejo/sibling", "Forgejo", "forgejo\n", "-forgejo", "f" * 49, None]:
+ with self.subTest(invalid=invalid), self.assertRaises(contract.Refused):
+ contract.documents(invalid)
+ with self.assertRaises(TypeError):
+ contract.external_secret("forgejo", store_name="caller-store")
+
+ def test_type_admitted_trailing_dash_is_preserved(self):
+ self.assertEqual(contract.external_secret("forgejo-")["metadata"]["name"],
+ "keycape-forgejo--client")
+ self.assertEqual(contract.documents("forgejo-")[0]["metadata"]["name"],
+ "openbao-keycape-forgejo--issuer")
+
+ def test_delivery_document_is_only_external_and_detached(self):
+ external = contract.external_secret("forgejo")
+ self.assertEqual(external["kind"], "ExternalSecret")
+ external["spec"]["secretStoreRef"]["name"] = "tampered"
+ self.assertEqual(contract.external_secret("forgejo")["spec"]["secretStoreRef"]["name"],
+ "openbao-keycape-forgejo-issuer")
+
+
+def mutate(resource, path, value):
+ parts = path.split(".")
+ for key in parts[:-1]:
+ resource = resource[key]
+ resource[parts[-1]] = copy.deepcopy(value)
+
+
+if __name__ == "__main__":
+ unittest.main(verbosity=2)

View file

@ -0,0 +1,66 @@
{
"schema": "custodian.nk48-r5-f2-implementation-candidate.v1",
"status": "proposed-source-not-admitted",
"date": "2026-10-17",
"scope": "NK-WP-0048-T16; existing RPF-1.3-T4 implementation preparation only",
"source_owner_assent_received": false,
"finding": "NK48-R5-F2",
"owner_requirement": "RPF-1.3-C1",
"netkingdom_base": "3236d5000e52e0643f33906a26a7825aa0b67465",
"reviewed_code": "001a38ca2aa85155ce4840c4da22aca6e2346171",
"platform_base": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"discovery": "No existing Forgejo issuer store declaration found in bounded public source search. No claim about live absence.",
"new_proposed_binding": {
"kind": "ClusterSecretStore",
"name": "openbao-keycape-{client_id}-issuer",
"namespace": null,
"allowed_external_secret_namespace": "sso",
"role": "external-secrets-keycape-{client_id}",
"service_account_ref": "external-secrets/external-secrets",
"audiences": [
"openbao"
],
"template_path": "manifests/templates/keycape-issuer-eso.yaml",
"template_sha256": "e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743",
"external_secret": "sso/keycape-{client_id}-client",
"secret_key": "client-secret",
"provider_mount": "platform",
"remote_ref_key": "workloads/keycape/{client_id}",
"remote_ref_property": "CLIENT_SECRET",
"target_creation_policy": "Owner",
"remote_deletion_policy": "Retain"
},
"candidate_patches": {
"platform.candidate.patch": "a490df7dee41e15351da8d2906e1342edebb533984befe3d9ae74d952dbb091b",
"netkingdom-entry-point.conditional.patch": "6784a21fbd10bd62712be2e0f4929034601c94629aa74ccaa2e93fc815eecd61"
},
"checks": {
"tests_passed": 8,
"subtests_passed": 42,
"patch_dryruns_passed": true,
"only_type_structural_delta": "spec.follow_through[id=deliver-secret].entry_point",
"parameters_bytes_unchanged": true
},
"remaining_existing_owner_work": [
"Independent Platform review/adoption of explicit template and metadata helper under RPF-1.3-T4; no assent inferred.",
"After that review, integrate the conditional NetKingdom text with F3 and regenerate combined composition artifact through existing owner path.",
"RPF-1.3-T4 real authenticated deliver/remove/evidence/session capabilities and catalog routing acceptance remain separate existing requirements.",
"Actual approved owner execution must establish installed ESO compatibility, authentic resource observation, fixed preexisting store and receipt/rollback semantics; source fixtures prove none of these."
],
"changes_not_made": [
"canonical checkouts",
"workplans/tasks/UUIDs",
"descriptors",
"catalog",
"CCR0041/grants",
"pins/acknowledgments",
"default 1.1 or revision 1.2",
"native resources",
"credentials/Secret values"
],
"knowledge": {
"version": "0.2.6",
"digest": "8d1d6a9d4d07fec7b619618de7dfe2be2254c1790f85f4198c7fe19db9751c02",
"status": "withheld-orientation-only; current source SECURITY-COMPANION and actual owner contracts reviewed; no authority inferred"
}
}

View file

@ -0,0 +1,108 @@
[
{
"repo": "net-kingdom",
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"path": "security-case-type-revisions/1.3/oidc-browser-relying-party/type.yaml",
"sha256": "e75fe94110ef9fb7fb18072fe2856941b33507c99cb406d36576046481485d0a",
"working_tree_equals_commit": true,
"line_anchors": [
14,
17,
269,
270,
273
]
},
{
"repo": "net-kingdom",
"commit": "3236d5000e52e0643f33906a26a7825aa0b67465",
"path": "sso-mfa/k8s/keycape/deliver-secret-adapter.py",
"sha256": "cd1a515a1ae2def2093660ed2a810a9c66d1d4cf7126f573ee7e9c4c42afb98d",
"working_tree_equals_commit": true,
"line_anchors": [
47,
60,
94,
98
]
},
{
"repo": "railiance-platform",
"commit": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"path": "credential-change-requests/CCR-2026-0041-forgejo-netkingdom-oidc-keycape-eso-reader.yaml",
"sha256": "e69077ad29166770e4a57b4c4105615e272822d8fde11df591d0c127b158ac67",
"working_tree_equals_commit": true,
"line_anchors": [
40,
44,
52,
56,
66,
89
]
},
{
"repo": "railiance-platform",
"commit": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"path": "docs/provisioning-windows/2026-10-04-1000/keycape/eso.draft.yaml",
"sha256": "c8c334fae9d7e7e2f74ac30095d2266d626e857f7c5a85ad4e20b28543678c5d",
"working_tree_equals_commit": true,
"line_anchors": [
3,
5,
16,
18,
19,
22,
26,
33,
43,
55
]
},
{
"repo": "railiance-platform",
"commit": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"path": "docs/credential-lane-designs/keycape-secrets-engine-openbao-issuer-input.yaml",
"sha256": "ade2e10b0f65341051b955900c68931bdd56fd3a81bf452ae81229cc2390ad63",
"working_tree_equals_commit": true,
"line_anchors": [
44,
56
]
},
{
"repo": "railiance-platform",
"commit": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"path": "scripts/catalog_lane_scaffold.py",
"sha256": "96d60cc47aa78728f5ba96ce1fd63033adf23c05641de93ebbdda3902082d2d1",
"working_tree_equals_commit": true,
"line_anchors": [
137,
144,
145,
149,
154
]
},
{
"repo": "railiance-platform",
"commit": "0a9617a62d4696a8070798923b459e8405c3dbf2",
"path": "argocd/platform-addons/openbao-secretstore/openbao-keycape-approval-clients.clustersecretstore.yaml",
"sha256": "9ce6533e652db5428248c37319b6096a5f8f4af82138141473de4d4ca809e692",
"working_tree_equals_commit": true,
"line_anchors": [
1
]
},
{
"repo": "the-custodian",
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-adapters-1.2-review/coordinator-review-r5.json",
"sha256": "e3016352c58178894ccbfc600b960d3f9e2b5d534a05b8df2c5b79737cb0127a"
},
{
"repo": "the-custodian",
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-1.3-owner-review/owner-review-railiance-platform.json",
"sha256": "d3f523b60924b530376b7aac4459cecda5da183848dd6e35889c1013c73439d9"
}
]

View file

@ -0,0 +1,8 @@
{
"only_structural_delta": "spec.follow_through[id=deliver-secret].entry_point",
"parameters_raw_bytes_identical": true,
"descriptor_changes": false,
"canonical_1_1_1_2_changes": false,
"base": "3236d5000e52e0643f33906a26a7825aa0b67465",
"both_patch_dryruns_exit": 0
}

View file

@ -0,0 +1,495 @@
apiVersion: netkingdom.io/security-case-type/v0.1
kind: SecurityCaseType
spec:
id: oidc-browser-relying-party
version: '1.3'
status: proposed
title: Browser OIDC relying party for an internal service
purpose: 'Let an internal web service sign its human users in through NetKingdom
(KeyCape): an exact-redirect OIDC client, optional MFA pin, the LLDAP groups the
service maps to its own roles, and, for confidential clients, a client secret
minted straight into OpenBao custody. Replaces the per-client rollout scripts
in sso-mfa/k8s/keycape. First case: Forgejo (KEY-WP-0038).'
parameters:
- name: client_id
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{1,62}$
sensitivity: operational
description: OAuth2 client_id, unique in KeyCape.
- name: display_name
type: string
case_settable: true
constraints:
pattern: ^[^\n\r]{1,80}$
sensitivity: public
description: Name shown on the sign-in page.
- name: redirect_uris
type: string
case_settable: true
constraints:
pattern: ^https://[^*?#\s,]+(,https://[^*?#\s,]+)*$
sensitivity: security_sensitive
description: 'Comma-separated exact https redirect URIs. No wildcards, no plain
http, no query and no fragment: KeyCape refuses ''*'' and ''?'' at startup,
and OAuth 2.0 forbids fragments (key-cape type review R1).'
- name: allowed_scopes
type: string
case_settable: true
constraints:
enum:
- openid,profile,email,groups
- openid,email,groups
- openid,profile,groups
- openid,groups
sensitivity: security_sensitive
description: Scopes the client may request, openid first. Always includes groups,
because access_groups is required and KeyCape's UserInfo returns groups only
for that scope (key-cape type review R2).
- name: client_type
type: string
case_settable: true
constraints:
enum:
- confidential
- public
sensitivity: security_sensitive
description: confidential for server-side services that can hold a secret; public
for SPAs and native apps (PKCE only).
- name: mfa_required
type: string
case_settable: true
constraints:
enum:
- 'true'
- 'false'
sensitivity: security_sensitive
description: '"true" pins MFA on this client; required when the service grants
administrative or owner rights. "false" is not "no MFA": the client then carries
no mfaRequired field and KeyCape applies the per-user privacyIDEA policy. A
renderer must never emit an explicit mfaRequired false, which would skip that
policy (key-cape type review R3).'
- name: access_groups
type: string
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]{1,62}(,[a-z][a-z0-9-]{1,62})*$
sensitivity: operational
description: 'Comma-separated LLDAP groups that the service maps to its roles.
Created if absent. KeyCape has no per-client group gate: it issues tokens to
any authenticated user and only carries the groups claim, so the consuming service
enforces the gate itself (for Forgejo, its required-claim setting; key-cape
type review R2).'
- name: initial_members
type: string
required: false
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*(;[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*)*$
sensitivity: operational
description: Initial memberships as group=user+user;group=user. Usernames are
directory usernames, never secrets.
- name: consuming_service
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{0,62}$
sensitivity: operational
description: The service that signs users in with this client.
- name: consumer_owner_repo
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]*$
sensitivity: operational
description: The repository that owns the consuming service's configuration.
- name: consumer_namespace
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
sensitivity: security_sensitive
description: Consumer namespace for namespaced ESO TokenRequest reader; actual
workload owner must confirm; never infer from service name.
- name: issuer
type: string
case_settable: false
default: https://kc.coulomb.social
sensitivity: security_sensitive
description: The NetKingdom issuer; fixed by the type.
composition:
authority: netkingdom
initial_trust:
- runtime_secret_trust
- runtime_identity_trust
capabilities:
- c1.lightweight-sso
providers:
c1.lightweight-sso: net-kingdom.keycape-client-registration
parameter_bindings:
net-kingdom.keycape-client-registration.client_id: client_id
net-kingdom.keycape-client-registration.display_name: display_name
net-kingdom.keycape-client-registration.redirect_uris: redirect_uris
net-kingdom.keycape-client-registration.allowed_scopes: allowed_scopes
net-kingdom.keycape-client-registration.client_type: client_type
net-kingdom.keycape-client-registration.mfa_required: mfa_required
materialization:
- id: client-secret-path
kind: kv_path
when: client_type == confidential
template: platform/workloads/keycape/{client_id}
body: field CLIENT_SECRET; minted by the credential broker, never written by hand
- id: keycape-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-eso
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: KeyCape reads its client secret only through ESO. No metadata, list,
parent or sibling access.
- id: consumer-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-{consuming_service}
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: The consuming service reads the same secret. No metadata, list, parent
or sibling access.
- id: eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}
body: 'auth: kubernetes
bound_service_account_names: [external-secrets]
bound_service_account_namespaces: [external-secrets]
token_policies: [workload-kv-read-keycape-{client_id}-eso]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: The Kubernetes-auth role deliver-secret uses; bound to the ESO service
account only.
- id: consumer-eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}-{consuming_service}
body: 'auth: kubernetes
bound_service_account_names: [{consuming_service}-keycape-{client_id}-eso]
bound_service_account_namespaces: [{consumer_namespace}]
audience: openbao
token_policies: [workload-kv-read-keycape-{client_id}-{consuming_service}]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: Consumer ESO requests a token for this separate reference identity.
Common ESO controller remains trusted and can request tokens; no cryptographic
controller isolation is claimed.
- id: catalog-entry
kind: catalog_entry
template: '{consuming_service}-keycape-client'
body: 'id: {consuming_service}-keycape-client
owner_repo: key-cape
warden_executes: false
risk: high
status: active once verification passes
workload_ref: applicable, name {consuming_service}, declaration_ref of the consumer''s
published declaration or the explicit unknown form, never inferred
path_template: platform/workloads/keycape/{client_id}
field: CLIENT_SECRET
delegation: native, intended_owner key-cape
rotation: mint-secret then verification; automatable false until a run has been
proven
'
description: One entry per case (ops-mason item 5, ops-warden R4'). It carries
the consumer's workload reference, which ADR-0009 needs for zone selection.
follow_through:
- id: ensure-groups
owner: net-kingdom
entry_point: reviewed adapter net-kingdom/keycape-ensure-groups, dispatched by Warden's
case kernel inside the attended session; it calls identity-provisioner
ensure_service_groups in the provisioner pod through the session's contained
cluster access (groups {access_groups}; members exactly {initial_members} as
recorded in the accepted case, nothing else)
auth: the attended human session on lane keycape-attended-case-change (actor human,
parent-session revoked per attempt); the in-pod call uses the provisioner's own
directory binding, and no provisioner or user-engine token is read or sent
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: The provisioner's only HTTP credential is user-engine's
runtime token, and its NetworkPolicy admits only user-engine pods. A proxy lane
would act as user-engine (ops-warden review R8; canon section 3; ops-warden
ADR-0002). Running it in the session register-client already needs adds no attended
session. It can become unattended once the provisioner has an operator credential
of its own and an admitted path. Warden's case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.
- id: mint-secret
owner: railiance-platform
when: client_type == confidential
entry_point: 'railiance-platform credential broker: generate a client secret inside
custody at bao:platform/workloads/keycape/{client_id}, through reviewed adapter
railiance-platform/keycape-mint-secret'
auth: a human caller (net-kingdom-admins, aal2) starts it; Warden runs it unattended
through the broker lane under the caller's session, with the caller's broker grant
for the case's KV path; agents and root are refused, and the value is generated
in custody and never returned
lane: keycape-client-secret-generate
warden_executes: true
attended: false
value_handling: generated_in_custody
- id: deliver-secret
owner: railiance-platform
when: client_type == confidential
entry_point: reviewed adapter railiance-platform/keycape-deliver-secret, dispatched
by Warden's case kernel; Platform's deliver capability applies ExternalSecret
sso/keycape-{client_id}-client (key client-secret) through the ESO store for
role external-secrets-keycape-{client_id}, from bao:platform/workloads/keycape/{client_id}
auth: Platform's own delivery path on lane platform-secret-delivery, inside the human
aal2 session; ESO reads custody through role external-secrets-keycape-{client_id};
Warden holds no Platform credential, and no value leaves custody
lane: platform-secret-delivery
warden_executes: false
attended: false
value_handling: none
ready_check: the delivery for sso/keycape-{client_id}-client reports Ready=True
(status only, no value read)
- id: bind-env
owner: net-kingdom
when: client_type == confidential
entry_point: 'reviewed adapter net-kingdom/keycape-bind-env, dispatched by Warden''s
case kernel inside the attended session: patch Deployment sso/keycape env
KEYCAPE_{client_id:env}_CLIENT_SECRET from sso/keycape-{client_id}-client, by
reference only'
auth: the attended human session on lane keycape-attended-case-change, with operator
kube credentials for namespace sso (actor human, parent-session revoked per attempt)
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: A change to the live identity provider's Deployment. It
runs in the same attended operator session as register-client, before it, because
KeyCape resolves a confidential client's secret at start and fails closed if
the binding is missing. Warden's case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.
- id: register-client
owner: net-kingdom
entry_point: reviewed adapter net-kingdom/keycape-register-client, dispatched by Warden's
case kernel inside the attended session; it runs sso-mfa/k8s/keycape/keycape-client.py
apply --client-file <client-from-case> --case-acceptance <record> --check-config
<keycape binary> (net-kingdom.keycape-client-registration)
auth: the attended human session on lane keycape-attended-case-change, with operator
write access to the live KeyCape client registry in namespace sso (actor human,
parent-session revoked per attempt)
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: 'The live KeyCape client registry is a Kubernetes Secret,
and agents do not read or write Secrets. Until KeyCape loads clients from a
non-secret registry with secrets referenced from custody, one attended operator
session applies the rendered registration. ops-warden groups all attended steps
of a run into that one session. KeyCape loads clients at startup and keeps login,
authorization and handoff state in memory, so the restart drops in-flight logins
and sessions for every client; runs go in a quiet window (key-cape type review
R4). The rendered registry must pass KeyCape''s own startup checks (keycape
check-config, the pinned checker artifact sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5
built from key-cape 3c71226, which keycape-client.py runs before it patches)
before the restart: a refused entry stops the single replica and every client
loses sign-in (R1). Warden''s case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.'
- id: deliver-consumer-secret
owner: '{consumer_owner_repo}'
when: client_type == confidential
entry_point: Reviewed adapter net-kingdom/keycape-deliver-consumer-secret, dispatched
by Warden's case kernel inside the attended consumer-owner session; the owner's
apply capability creates dedicated ServiceAccount {consumer_namespace}/{consuming_service}-keycape-{client_id}-eso
(automount=false, no legacy tokens), namespace SecretStore openbao-keycape-{client_id}-consumer
with serviceAccountRef and audiences [openbao], and ExternalSecret {consuming_service}-netkingdom-oidc-client
with Owner target, Retain remote deletion and only CLIENT_SECRET from workloads/keycape/{client_id}.
Admission validates actual installed ESO TokenRequest support and common controller
RBAC before any owner-approved apply.
auth: the attended consumer-owner session on lane consumer-owner-deployment (actor
human, the consumer owner's operator deployment authority, on the founder's go
for the change); ESO authenticates to OpenBao role external-secrets-keycape-{client_id}-{consuming_service}
with a TokenRequest for the dedicated namespaced serviceAccountRef; controller
remains trusted
lane: consumer-owner-deployment
warden_executes: false
attended: true
value_handling: none
attended_justification: The consumer owner's only deployment authority in the consumer
namespace is its operator credential, and production applies need the founder's
go per change. No contained agent deployer identity exists, and the owner does
not want a standing credential an agent could trigger. It runs in one attended
consumer-owner session together with hand-over. Warden's case kernel dispatches
the reviewed adapter only inside that session (actor human, parent-session
revoked per attempt); the human session is the authority and the kernel is only
the dispatcher.
ready_check: Namespace SecretStore and ExternalSecret both report Ready=True;
dedicated SA has no legacy token refs; status and fixed metadata only, never
Secret values.
- id: hand-over
owner: '{consumer_owner_repo}'
entry_point: The consumer owner first makes its own Helm change configuring {consuming_service}
with issuer {issuer}, client {client_id} and custody bao:platform/workloads/keycape/{client_id},
requiring one of {access_groups} in the groups claim before sign-in completes.
Then reviewed adapter net-kingdom/keycape-hand-over, dispatched by Warden's case
kernel inside the attended consumer-owner session, verifies the consumer with
four value-free probes (member-login, non-member-refused, membership-add-grants,
membership-remove-revokes) and records the hand-over receipt.
auth: the attended consumer-owner session on lane apps-consumer-handover (actor human,
parent-session revoked per attempt); the consumer configuration itself is the
owner's own deployment path
lane: apps-consumer-handover
warden_executes: false
attended: true
value_handling: none
attended_justification: The verification needs a real member login and a refused
non-member login, which only an attended session can perform, and it follows
the owner's own Helm change in the same consumer-owner session as
deliver-consumer-secret. Warden's case kernel dispatches the reviewed adapter
only inside that session (actor human, parent-session revoked per attempt); the
human session is the authority and the kernel is only the dispatcher.
verification:
- id: authorize-accepts-redirects
check: GET {issuer}/authorize with client {client_id} and each of {redirect_uris}
returns the login page
expect: present
reads_secret_value: false
- id: authorize-refuses-other-redirect
check: GET {issuer}/authorize with client {client_id} and an unregistered redirect
returns an OAuth error
expect: deny
reads_secret_value: false
- id: custody-denied-to-default
when: client_type == confidential
check: a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/{client_id}
expect: deny
reads_secret_value: false
- id: custody-allowed-to-consumer
when: client_type == confidential
check: policy workload-kv-read-keycape-{client_id}-{consuming_service} grants
read on bao:platform/workloads/keycape/{client_id} (capabilities check only)
expect: allow
reads_secret_value: false
- id: groups-present
check: LLDAP groups {access_groups} exist, with exactly the memberships of the
accepted case added
expect: present
reads_secret_value: false
- id: consumer-enforces-groups
check: '{consuming_service}''s OIDC source for {client_id} (owner {consumer_owner_repo})
requires one of {access_groups} in the groups claim (configuration read, no
secret value)'
expect: present
reads_secret_value: false
- id: secret-delivered
when: client_type == confidential
check: the delivery for sso/keycape-{client_id}-client reports Ready=True (status
only)
expect: present
reads_secret_value: false
- id: mfa-pinned
when: mfa_required == true
check: keycape-client.py inspect for {client_id} shows the MFA pin on the registered
client (non-secret client view)
expect: present
reads_secret_value: false
- id: consumer-secret-delivered
when: client_type == confidential
check: '{consumer_namespace} SecretStore openbao-keycape-{client_id}-consumer
and ExternalSecret {consuming_service}-netkingdom-oidc-client Ready=True, exact
dedicated SA/audience role binding, fixed CLIENT_SECRET mapping; no Secret value
read'
expect: present
reads_secret_value: false
rollback:
- reverses: hand-over
action: the adapter removes only its hand-over receipt. Removing the OIDC source
for {client_id} from {consuming_service} is the owner's Helm rollback (owner
{consumer_owner_repo}), done inside deliver-consumer-secret's owner_remove
before any consumer object is removed
- reverses: deliver-consumer-secret
when: client_type == confidential
action: After reverting consumer secret reference, delete only authenticated created
ExternalSecret/owned target by UID and ownerReference, then SecretStore and
dedicated SA; preserve preexisting-matched resources and never delete a shared
target. Retain audit and ownership receipts; removing SecretStore/SA alone is
not immediate OpenBao token revocation.
- reverses: register-client
action: keycape-client.py apply --operation remove for {client_id}
- reverses: bind-env
when: client_type == confidential
action: remove env KEYCAPE_{client_id:env}_CLIENT_SECRET from Deployment sso/keycape,
after register-client is reversed
- reverses: deliver-secret
when: client_type == confidential
action: delete ExternalSecret sso/keycape-{client_id}-client and its target
- reverses: mint-secret
when: client_type == confidential
action: 'covered by client-secret-path: one metadata delete, after deliver-secret
is reversed'
- reverses: ensure-groups
action: identity-provisioner revoke_service_groups inside the provisioner pod
(attended, as ensure-groups) with the case's memberships; delete_if_empty only
if no other case uses {access_groups}
- reverses: client-secret-path
when: client_type == confidential
action: delete metadata and all versions at platform/workloads/keycape/{client_id},
after the ExternalSecret is gone (this also reverses mint-secret)
- reverses: eso-role
when: client_type == confidential
action: delete Kubernetes-auth role external-secrets-keycape-{client_id}
- reverses: keycape-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-eso, after eso-role
- reverses: consumer-eso-role
when: client_type == confidential
action: Delete only this case-created role external-secrets-keycape-{client_id}-{consuming_service},
before deleting consumer-reader-policy; revoke case-issued OpenBao tokens or
prove expiration before declaring deactivation.
- reverses: consumer-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-{consuming_service}
- reverses: catalog-entry
action: remove catalog entry {consuming_service}-keycape-client
acceptance:
accepted_by:
- owner
- founder
risk_class: medium
# Reviewed machine descriptors (NK-WP-0048-T16 successor candidate). Digests are
# generated by sso-mfa/k8s/keycape/compose-1.2-descriptors.py --version 1.3.
execution_descriptors:
bind-env: sha256:d5fcb20cf15bf7454890d2529180c582218e3df12584a99162e4b664b899caa0
deliver-consumer-secret: sha256:36281df8139fb1ec64b226d94f80eb592de5addab7063ff54c691c641e275fc7
deliver-secret: sha256:75aaa7346aebdea2a0eb0ba993995515b5248ffefc34caf8e713525e9b58da85
ensure-groups: sha256:ebc9d5b9167d18e6015f4bbeb9699e8d396d64fbfaf195142781f84f4f47a70a
hand-over: sha256:1bce07a3229b7d0c7c730f35ce5b40fe471009a82de8dd53788ed970a9be1224
mint-secret: sha256:c92957227235db04953809d92b260d32c8b947472a8e8fd17a258ade3ae8da70
register-client: sha256:4ecc769f75433b66c7161f13c0fe7e5599633cf466d46cb6d8031f0456f426e7

View file

@ -0,0 +1,498 @@
apiVersion: netkingdom.io/security-case-type/v0.1
kind: SecurityCaseType
spec:
id: oidc-browser-relying-party
version: '1.3'
status: proposed
title: Browser OIDC relying party for an internal service
purpose: 'Let an internal web service sign its human users in through NetKingdom
(KeyCape): an exact-redirect OIDC client, optional MFA pin, the LLDAP groups the
service maps to its own roles, and, for confidential clients, a client secret
minted straight into OpenBao custody. Replaces the per-client rollout scripts
in sso-mfa/k8s/keycape. First case: Forgejo (KEY-WP-0038).'
parameters:
- name: client_id
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{1,62}$
sensitivity: operational
description: OAuth2 client_id, unique in KeyCape.
- name: display_name
type: string
case_settable: true
constraints:
pattern: ^[^\n\r]{1,80}$
sensitivity: public
description: Name shown on the sign-in page.
- name: redirect_uris
type: string
case_settable: true
constraints:
pattern: ^https://[^*?#\s,]+(,https://[^*?#\s,]+)*$
sensitivity: security_sensitive
description: 'Comma-separated exact https redirect URIs. No wildcards, no plain
http, no query and no fragment: KeyCape refuses ''*'' and ''?'' at startup,
and OAuth 2.0 forbids fragments (key-cape type review R1).'
- name: allowed_scopes
type: string
case_settable: true
constraints:
enum:
- openid,profile,email,groups
- openid,email,groups
- openid,profile,groups
- openid,groups
sensitivity: security_sensitive
description: Scopes the client may request, openid first. Always includes groups,
because access_groups is required and KeyCape's UserInfo returns groups only
for that scope (key-cape type review R2).
- name: client_type
type: string
case_settable: true
constraints:
enum:
- confidential
- public
sensitivity: security_sensitive
description: confidential for server-side services that can hold a secret; public
for SPAs and native apps (PKCE only).
- name: mfa_required
type: string
case_settable: true
constraints:
enum:
- 'true'
- 'false'
sensitivity: security_sensitive
description: '"true" pins MFA on this client; required when the service grants
administrative or owner rights. "false" is not "no MFA": the client then carries
no mfaRequired field and KeyCape applies the per-user privacyIDEA policy. A
renderer must never emit an explicit mfaRequired false, which would skip that
policy (key-cape type review R3).'
- name: access_groups
type: string
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]{1,62}(,[a-z][a-z0-9-]{1,62})*$
sensitivity: operational
description: 'Comma-separated LLDAP groups that the service maps to its roles.
Created if absent. KeyCape has no per-client group gate: it issues tokens to
any authenticated user and only carries the groups claim, so the consuming service
enforces the gate itself (for Forgejo, its required-claim setting; key-cape
type review R2).'
- name: initial_members
type: string
required: false
case_settable: true
constraints:
pattern: ^[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*(;[a-z][a-z0-9-]*=[a-z][a-z0-9._-]*(\+[a-z][a-z0-9._-]*)*)*$
sensitivity: operational
description: Initial memberships as group=user+user;group=user. Usernames are
directory usernames, never secrets.
- name: consuming_service
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]{0,62}$
sensitivity: operational
description: The service that signs users in with this client.
- name: consumer_owner_repo
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9][a-z0-9-]*$
sensitivity: operational
description: The repository that owns the consuming service's configuration.
- name: consumer_namespace
type: string
case_settable: true
constraints:
pattern: ^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$
sensitivity: security_sensitive
description: Consumer namespace for namespaced ESO TokenRequest reader; actual
workload owner must confirm; never infer from service name.
- name: issuer
type: string
case_settable: false
default: https://kc.coulomb.social
sensitivity: security_sensitive
description: The NetKingdom issuer; fixed by the type.
composition:
authority: netkingdom
initial_trust:
- runtime_secret_trust
- runtime_identity_trust
capabilities:
- c1.lightweight-sso
providers:
c1.lightweight-sso: net-kingdom.keycape-client-registration
parameter_bindings:
net-kingdom.keycape-client-registration.client_id: client_id
net-kingdom.keycape-client-registration.display_name: display_name
net-kingdom.keycape-client-registration.redirect_uris: redirect_uris
net-kingdom.keycape-client-registration.allowed_scopes: allowed_scopes
net-kingdom.keycape-client-registration.client_type: client_type
net-kingdom.keycape-client-registration.mfa_required: mfa_required
materialization:
- id: client-secret-path
kind: kv_path
when: client_type == confidential
template: platform/workloads/keycape/{client_id}
body: field CLIENT_SECRET; minted by the credential broker, never written by hand
- id: keycape-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-eso
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: KeyCape reads its client secret only through ESO. No metadata, list,
parent or sibling access.
- id: consumer-reader-policy
kind: openbao_policy
when: client_type == confidential
template: workload-kv-read-keycape-{client_id}-{consuming_service}
body: "path \"platform/data/workloads/keycape/{client_id}\" {{\n capabilities\
\ = [\"read\"]\n}}\n"
description: The consuming service reads the same secret. No metadata, list, parent
or sibling access.
- id: eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}
body: 'auth: kubernetes
bound_service_account_names: [external-secrets]
bound_service_account_namespaces: [external-secrets]
token_policies: [workload-kv-read-keycape-{client_id}-eso]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: The Kubernetes-auth role deliver-secret uses; bound to the ESO service
account only.
- id: consumer-eso-role
kind: openbao_role
when: client_type == confidential
template: external-secrets-keycape-{client_id}-{consuming_service}
body: 'auth: kubernetes
bound_service_account_names: [{consuming_service}-keycape-{client_id}-eso]
bound_service_account_namespaces: [{consumer_namespace}]
audience: openbao
token_policies: [workload-kv-read-keycape-{client_id}-{consuming_service}]
token_no_default_policy: true
token_ttl: 15m
token_max_ttl: 15m
'
description: Consumer ESO requests a token for this separate reference identity.
Common ESO controller remains trusted and can request tokens; no cryptographic
controller isolation is claimed.
- id: catalog-entry
kind: catalog_entry
template: '{consuming_service}-keycape-client'
body: 'id: {consuming_service}-keycape-client
owner_repo: key-cape
warden_executes: false
risk: high
status: active once verification passes
workload_ref: applicable, name {consuming_service}, declaration_ref of the consumer''s
published declaration or the explicit unknown form, never inferred
path_template: platform/workloads/keycape/{client_id}
field: CLIENT_SECRET
delegation: native, intended_owner key-cape
rotation: mint-secret then verification; automatable false until a run has been
proven
'
description: One entry per case (ops-mason item 5, ops-warden R4'). It carries
the consumer's workload reference, which ADR-0009 needs for zone selection.
follow_through:
- id: ensure-groups
owner: net-kingdom
entry_point: reviewed adapter net-kingdom/keycape-ensure-groups, dispatched by Warden's
case kernel inside the attended session; it calls identity-provisioner
ensure_service_groups in the provisioner pod through the session's contained
cluster access (groups {access_groups}; members exactly {initial_members} as
recorded in the accepted case, nothing else)
auth: the attended human session on lane keycape-attended-case-change (actor human,
parent-session revoked per attempt); the in-pod call uses the provisioner's own
directory binding, and no provisioner or user-engine token is read or sent
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: The provisioner's only HTTP credential is user-engine's
runtime token, and its NetworkPolicy admits only user-engine pods. A proxy lane
would act as user-engine (ops-warden review R8; canon section 3; ops-warden
ADR-0002). Running it in the session register-client already needs adds no attended
session. It can become unattended once the provisioner has an operator credential
of its own and an admitted path. Warden's case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.
- id: mint-secret
owner: railiance-platform
when: client_type == confidential
entry_point: 'railiance-platform credential broker: generate a client secret inside
custody at bao:platform/workloads/keycape/{client_id}, through reviewed adapter
railiance-platform/keycape-mint-secret'
auth: a human caller (net-kingdom-admins, aal2) starts it; Warden runs it unattended
through the broker lane under the caller's session, with the caller's broker grant
for the case's KV path; agents and root are refused, and the value is generated
in custody and never returned
lane: keycape-client-secret-generate
warden_executes: true
attended: false
value_handling: generated_in_custody
- id: deliver-secret
owner: railiance-platform
when: client_type == confidential
entry_point: reviewed adapter railiance-platform/keycape-deliver-secret, dispatched
by Warden's case kernel; Platform's deliver capability applies ExternalSecret
sso/keycape-{client_id}-client (key client-secret) through fixed ClusterSecretStore
openbao-keycape-{client_id}-issuer (cluster-scoped, restricted to namespace sso),
defined by Platform-controlled manifests/templates/keycape-issuer-eso.yaml
(sha256:e17498bd8a4c820041a4105e4efe9c60c6a50953db8f621ff54887080065c743),
using role external-secrets-keycape-{client_id}, from bao:platform/workloads/keycape/{client_id}
auth: Platform's own delivery path on lane platform-secret-delivery, inside the human
aal2 session; ESO reads custody through role external-secrets-keycape-{client_id};
Warden holds no Platform credential, and no value leaves custody
lane: platform-secret-delivery
warden_executes: false
attended: false
value_handling: none
ready_check: the delivery for sso/keycape-{client_id}-client reports Ready=True
(status only, no value read)
- id: bind-env
owner: net-kingdom
when: client_type == confidential
entry_point: 'reviewed adapter net-kingdom/keycape-bind-env, dispatched by Warden''s
case kernel inside the attended session: patch Deployment sso/keycape env
KEYCAPE_{client_id:env}_CLIENT_SECRET from sso/keycape-{client_id}-client, by
reference only'
auth: the attended human session on lane keycape-attended-case-change, with operator
kube credentials for namespace sso (actor human, parent-session revoked per attempt)
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: A change to the live identity provider's Deployment. It
runs in the same attended operator session as register-client, before it, because
KeyCape resolves a confidential client's secret at start and fails closed if
the binding is missing. Warden's case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.
- id: register-client
owner: net-kingdom
entry_point: reviewed adapter net-kingdom/keycape-register-client, dispatched by Warden's
case kernel inside the attended session; it runs sso-mfa/k8s/keycape/keycape-client.py
apply --client-file <client-from-case> --case-acceptance <record> --check-config
<keycape binary> (net-kingdom.keycape-client-registration)
auth: the attended human session on lane keycape-attended-case-change, with operator
write access to the live KeyCape client registry in namespace sso (actor human,
parent-session revoked per attempt)
lane: keycape-attended-case-change
warden_executes: false
attended: true
value_handling: none
attended_justification: 'The live KeyCape client registry is a Kubernetes Secret,
and agents do not read or write Secrets. Until KeyCape loads clients from a
non-secret registry with secrets referenced from custody, one attended operator
session applies the rendered registration. ops-warden groups all attended steps
of a run into that one session. KeyCape loads clients at startup and keeps login,
authorization and handoff state in memory, so the restart drops in-flight logins
and sessions for every client; runs go in a quiet window (key-cape type review
R4). The rendered registry must pass KeyCape''s own startup checks (keycape
check-config, the pinned checker artifact sha256:be37738fe1c08259fb4f9ca0daf0f9301bfffc237e5bb38435525dfbf11ccff5
built from key-cape 3c71226, which keycape-client.py runs before it patches)
before the restart: a refused entry stops the single replica and every client
loses sign-in (R1). Warden''s case kernel dispatches the reviewed adapter only inside the one attended human session (descriptor actor human, lane keycape-attended-case-change, parent-session revoked per attempt); the human session is the authority and the kernel is only the dispatcher.'
- id: deliver-consumer-secret
owner: '{consumer_owner_repo}'
when: client_type == confidential
entry_point: Reviewed adapter net-kingdom/keycape-deliver-consumer-secret, dispatched
by Warden's case kernel inside the attended consumer-owner session; the owner's
apply capability creates dedicated ServiceAccount {consumer_namespace}/{consuming_service}-keycape-{client_id}-eso
(automount=false, no legacy tokens), namespace SecretStore openbao-keycape-{client_id}-consumer
with serviceAccountRef and audiences [openbao], and ExternalSecret {consuming_service}-netkingdom-oidc-client
with Owner target, Retain remote deletion and only CLIENT_SECRET from workloads/keycape/{client_id}.
Admission validates actual installed ESO TokenRequest support and common controller
RBAC before any owner-approved apply.
auth: the attended consumer-owner session on lane consumer-owner-deployment (actor
human, the consumer owner's operator deployment authority, on the founder's go
for the change); ESO authenticates to OpenBao role external-secrets-keycape-{client_id}-{consuming_service}
with a TokenRequest for the dedicated namespaced serviceAccountRef; controller
remains trusted
lane: consumer-owner-deployment
warden_executes: false
attended: true
value_handling: none
attended_justification: The consumer owner's only deployment authority in the consumer
namespace is its operator credential, and production applies need the founder's
go per change. No contained agent deployer identity exists, and the owner does
not want a standing credential an agent could trigger. It runs in one attended
consumer-owner session together with hand-over. Warden's case kernel dispatches
the reviewed adapter only inside that session (actor human, parent-session
revoked per attempt); the human session is the authority and the kernel is only
the dispatcher.
ready_check: Namespace SecretStore and ExternalSecret both report Ready=True;
dedicated SA has no legacy token refs; status and fixed metadata only, never
Secret values.
- id: hand-over
owner: '{consumer_owner_repo}'
entry_point: The consumer owner first makes its own Helm change configuring {consuming_service}
with issuer {issuer}, client {client_id} and custody bao:platform/workloads/keycape/{client_id},
requiring one of {access_groups} in the groups claim before sign-in completes.
Then reviewed adapter net-kingdom/keycape-hand-over, dispatched by Warden's case
kernel inside the attended consumer-owner session, verifies the consumer with
four value-free probes (member-login, non-member-refused, membership-add-grants,
membership-remove-revokes) and records the hand-over receipt.
auth: the attended consumer-owner session on lane apps-consumer-handover (actor human,
parent-session revoked per attempt); the consumer configuration itself is the
owner's own deployment path
lane: apps-consumer-handover
warden_executes: false
attended: true
value_handling: none
attended_justification: The verification needs a real member login and a refused
non-member login, which only an attended session can perform, and it follows
the owner's own Helm change in the same consumer-owner session as
deliver-consumer-secret. Warden's case kernel dispatches the reviewed adapter
only inside that session (actor human, parent-session revoked per attempt); the
human session is the authority and the kernel is only the dispatcher.
verification:
- id: authorize-accepts-redirects
check: GET {issuer}/authorize with client {client_id} and each of {redirect_uris}
returns the login page
expect: present
reads_secret_value: false
- id: authorize-refuses-other-redirect
check: GET {issuer}/authorize with client {client_id} and an unregistered redirect
returns an OAuth error
expect: deny
reads_secret_value: false
- id: custody-denied-to-default
when: client_type == confidential
check: a default-only OpenBao identity has no read capability on bao:platform/workloads/keycape/{client_id}
expect: deny
reads_secret_value: false
- id: custody-allowed-to-consumer
when: client_type == confidential
check: policy workload-kv-read-keycape-{client_id}-{consuming_service} grants
read on bao:platform/workloads/keycape/{client_id} (capabilities check only)
expect: allow
reads_secret_value: false
- id: groups-present
check: LLDAP groups {access_groups} exist, with exactly the memberships of the
accepted case added
expect: present
reads_secret_value: false
- id: consumer-enforces-groups
check: '{consuming_service}''s OIDC source for {client_id} (owner {consumer_owner_repo})
requires one of {access_groups} in the groups claim (configuration read, no
secret value)'
expect: present
reads_secret_value: false
- id: secret-delivered
when: client_type == confidential
check: the delivery for sso/keycape-{client_id}-client reports Ready=True (status
only)
expect: present
reads_secret_value: false
- id: mfa-pinned
when: mfa_required == true
check: keycape-client.py inspect for {client_id} shows the MFA pin on the registered
client (non-secret client view)
expect: present
reads_secret_value: false
- id: consumer-secret-delivered
when: client_type == confidential
check: '{consumer_namespace} SecretStore openbao-keycape-{client_id}-consumer
and ExternalSecret {consuming_service}-netkingdom-oidc-client Ready=True, exact
dedicated SA/audience role binding, fixed CLIENT_SECRET mapping; no Secret value
read'
expect: present
reads_secret_value: false
rollback:
- reverses: hand-over
action: the adapter removes only its hand-over receipt. Removing the OIDC source
for {client_id} from {consuming_service} is the owner's Helm rollback (owner
{consumer_owner_repo}), done inside deliver-consumer-secret's owner_remove
before any consumer object is removed
- reverses: deliver-consumer-secret
when: client_type == confidential
action: After reverting consumer secret reference, delete only authenticated created
ExternalSecret/owned target by UID and ownerReference, then SecretStore and
dedicated SA; preserve preexisting-matched resources and never delete a shared
target. Retain audit and ownership receipts; removing SecretStore/SA alone is
not immediate OpenBao token revocation.
- reverses: register-client
action: keycape-client.py apply --operation remove for {client_id}
- reverses: bind-env
when: client_type == confidential
action: remove env KEYCAPE_{client_id:env}_CLIENT_SECRET from Deployment sso/keycape,
after register-client is reversed
- reverses: deliver-secret
when: client_type == confidential
action: delete ExternalSecret sso/keycape-{client_id}-client and its target
- reverses: mint-secret
when: client_type == confidential
action: 'covered by client-secret-path: one metadata delete, after deliver-secret
is reversed'
- reverses: ensure-groups
action: identity-provisioner revoke_service_groups inside the provisioner pod
(attended, as ensure-groups) with the case's memberships; delete_if_empty only
if no other case uses {access_groups}
- reverses: client-secret-path
when: client_type == confidential
action: delete metadata and all versions at platform/workloads/keycape/{client_id},
after the ExternalSecret is gone (this also reverses mint-secret)
- reverses: eso-role
when: client_type == confidential
action: delete Kubernetes-auth role external-secrets-keycape-{client_id}
- reverses: keycape-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-eso, after eso-role
- reverses: consumer-eso-role
when: client_type == confidential
action: Delete only this case-created role external-secrets-keycape-{client_id}-{consuming_service},
before deleting consumer-reader-policy; revoke case-issued OpenBao tokens or
prove expiration before declaring deactivation.
- reverses: consumer-reader-policy
when: client_type == confidential
action: delete policy workload-kv-read-keycape-{client_id}-{consuming_service}
- reverses: catalog-entry
action: remove catalog entry {consuming_service}-keycape-client
acceptance:
accepted_by:
- owner
- founder
risk_class: medium
# Reviewed machine descriptors (NK-WP-0048-T16 successor candidate). Digests are
# generated by sso-mfa/k8s/keycape/compose-1.2-descriptors.py --version 1.3.
execution_descriptors:
bind-env: sha256:d5fcb20cf15bf7454890d2529180c582218e3df12584a99162e4b664b899caa0
deliver-consumer-secret: sha256:36281df8139fb1ec64b226d94f80eb592de5addab7063ff54c691c641e275fc7
deliver-secret: sha256:75aaa7346aebdea2a0eb0ba993995515b5248ffefc34caf8e713525e9b58da85
ensure-groups: sha256:ebc9d5b9167d18e6015f4bbeb9699e8d396d64fbfaf195142781f84f4f47a70a
hand-over: sha256:1bce07a3229b7d0c7c730f35ce5b40fe471009a82de8dd53788ed970a9be1224
mint-secret: sha256:c92957227235db04953809d92b260d32c8b947472a8e8fd17a258ade3ae8da70
register-client: sha256:4ecc769f75433b66c7161f13c0fe7e5599633cf466d46cb6d8031f0456f426e7

View file

@ -0,0 +1,43 @@
# F2 proposed source publication packet
Prepared local integration only; not executed against either canonical checkout.
`manifest.json` lists exact source hashes and absent preimages. Platform HEAD was
`0a9617a62d4696a8070798923b459e8405c3dbf2`; staged `.custodian-brief.md` and
unstaged `WORK-RECORDS.md` already existed. Preserve them.
Check, then apply the four reviewed files:
```bash
python3 /home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/integrate_platform.py
python3 /home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/integrate_platform.py --apply
```
The script checks the exact HEAD, absent tracked/worktree preimages, hashes and
symlink safety; it writes only the four manifest paths. It never stages, commits,
syncs, applies native resources or edits NetKingdom. The source remains explicitly
proposed/source-only, with no inferred owner assent. It verifies that unrelated
Git status and index bytes are unchanged. A concurrent failure may leave a
partial set of newly created files; inspect it rather than reset unrelated dirt.
Run the focused test in Platform, then stage only these paths. To keep the
preexisting staged brief out of the source commit, use a path-scoped commit:
```bash
git add -- docs/keycape-issuer-eso-contract.md manifests/templates/keycape-issuer-eso.yaml scripts/keycape_issuer_eso.py tests/test_keycape_issuer_eso.py
git commit --only -m "Prepare proposed fixed KeyCape issuer ESO source contract" -- docs/keycape-issuer-eso-contract.md manifests/templates/keycape-issuer-eso.yaml scripts/keycape_issuer_eso.py tests/test_keycape_issuer_eso.py
```
Root handles the already-authorized normal repository sync and its exact-commit
receipt. No task is marked done. `progress-paragraph.md` explains the completed
source-fit work and remaining real implementation. No legitimate Platform
workplan task was found: `RPF-1.3-T4` lives in the original owner-review JSON only.
Do not append the paragraph to an unrelated finished workplan or create a new one.
`netkingdom-entry-point.conditional.patch` is the unchanged exact proposed-1.3
entry text from the reviewed packet. Keep it unapplied until F3 is combined and
the existing combined artifact regenerated. It edits only the issuer delivery
entry point, pins the exact template digest and grants no adoption or activation.
`integration-checks.json` records the isolated scratch application, preservation
of synthetic staged/unstaged dirt, rejection of non-absent preimages, and eight
passing focused tests. Tests used a minimal environment and local Git only.

View file

@ -0,0 +1,5 @@
{
"first_attempt": "missing /home/worsch/railiance-platform/.venv/bin/python; exit127; tests did not run",
"rerun": "env PYTHONDONTWRITEBYTECODE=1 HOME=/tmp PATH=/usr/bin:/bin python3 -B -m unittest discover -s tests -p test_keycape_issuer_eso.py -q",
"result": "8 tests passed; fixture-only metadata, no native/API calls"
}

View file

@ -0,0 +1,604 @@
{
"repo_slug": "railiance-platform",
"repo_path": "/home/worsch/railiance-platform",
"source_revision": "104ed90f42a9a86bf9fda343b49b65a85c9ee4b9",
"source_revision_reason": null,
"issues": [
{
"severity": "WARN",
"check_id": "C-35",
"message": "Repo Manager missing: README.md: README.md is required for flavor tooling",
"file_path": "README.md",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0015-T03' in workplan 'RPF-WP-0015' \u2014 decision 2fd5849c-240e-4d0a-bf07-5ebf8dfce3fd is resolved",
"file_path": "workplans/RPF-WP-0015-audit-core-custody-and-recovery-coordination.md#RPF-WP-0015-T03",
"db_id": "",
"file_value": "2fd5849c-240e-4d0a-bf07-5ebf8dfce3fd",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0035-T02' in workplan 'RPF-WP-0035' \u2014 decision 62aa95e4-3ccc-4867-8806-5e3db005b483 is resolved",
"file_path": "workplans/RPF-WP-0035-credential-lane-implementation.md#RPF-WP-0035-T02",
"db_id": "",
"file_value": "62aa95e4-3ccc-4867-8806-5e3db005b483",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0035-T03' in workplan 'RPF-WP-0035' \u2014 decision 62aa95e4-3ccc-4867-8806-5e3db005b483 is resolved",
"file_path": "workplans/RPF-WP-0035-credential-lane-implementation.md#RPF-WP-0035-T03",
"db_id": "",
"file_value": "62aa95e4-3ccc-4867-8806-5e3db005b483",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0035-T07' in workplan 'RPF-WP-0035' \u2014 decision 1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa is resolved",
"file_path": "workplans/RPF-WP-0035-credential-lane-implementation.md#RPF-WP-0035-T07",
"db_id": "",
"file_value": "1591daa1-6e85-4dfd-aadd-5a9fe1ef47fa",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0035-T08' in workplan 'RPF-WP-0035' \u2014 decision ab85ae8a-12a0-4945-ae64-1d3d86d5b26f is resolved",
"file_path": "workplans/RPF-WP-0035-credential-lane-implementation.md#RPF-WP-0035-T08",
"db_id": "",
"file_value": "ab85ae8a-12a0-4945-ae64-1d3d86d5b26f",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0036-T03' in workplan 'RPF-WP-0036' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0036-platform-service-assurance.md#RPF-WP-0036-T03",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-39",
"message": "Wait task 'RPF-WP-0038-T04' in workplan 'RPF-WP-0038' has neither depends_on, needs_human: true, blocked_on: message-from:\u2026 nor wait_until \u2014 unqualified wait",
"file_path": "workplans/RPF-WP-0038-forgejo-scaleway-primary-coverage.md#RPF-WP-0038-T04",
"db_id": "",
"file_value": "wait",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0043-T03' in workplan 'RPF-WP-0043' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0043-policy-nexus-argocd-onboarding.md#RPF-WP-0043-T03",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0043-T04' in workplan 'RPF-WP-0043' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0043-policy-nexus-argocd-onboarding.md#RPF-WP-0043-T04",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0044-T04' in workplan 'RPF-WP-0044' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md#RPF-WP-0044-T04",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0044-T06' in workplan 'RPF-WP-0044' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md#RPF-WP-0044-T06",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0044-T07' in workplan 'RPF-WP-0044' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0044-argocd-phase-b-adopt-existing-applications.md#RPF-WP-0044-T07",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-40",
"message": "blocker satisfied, task still wait: 'RPF-WP-0048-T02' in workplan 'RPF-WP-0048' \u2014 decision 89f1058f-33bc-47a8-8a49-0b44d426c67e is resolved",
"file_path": "workplans/RPF-WP-0048-activity-core-gitops-adoption.md#RPF-WP-0048-T02",
"db_id": "",
"file_value": "89f1058f-33bc-47a8-8a49-0b44d426c67e",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-23",
"message": "Lifecycle drift in 'rpf-wp-0053': workplan status 'proposed' has an active task \u2014 report only (ADR-007: do not auto-promote proposed)",
"file_path": "workplans/RPF-WP-0053-coulomb-paired-backup-admission.md",
"db_id": "cb55e474-c7a5-5c6f-bd72-ce65f853e3e3",
"file_value": "proposed",
"db_value": "proposed",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-39",
"message": "Wait task 'RPF-WP-0058-T05' in workplan 'RPF-WP-0058' has neither depends_on, needs_human: true, blocked_on: message-from:\u2026 nor wait_until \u2014 unqualified wait",
"file_path": "workplans/RPF-WP-0058-reuse-private-source-reader.md#RPF-WP-0058-T05",
"db_id": "",
"file_value": "wait",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0004' is not linked to State Hub",
"file_path": "workplans/archived/260702-RPF-WP-0023-workload-kv-access-lanes.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0005' is not linked to State Hub",
"file_path": "workplans/archived/260702-RPF-WP-0024-credential-change-approval-workflow.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0005",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0006' is not linked to State Hub",
"file_path": "workplans/archived/260702-RPF-WP-0024-credential-change-approval-workflow.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0006",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0005' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0002-openbao-approved-automation-delegation.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0005",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0006' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0002-openbao-approved-automation-delegation.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0006",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0007' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0002-openbao-approved-automation-delegation.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0007",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0004' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0003-issue-core-runtime-ingestion-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0007' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0003-issue-core-runtime-ingestion-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0007",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0008' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0003-issue-core-runtime-ingestion-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0008",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0004' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0004-llm-connect-openrouter-provider-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0004",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0007' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0004-llm-connect-openrouter-provider-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0007",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0008' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0004-llm-connect-openrouter-provider-key-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0008",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0007' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0005-reuse-surface-runtime-secrets-openbao-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0007",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-20",
"message": "Workplan dependency target 'RAILIANCE-WP-0008' is not linked to State Hub",
"file_path": "workplans/archived/260905-RPF-WP-0005-reuse-surface-runtime-secrets-openbao-lane.md",
"db_id": "",
"file_value": "RAILIANCE-WP-0008",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0003@retired-20260826' (id=665b3b9b\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "665b3b9b-608a-4be4-84b6-dcb8261ff57b",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0004@retired-20260826' (id=e57e487b\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "e57e487b-8557-439d-8093-0457c73ede93",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0005@retired-20260826' (id=2731fece\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "2731fece-6c49-45b8-ab8a-4ea6c04ac603",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0006@retired-20260826' (id=96c8a93d\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "96c8a93d-7a5a-4fa9-8f7b-865119551da3",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0007@retired-20260826' (id=4d7ce243\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "4d7ce243-f40a-4249-a46a-a24f75d6fe4c",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0008@retired-20260826' (id=671898ef\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "671898ef-2378-4814-b8f6-066148cdad46",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0009@retired-20260826' (id=b059c81d\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "b059c81d-96f1-451f-896f-a05cd73744a1",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0010@retired-20260826' (id=f364d405\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "f364d405-a85d-4b89-b600-1964ab436cad",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0029@retired-20260826' (id=038bc3c0\u2026, status=blocked) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "038bc3c0-4492-5b91-95eb-ae515ca205df",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0024@retired-20260826' (id=88c4ef7f\u2026, status=blocked) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "88c4ef7f-0af8-580e-90dc-a2bae2675a4d",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-platform-railiance-wp-0011@retired-20260826' (id=3f9fd8de\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "3f9fd8de-7235-4486-aaa7-634dba2bb6fa",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0027@retired-20260826' (id=6f8a6cbc\u2026, status=blocked) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "6f8a6cbc-c076-5f0a-ade2-281a7ec71360",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0017@retired-20260826' (id=16e8f234\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "16e8f234-9305-5ff3-af82-4639215a0c54",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0028@retired-20260826' (id=022dda1f\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "022dda1f-8772-57ad-862e-672924455f11",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0015@retired-20260826' (id=1c73af72\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "1c73af72-fd4b-5ab6-8ff7-a3c302bf55a5",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0022@retired-20260826' (id=a7977cbf\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "a7977cbf-ab43-56b7-b7a9-ceb52382b341",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0025@retired-20260826' (id=2422d4e7\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "2422d4e7-2125-591e-8e95-80ecc6e09da0",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0016@retired-20260826' (id=857ca302\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "857ca302-bb94-5d41-a649-1aa966368df4",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0026@retired-20260826' (id=73878f8d\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "73878f8d-d8bb-5845-8a5c-91cdd83c1066",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Retired DB workstream 'railiance-wp-0023@retired-20260826' (id=ec52fbe6\u2026, status=finished) has no backing workplan file \u2014 projection tombstone, not live work",
"file_path": "",
"db_id": "ec52fbe6-571b-570e-884b-c7a32ff7bcc8",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-25",
"message": "Owner-return task 'RPF-WP-0035-T08' waiting on audit-core has 9 reply/replies after its last dated note (or unread when undated) \u2014 owner action needed: 570ca050-0316-4e38-9c16-be41057c2330, 2de1c6e7-9602-48e5-868d-0048fbbef150, e7c36b17-d8f7-4d86-af09-02111289d1f5, 5fe769a7-d35b-4e37-a671-673d13cf8948, b3c564a6-93f9-4c07-872b-7feb22cccb73, ec4995b5-e1b2-4c66-9f8d-5ac8d6ceb149, 7c4019f2-348d-475e-9c96-e1ff6d0d27f5, ff43fd2c-7633-4b34-9ae6-2483ba03a271, 0d0da0d2-36a1-4ffc-b7bf-7896fad691f6",
"file_path": "workplans/RPF-WP-0035-credential-lane-implementation.md#RPF-WP-0035-T08",
"db_id": "",
"file_value": "message-from:audit-core",
"db_value": "",
"fixable": false,
"repo_slug": "railiance-platform",
"source_revision": "104ed90f42a9a86bf9fda343b49b65a85c9ee4b9",
"source_revision_reason": null,
"owner_return": {
"task_record_id": "RPF-WP-0035-T08",
"message_ids": [
"570ca050-0316-4e38-9c16-be41057c2330",
"2de1c6e7-9602-48e5-868d-0048fbbef150",
"e7c36b17-d8f7-4d86-af09-02111289d1f5",
"5fe769a7-d35b-4e37-a671-673d13cf8948",
"b3c564a6-93f9-4c07-872b-7feb22cccb73",
"ec4995b5-e1b2-4c66-9f8d-5ac8d6ceb149",
"7c4019f2-348d-475e-9c96-e1ff6d0d27f5",
"ff43fd2c-7633-4b34-9ae6-2483ba03a271",
"0d0da0d2-36a1-4ffc-b7bf-7896fad691f6"
]
}
},
{
"severity": "WARN",
"check_id": "C-25",
"message": "Owner-return task 'RPF-WP-0056-T03' waiting on railiance-cluster has 9 reply/replies after its last dated note (or unread when undated) \u2014 owner action needed: 4e9d4e58-71b3-497b-8954-cedc30740529, 13acb774-8fbe-4ca3-b44d-89a4742138bd, c9435491-8545-4d48-a57a-1773f2789092, fb8f25df-57ce-40e5-ae67-0c0b392746e8, 4bb0d7af-b644-44f3-acc8-69c7321e9824, 5301d4fb-0631-4ac5-8471-531e5362b2ba, 2087b9ac-c980-4881-89f1-6b1088132f5b, 78b89fb2-ced6-45f1-9718-0670b8257d45, 110e8dea-ce81-40ff-8161-325ddb89cd67",
"file_path": "workplans/RPF-WP-0056-playwright-consumer-admission.md#RPF-WP-0056-T03",
"db_id": "",
"file_value": "message-from:railiance-cluster",
"db_value": "",
"fixable": false,
"repo_slug": "railiance-platform",
"source_revision": "104ed90f42a9a86bf9fda343b49b65a85c9ee4b9",
"source_revision_reason": null,
"owner_return": {
"task_record_id": "RPF-WP-0056-T03",
"message_ids": [
"4e9d4e58-71b3-497b-8954-cedc30740529",
"13acb774-8fbe-4ca3-b44d-89a4742138bd",
"c9435491-8545-4d48-a57a-1773f2789092",
"fb8f25df-57ce-40e5-ae67-0c0b392746e8",
"4bb0d7af-b644-44f3-acc8-69c7321e9824",
"5301d4fb-0631-4ac5-8471-531e5362b2ba",
"2087b9ac-c980-4881-89f1-6b1088132f5b",
"78b89fb2-ced6-45f1-9718-0670b8257d45",
"110e8dea-ce81-40ff-8161-325ddb89cd67"
]
}
},
{
"severity": "WARN",
"check_id": "C-28",
"message": "14 unread message(s) lack thread_id for supersession tracking: the-custodian:836a8502, the-custodian:72c6a148, audit-core:0d0da0d2, rapp-postgres:6d047a08, railiance-platform:c4a80a60",
"file_path": "",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'RAIL-PL-WP-0002' uses prefix 'RAIL-PL-WP' but repo canonical prefix is 'RPF-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/260702-RAIL-PL-WP-0002-openbao-platform-secrets-service.md",
"db_id": "",
"file_value": "RAIL-PL-WP-0002",
"db_value": "RPF-WP",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-26",
"message": "Workplan id 'RAIL-PL-WP-0001' uses prefix 'RAIL-PL-WP' but repo canonical prefix is 'RPF-WP' \u2014 new plans must conform",
"file_path": "workplans/archived/RAIL-PL-WP-0001-platform-baseline.md",
"db_id": "",
"file_value": "RAIL-PL-WP-0001",
"db_value": "RPF-WP",
"fixable": false
}
],
"fixes_applied": [
"bindings: synced 64/64",
"C-17 cleared: pushed 1 backlogged commit(s)",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 35,
"info": 20
},
"result": "warn"
}