feat(admission): founder-signed trust and recovery-attempt admission (WP14 T02, WP15 T05)
Reuse the gated-executor approval pattern: ssh-keygen -Y signatures over exact bytes, verified against a runtime-unwritable allowed_signers anchor with a fixed namespace per purpose. load_trust now refuses responder trust without a founder admission; the KeyCape selector preflight gains --admission for one exact, bounded recovery attempt. WP14 re-pointed to CUST-WP-0082-T06 and split founder key admission into human-gated T04; WP15 T04 now requires the signed admission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 809600@bnt-lap001 Assistant-Session: 40ba228f-c8a0-4ec9-bb29-3129951afdc4
This commit is contained in:
parent
497040c58c
commit
ebd8e49aff
15 changed files with 469 additions and 29 deletions
|
|
@ -6,6 +6,26 @@ import subprocess
|
|||
import pytest
|
||||
|
||||
PUBLIC='IVL40Zt5HSRFMkLhXy6rbLfP-ntqXtMAl5YOBpiB2xI'
|
||||
FOUNDER='founder@synthetic'
|
||||
|
||||
|
||||
def admission_anchor(directory):
|
||||
"""Synthetic founder key plus allowed_signers anchor, like /etc/gexec."""
|
||||
key=directory/'founder'
|
||||
subprocess.run(['ssh-keygen','-q','-t','ed25519','-N','','-C',FOUNDER,'-f',str(key)],check=True,timeout=30)
|
||||
anchor=directory/'anchor';anchor.mkdir(mode=0o755)
|
||||
(anchor/'allowed_signers').write_text(FOUNDER+' '+(directory/'founder.pub').read_text())
|
||||
(anchor/'allowed_signers').chmod(0o644)
|
||||
return {'key':key,'anchor':anchor}
|
||||
|
||||
|
||||
def admit(path,namespace='secrets-engine-pdp-trust',key=None):
|
||||
"""Founder-sign exact file bytes as `<path>.sig` (ssh-keygen -Y sign)."""
|
||||
import os as _os
|
||||
key=key or Path(_os.environ['SECRETS_ENGINE_ADMISSION_ANCHOR']).parent/'founder'
|
||||
Path(str(path)+'.sig').unlink(missing_ok=True)
|
||||
subprocess.run(['ssh-keygen','-q','-Y','sign','-f',str(key),'-n',namespace,str(path)],check=True,timeout=30,capture_output=True)
|
||||
return path
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def signature_tools(tmp_path_factory):
|
||||
|
|
@ -22,7 +42,7 @@ def admit_tools(cfg, directory, tools):
|
|||
trust={'schema':'secrets-engine.pdp-trust.v1','evaluator':'stub/local','mode':'standalone',
|
||||
'policy_package':cfg.authorization_policy_package,'policy_version':cfg.authorization_policy_version,
|
||||
'policy_package_digest':'sha256:'+'1'*64,'keys':{'testdata-ed25519':PUBLIC}}
|
||||
path=directory/'pdp-trust.json';path.write_text(json.dumps(trust))
|
||||
path=directory/'pdp-trust.json';path.write_text(json.dumps(trust));admit(path)
|
||||
from dataclasses import is_dataclass, replace
|
||||
if is_dataclass(cfg):
|
||||
return replace(cfg,pdp_trust_file=path,pdp_verifier=tools/'verify')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue