fix: bind issuer template exactly and align catalog admission fixtures
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
This commit is contained in:
parent
342a6f25af
commit
befb0bc68c
5 changed files with 209 additions and 10 deletions
|
|
@ -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
|
||||
|
|
|
|||
128
sso-mfa/k8s/keycape/kernel-catalog.fixture.yaml
Normal file
128
sso-mfa/k8s/keycape/kernel-catalog.fixture.yaml
Normal 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.
|
||||
|
|
@ -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']
|
||||
|
|
|
|||
|
|
@ -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 == (
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue