Test kernel admission of every 1.2 descriptor (NK48-R1-F1 follow-up)
Run Executor.admit on all seven composed descriptors with the real 1.2 type, example case and reviewed browser validator. Pin agent-mint and wrong-lane refusals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 1011674@bnt-lap001 Assistant-Session: b3b5b6f0-3bf5-41a3-8150-3ca4606cc028
This commit is contained in:
parent
410d5239cd
commit
68f4bbb8ca
2 changed files with 108 additions and 2 deletions
98
sso-mfa/k8s/keycape/test_admit_1_2_adapter_descriptors.py
Normal file
98
sso-mfa/k8s/keycape/test_admit_1_2_adapter_descriptors.py
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
"""Kernel admission of every 1.2 descriptor with fixture-only trust (NK48-R1-F1).
|
||||
|
||||
Descriptor.decode alone missed that the kernel refuses an agent mint. Each of the
|
||||
seven composed descriptors goes through Warden's own Executor.admit here, with the
|
||||
real 1.2 type, the 1.2 forgejo example case and the reviewed browser validator.
|
||||
Adapters are stand-ins carrying only the pinned reference and source; nothing is
|
||||
dispatched. Admission here is a fixture, not owner admission or a pin.
|
||||
"""
|
||||
from dataclasses import replace
|
||||
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_12_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.2/oidc-browser-relying-party'
|
||||
ARTIFACT = json.loads((ROOT / 'descriptor-composition-1.2.candidate.json').read_text())
|
||||
EVIDENCE = {'fixture-acceptance', 'fixture-materialization', 'fixture-descriptor', 'fixture-session'}
|
||||
|
||||
|
||||
def unused(*_):
|
||||
raise AssertionError('admission must not dispatch')
|
||||
|
||||
|
||||
class AdmitDescriptorSetTests(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']))
|
||||
|
||||
def admit(self, desc, *, actor=None, lane=None):
|
||||
desc_bytes = c.encode(desc)
|
||||
typ = yaml.safe_load((TYPE_DIR / 'type.yaml').read_bytes())
|
||||
typ['spec']['execution_descriptors'] = {desc.step: digest(desc_bytes)}
|
||||
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, yaml.safe_dump(typ).encode(), 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_composed_descriptors_are_the_committed_artifact(self):
|
||||
self.assertEqual({s: digest(c.encode(d)) for s, d in self.descriptors.items()},
|
||||
ARTIFACT['execution_descriptors'])
|
||||
|
||||
def test_every_1_2_descriptor_passes_kernel_admission(self):
|
||||
self.assertEqual(len(self.descriptors), 7)
|
||||
for step, desc in self.descriptors.items():
|
||||
with self.subTest(step=step):
|
||||
admitted_desc, invocation, _ = self.admit(desc)
|
||||
self.assertEqual(admitted_desc, desc)
|
||||
self.assertEqual((invocation.step, invocation.owner, invocation.lane,
|
||||
invocation.actor, invocation.target),
|
||||
(desc.step, desc.owner, desc.lane, desc.actor, 'forgejo'))
|
||||
|
||||
def test_mint_secret_admits_only_a_human_actor(self):
|
||||
mint = self.descriptors['mint-secret']
|
||||
self.assertEqual((mint.effect, mint.actor), ('mint', 'human'))
|
||||
with self.assertRaisesRegex(Refused, 'agent mint is forbidden'):
|
||||
self.admit(replace(mint, actor='agent'))
|
||||
with self.assertRaisesRegex(Refused, 'principal actor or lane mismatch'):
|
||||
self.admit(mint, actor='agent')
|
||||
|
||||
def test_wrong_lane_is_refused(self):
|
||||
for step, desc in self.descriptors.items():
|
||||
with self.subTest(step=step), self.assertRaisesRegex(
|
||||
Refused, 'principal actor or lane mismatch'):
|
||||
self.admit(desc, lane='wrong-lane')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
@ -1397,8 +1397,16 @@ finding NK48-R1-F1) showed that unchanged kernel a45cf47 refuses every
|
|||
forbidden"), so the `agent` descriptor could never be admitted. Adapter, tests
|
||||
and composer comment updated and the artifact regenerated (mint-secret
|
||||
descriptor digest now `sha256:8c40c2884f8ba15e8cb6c98f33419c395e54fce8ef33d6e1a34782cf3f1fcfa9`);
|
||||
98 tests pass against a45cf47. Open: no test yet runs `Executor.admit` on the
|
||||
1.2 descriptors. The set needs an independent r2 review.
|
||||
98 tests pass against a45cf47. The set needs an independent r2 review.
|
||||
|
||||
2026-10-17 `test_admit_1_2_adapter_descriptors.py` runs Warden's own
|
||||
`Executor.admit` on all seven composed 1.2 descriptors, with the real 1.2
|
||||
type, the 1.2 forgejo example case, the reviewed `BrowserInputs` validator and
|
||||
fixture-only trust (stand-in adapters, nothing dispatched). It also pins that
|
||||
an agent mint descriptor is refused ("agent mint is forbidden") and that a
|
||||
wrong lane is refused for every step. Against the old `agent` revision
|
||||
(582ab9f) it fails as expected. Combined suite: 102 passed on ops-warden a45cf47
|
||||
and on current ops-warden. Fixture admission is not owner admission or a pin.
|
||||
|
||||
2026-10-17 founder decision: the mint-secret actor is `agent`, not `warden`.
|
||||
The kernel is unchanged. The adapter, its test and the composer were updated and
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue