fix: bind issuer template exactly and align catalog admission fixtures
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
This commit is contained in:
tegwick 2026-10-17 20:44:31 +02:00
parent 342a6f25af
commit befb0bc68c
5 changed files with 209 additions and 10 deletions

View file

@ -269,8 +269,11 @@ spec:
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,128 @@
# TEST ONLY: synthetic subset shaped after ops-warden 5abde817 catalog.
# Four draft entries are hypothetically active; Apps session_lane remains unresolved.
# Not an authenticated owner catalog, promotion, login choice or native authority.
entries:
- id: key-cape-oidc-login
risk: standard
owner_repo: key-cape
warden_executes: false
reviewed: '2026-06-27'
status: active
delegation:
mode: interim
intended_owner: key-cape
reviewed: '2026-09-08'
blocked_on: fixture-only; no native authority
lane: login
title: Synthetic key-cape-oidc-login
need_keywords:
- key-cape-oidc-login
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.
- id: keycape-client-secret-generate
risk: high
owner_repo: railiance-platform
warden_executes: false
reviewed: '2026-10-10'
status: active
delegation:
mode: native
intended_owner: railiance-platform
reviewed: '2026-10-10'
lane: secret
title: Synthetic keycape-client-secret-generate
need_keywords:
- keycape-client-secret-generate
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.
- id: keycape-attended-case-change
lane: attended-change
session_lane: key-cape-oidc-login
risk: high
owner_repo: key-cape/net-kingdom
warden_executes: false
reviewed: '2026-10-17'
status: active
delegation:
mode: interim
intended_owner: key-cape
reviewed: '2026-10-17'
blocked_on: fixture-only; no native authority
title: Synthetic keycape-attended-case-change
need_keywords:
- keycape-attended-case-change
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.
- id: platform-secret-delivery
risk: high
owner_repo: railiance-platform
warden_executes: false
reviewed: '2026-10-17'
status: active
delegation:
mode: native
intended_owner: railiance-platform
reviewed: '2026-10-17'
title: Synthetic platform-secret-delivery
need_keywords:
- platform-secret-delivery
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.
- id: consumer-owner-deployment
lane: attended-change
session_lane: pending-owner-confirmation
risk: high
owner_repo: railiance-apps
warden_executes: false
reviewed: '2026-10-17'
status: active
delegation:
mode: native
intended_owner: railiance-apps
reviewed: '2026-10-17'
title: Synthetic consumer-owner-deployment
need_keywords:
- consumer-owner-deployment
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.
- id: apps-consumer-handover
lane: attended-change
session_lane: pending-owner-confirmation
risk: high
owner_repo: railiance-apps
warden_executes: false
reviewed: '2026-10-17'
status: active
delegation:
mode: native
intended_owner: railiance-apps
reviewed: '2026-10-17'
title: Synthetic apps-consumer-handover
need_keywords:
- apps-consumer-handover
subsystem: synthetic source test
wiki_ref: fixture-only
canon_ref: fixture-only
workload_ref:
applicability: not-applicable
reason: Synthetic source test; no workload or native authority.

View file

