Test kernel admission of every 1.2 descriptor (NK48-R1-F1 follow-up)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s

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:
tegwick 2026-10-17 10:49:50 +02:00
parent 410d5239cd
commit 68f4bbb8ca
2 changed files with 108 additions and 2 deletions

View 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()

View file

@ -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