@ -8,7 +8,9 @@ fingerprint and knows only 1.1 and 1.2 (ops-warden case_inputs.PARAMETER_PINS),
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.
memory the five resolvable steps admit. The two Apps attended steps remain refused
because their establishing login is unresolved in the synthetic catalog. Four real
draft lane shapes are hypothetically active in that fixture; no catalog is promoted.
Trust is fixture-only, nothing is dispatched, and none of this is owner admission
or an acknowledgment.
"""
@ -37,6 +39,8 @@ 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())
CATALOG = (ROOT / 'kernel-catalog.fixture.yaml').read_bytes()
UNRESOLVED_APPS = {'deliver-consumer-secret', 'hand-over'}
EVIDENCE = {'fixture-acceptance', 'fixture-materialization', 'fixture-descriptor', 'fixture-session'}
@ -74,12 +78,13 @@ class Admit13TypeTests(unittest.TestCase):
ARTIFACT['params']['consumer_owner_repo'],
version='1.3'))
def admit(self, desc, type_source, *, actor=None, lane=None, agent_id=None):
def admit(self, desc, type_source, *, actor=None, lane=None, agent_id=None, catalog=CATALOG):
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,
lambda purpose, source, evidence: (evidence in EVIDENCE and
(purpose != 'catalog-routing-acceptance' or source == digest(CATALOG))),
browser_inputs=inputs.BrowserInputs(REPO))
with mock.patch.dict(os.environ):
if agent_id is None:
@ -87,7 +92,7 @@ class Admit13TypeTests(unittest.TestCase):
else:
os.environ['WARDEN_AGENT_ID'] = agent_id
return executor.admit(self.case_source, type_source, desc_bytes,
b'fixture-only-catalog', principal='founder', actor=actor or desc.actor,
catalog, principal='founder', actor=actor or desc.actor,
lane=lane or desc.lane,
acceptance_evidence='fixture-acceptance',
materialization_evidence='fixture-materialization',
@ -112,19 +117,34 @@ class Admit13TypeTests(unittest.TestCase):
self.assertEqual(parameter_fingerprint(TYPE_BYTES), inputs.PARAMETER_PINS['1.2'])
acknowledged = with_status('acknowledged')
for step, desc in self.descriptors.items():
if step in UNRESOLVED_APPS:
continue # The attended session gate correctly precedes parameter validation.
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):
def test_committed_map_conditionally_admits_five_resolvable_steps(self):
acknowledged = with_status('acknowledged')
for step, desc in self.descriptors.items():
if step in UNRESOLVED_APPS:
continue
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_unresolved_apps_sessions_refused_even_once_acknowledged_and_pinned(self):
for step in sorted(UNRESOLVED_APPS):
with self.subTest(step=step), pinned_13(), self.assertRaisesRegex(
Refused, 'does not resolve to an active, reviewed login lane'):
self.admit(self.descriptors[step], with_status('acknowledged'))
def test_catalog_evidence_is_bound_to_exact_fixture_bytes(self):
mint = self.descriptors['mint-secret']
with pinned_13(), self.assertRaisesRegex(Refused, 'independent owner evidence not verified'):
self.admit(mint, with_status('acknowledged'), catalog=CATALOG + b'\n# changed source\n')
def test_descriptor_outside_the_map_is_refused(self):
acknowledged = with_status('acknowledged')
mint = self.descriptors['mint-secret']

View file

@ -259,8 +259,13 @@ class RegistrationTests(unittest.TestCase):
case_source = yaml.safe_dump(case).encode()
typ = yaml.safe_load((root / 'security-case-types/oidc-browser-relying-party/type.yaml').read_bytes())
typ['spec']['execution_descriptors'] = {'register-client': digest(self.desc_bytes)}
# Fixture-only successor lane for the adapter's current descriptor.
# Canonical 1.1 still names the earlier login lane and is not edited.
typ['spec']['follow_through'] = [
dict(step, lane=self.admitted.lane) if step['id'] == 'register-client' else step
for step in typ['spec']['follow_through']]
type_source = yaml.safe_dump(typ).encode()
catalog = b'fixture-only-catalog'
catalog = (ROOT / 'kernel-catalog.fixture.yaml').read_bytes()
sheet = json.dumps(['register-client', 'net-kingdom', 'forgejo', 'human',
'founder', 'keycape-attended-case-change', 'fixture-acceptance', 'fixture-materialization',
'fixture-descriptor', 'fixture-session'], separators=(',', ':')).encode()
@ -270,6 +275,8 @@ class RegistrationTests(unittest.TestCase):
adapter = a.build(**dict(self.kw, admitted=invocation, case_source=case_source,
case_acceptance='fixture-acceptance'))
def fixture_verifier(purpose, source, evidence):
if purpose == 'catalog-routing-acceptance':
return source == digest(catalog) and evidence == 'fixture-descriptor'
if purpose.startswith('session-revocation:'):
_, lane, operation, attempt = purpose.split(':')
return source == digest(case_source) and lane == invocation.lane and evidence == (

View file

@ -1559,7 +1559,7 @@ T16 still owns actual composition and admission; F2/F3 follow below.
```task
id: NK-WP-0048-T33
status: todo
status: done
priority: high
state_hub_task_id: "5ace28ff-a4cb-5647-a8f6-3cd54bb9d0a5"
```
@ -1584,7 +1584,7 @@ RPF-1.3-T4 and T16 admission/native requirements.
```task
id: NK-WP-0048-T34
status: todo
status: progress
priority: high
state_hub_task_id: "37f43c40-d014-544e-aa0b-5219dd4a6b93"
```
@ -1607,3 +1607,44 @@ Custodian `docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r
and `nk48-r5-f3-review-r1/`. Source review, owner acknowledgment and native proof
remain distinct. T16's final composition/admission and T06's native first case
are not completed by this refinement.
## T35 — Align source admission fixtures with the authenticated catalog and attended-session API
```task
id: NK-WP-0048-T35
status: done
priority: high
state_hub_task_id: "cf1d6ab3-846e-53ea-8575-d6347b6f4769"
```
Completed 2026-10-17, source fixture compatibility only. Distinct from T32's
independent agent-mint regression repair: both remaining opaque catalog byte
placeholders now use one well-formed synthetic catalog whose exact bytes are
bound by the fixture evidence verifier. The fixture mirrors the six relevant
Warden lane shapes; four draft statuses are hypothetically active, while both
Apps establishing login references remain unresolved. No real catalog entry,
owner login choice or production parameter pin changes.
Against the reviewed mode-aware Warden source now integrated at
`ae7bc73b4f4bac22454144959b870d161498e0af`, scratch validation passes 31 tests
and 53 subtests. Five resolvable 1.3 descriptors conditionally admit under
fixture-only acknowledgment and pinning; both Apps attended steps refuse before
execution. Changed catalog bytes refuse, all independent mint-guard tests still
reach their intended guard, and the registration fixture's actual kernel
run/rollback and uncertain-result paths pass with synthetic owner callbacks.
The registration fixture explicitly aligns its in-memory proposed type lane
with its current descriptor; canonical 1.1 is unchanged.
The same tests against predecessor `117fec9241e7b985dfb187b992e173d0a5dc3700`
pass 31 tests and 51 subtests, with only the two new Apps refusal assertions
failing because that predecessor lacks the attended-session catalog check.
Tests target the reviewed current API; the parser or Apps gate is not weakened
for predecessor compatibility. Evidence and root source review:
`the-custodian/docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/`
and `nk48-catalog-fixture-publication-r2/`. Root canonical validation passes
31 tests / 53 subtests against Warden `922c26d` (the same reviewed code plus
one normal allocator-only source UUID commit). Publication receipts belong
in that packet. This records source
fixture work, not native T03, owner assent, exact-type acknowledgment, PIN-1,
composition/admission completion under T16 or the native first case under T06.
T33 and T34 retain their existing issuer-store and consumer-inverse work.