Point the OpenRouter cycle at memo version 3.
Fresh receipts use the new approval IDs. A matching live policy and AppRole skips apply without claiming that approval. A difference fails closed. Assistant: grok Assistant-Session: 01a0e2a1-8058-7553-9999-b7d106c17047
This commit is contained in:
parent
1cd546e77c
commit
53825190ca
5 changed files with 47 additions and 17 deletions
|
|
@ -1,8 +1,11 @@
|
|||
# T03 continuation after Railiance Clock deployment
|
||||
|
||||
The original requests expired unconsumed. Replacement request IDs and immutable
|
||||
memo version 2 are recorded in the creation receipt and Secrets Engine workplan.
|
||||
The exact apply/verify/exec action requests and checker pins are unchanged.
|
||||
The 2026-09-16 requests were consumed. The next cycle uses three new approval
|
||||
IDs and immutable memo version 3. The creation receipt is
|
||||
`docs/evidence/2026-09-27-t03-approval-requests.json`; execution receipts are
|
||||
`secrets-engine/docs/evidence/2026-09-27-t03-native-execution.json` and
|
||||
`docs/evidence/2026-09-27-t03-attended-delivery.json`. The exact
|
||||
apply/verify/exec action requests and checker pins are unchanged.
|
||||
|
||||
Run the requester and execution worker with
|
||||
`/home/worsch/secrets-engine/.venv/bin/python`; this environment includes Clock,
|
||||
|
|
@ -20,6 +23,6 @@ The outer lane remains secrets-engine-approval-client-login; its reviewed
|
|||
Both retain their own self-revocation and private runtime cleanup.
|
||||
|
||||
Human review: https://decisions.coulomb.social/review?memo_id=SECRETS-WP-0010-T03-apply
|
||||
(and identifiers ending -verify and -exec). Version 2 is required. The requester
|
||||
has no approval or consume scope; no human entries are copied from version 1.
|
||||
(and identifiers ending -verify and -exec). Version 3 is required. The requester
|
||||
has no approval or consume scope; no human entries are copied from version 2.
|
||||
No execution may begin before the new approvals pass native claim/PDP checks.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from urllib.parse import urlencode
|
|||
from urllib.error import HTTPError
|
||||
import jwt
|
||||
ROOT=Path('/home/worsch/railiance-platform')
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-15-t03-renewed-approval-requests.json'
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-27-t03-approval-requests.json'
|
||||
POLICY='workload-kv-read-secrets-engine-requester-client'
|
||||
KV='platform/data/workloads/secrets-engine/approval-requester'
|
||||
ISSUER='https://kc.coulomb.social'
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from datetime import datetime,timezone
|
|||
from urllib.request import Request,build_opener,ProxyHandler,HTTPRedirectHandler
|
||||
ROOT=Path('/home/worsch/railiance-platform')
|
||||
spec=importlib.util.spec_from_file_location('preflight',ROOT/'scripts/approval-client-reader-preflight.py');pre=importlib.util.module_from_spec(spec);spec.loader.exec_module(pre)
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-15-t03-attended-delivery.json'
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-27-t03-attended-delivery.json'
|
||||
class NoRedirect(HTTPRedirectHandler):
|
||||
def redirect_request(self,*args,**kwargs):return None
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ if RESUME:RECEIPT=ROOT/'docs/evidence/2026-09-16-t03-resume-attended-delivery.js
|
|||
|
||||
def main(receipt):
|
||||
require(Path.home().parent.name=='.warden-attended-login' and not os.getenv('BAO_TOKEN') and not os.getenv('VAULT_TOKEN'),'attended_reader_required')
|
||||
require(not Path('/home/worsch/secrets-engine/docs/evidence/'+('2026-09-16-t03-resume-exec.json' if RESUME else '2026-09-15-t03-native-execution.json')).exists(),'execution_receipt_requires_reconciliation')
|
||||
require(not Path('/home/worsch/secrets-engine/docs/evidence/'+('2026-09-16-t03-resume-exec.json' if RESUME else '2026-09-27-t03-native-execution.json')).exists(),'execution_receipt_requires_reconciliation')
|
||||
identity=pre.bao('token','lookup','-format=json')['data'];pre.validate_identity(identity)
|
||||
for path,expected in pre.EXPECTED.items():require(sorted(pre.bao('token','capabilities','-format=json',path))==expected,'reader_scope_failed')
|
||||
runtime=Path('/run/user')/str(os.getuid());private(runtime,True)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ from secrets_engine.decisions import resolve_decision,require_approved
|
|||
from secrets_engine.openbao import OpenBaoClient
|
||||
from secrets_engine.exec_owner import validate_delivery_target
|
||||
from secrets_engine.plan import build_plan
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-15-t03-native-execution.json'
|
||||
RECEIPT=ROOT/'docs/evidence/2026-09-27-t03-native-execution.json'
|
||||
KUBE=['kubectl','--kubeconfig','/home/worsch/.kube/config-railiance01']
|
||||
ROLE='se-prod-openrouter-llm-connect'; LANE='openrouter-llm-connect'
|
||||
IDS={'apply':'9935335c-8e9a-566e-a48e-6a5b5f4882eb','verify':'273d6882-6253-5dc9-ac54-544f92ef5e56','exec':'7ba0c13b-68cd-5b3e-9481-42ba9e385e68'}
|
||||
PRIOR_IDS={'apply':'9935335c-8e9a-566e-a48e-6a5b5f4882eb','verify':'273d6882-6253-5dc9-ac54-544f92ef5e56','exec':'7ba0c13b-68cd-5b3e-9481-42ba9e385e68'}
|
||||
IDS={'apply':'b5fcbfcc-ad56-456f-bc36-c823052e9917','verify':'4e9ff881-d59f-4143-9155-929afbe8dd43','exec':'a24e0898-b3c5-4e50-85a8-18a2c2aa229e'}
|
||||
LIMITS={'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}
|
||||
|
||||
def require(value,code):
|
||||
if not value:raise ValueError(code)
|
||||
|
|
@ -86,10 +88,18 @@ def verify_session_cleanup(client):
|
|||
del probe_token
|
||||
return {'unrelated_path_denied':True,'session_revocation_verified':True,'revoked_token_lookup_status':403}
|
||||
|
||||
def native_apply_disposition(policy_hcl,existing,role):
|
||||
if existing is None and role is None:return 'absent'
|
||||
require(isinstance(existing,str) and isinstance(role,dict) and existing.strip()==policy_hcl.strip() and all(role.get(k)==v for k,v in LIMITS.items()) and role.get('token_policies')==[ROLE],'existing_native_objects_require_reconciliation')
|
||||
return 'satisfied'
|
||||
def fresh_apply_plan(policy_hcl,existing,role):
|
||||
if native_apply_disposition(policy_hcl,existing,role)=='absent':return tuple(IDS),None
|
||||
return ('verify','exec'),{'action':'apply','already_satisfied':True,'limits':dict(LIMITS)}
|
||||
|
||||
def resume_receipt():
|
||||
prior=json.loads((ROOT/'docs/evidence/2026-09-15-t03-native-execution.json').read_text())
|
||||
require(prior.get('phase')=='verify_attempt_started' and prior.get('failure_code')=='revoked_token_still_usable','unexpected_prior_failure')
|
||||
require(prior.get('actions')==[{'action':'apply','approval_id':IDS['apply'],'exit_code':0,'limits':{'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}}],'prior_apply_not_verified')
|
||||
require(prior.get('actions')==[{'action':'apply','approval_id':PRIOR_IDS['apply'],'exit_code':0,'limits':{'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}}],'prior_apply_not_verified')
|
||||
return prior
|
||||
|
||||
def admin(directory,negative,resume=False):
|
||||
|
|
@ -122,7 +132,14 @@ def admin(directory,negative,resume=False):
|
|||
fd=os.open(directory/'pdp-caller',os.O_WRONLY|os.O_CREAT|os.O_EXCL,0o600)
|
||||
with os.fdopen(fd,'w') as out:out.write(run(*KUBE,'-n','secrets-engine','create','token','secrets-engine','--audience=flex-auth','--duration=10m').strip())
|
||||
# Validate real claims and exact current decisions before any consumption.
|
||||
# Fresh apply is classified first. A match is left out of this loop so the new apply approval is not claimed or consumed.
|
||||
actions=('exec',) if resume else tuple(IDS)
|
||||
if not resume:
|
||||
client=OpenBaoClient.resolve('http://127.0.0.1:18200')
|
||||
existing=client.read_policy(ROLE)
|
||||
role=bao('read','-format=json','auth/approle/role/'+ROLE)['data'] if client.approle_exists(ROLE) else None
|
||||
actions,satisfied=fresh_apply_plan(build_plan(entries['apply'],'prod').policy_hcl,existing,role)
|
||||
if satisfied:receipt['actions'].append(satisfied)
|
||||
for action in actions:
|
||||
auth=authorize_action(configs[action],entries[action],action,fields=() if action=='apply' else tuple(entries[action].fields),policy_targets=(ROLE,),auth_targets=(ROLE,))
|
||||
require(auth is not None,'native_authorization_missing')
|
||||
|
|
@ -135,13 +152,13 @@ def admin(directory,negative,resume=False):
|
|||
require(existing is not None and existing.strip()==plan.policy_hcl.strip(),'applied_policy_drift')
|
||||
role=bao('read','-format=json','auth/approle/role/'+ROLE)['data']
|
||||
require(all(role.get(k)==v for k,v in prior['actions'][0]['limits'].items()) and role.get('token_policies')==[ROLE],'applied_role_drift')
|
||||
code="import json;from approval_engine.store import Engine;e=Engine('/data/approvals.sqlite');print(json.dumps({k:e.claim(v) for k,v in "+repr(IDS)+".items()}))"
|
||||
code="import json;from approval_engine.store import Engine;e=Engine('/data/approvals.sqlite');print(json.dumps({k:e.claim(v) for k,v in "+repr(PRIOR_IDS)+".items()}))"
|
||||
claims=json.loads(run(*KUBE,'-n','approval-engine','exec','statefulset/approval-engine','--','python','-c',code))
|
||||
require(all(claims[a]['consumed'] and claims[a]['approval_id']==IDS[a] for a in ('apply','verify')) and claims['exec']['valid_now'] and not claims['exec']['consumed'],'resume_approval_state_mismatch')
|
||||
require(all(claims[a]['consumed'] and claims[a]['approval_id']==PRIOR_IDS[a] for a in ('apply','verify')) and claims['exec']['valid_now'] and not claims['exec']['consumed'],'resume_approval_state_mismatch')
|
||||
receipt['prior_receipt']='2026-09-15-t03-native-execution.json'
|
||||
receipt['completed_actions_not_replayed']=['apply','verify']
|
||||
receipt['supplemental_cleanup']=verify_session_cleanup(client);save(receipt)
|
||||
else:
|
||||
elif 'apply' in actions:
|
||||
require(existing is None and not client.approle_exists(ROLE),'existing_native_objects_require_reconciliation')
|
||||
for action in actions:
|
||||
receipt['phase']=action+'_attempt_started';save(receipt)
|
||||
|
|
@ -156,8 +173,7 @@ def admin(directory,negative,resume=False):
|
|||
row={'action':action,'approval_id':IDS[action],'exit_code':rc}
|
||||
if action=='apply':
|
||||
role=bao('read','-format=json','auth/approle/role/'+ROLE)['data']
|
||||
limits={'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}
|
||||
require(all(role.get(k)==v for k,v in limits.items()) and role.get('token_policies')==[ROLE],'role_limits_mismatch');row['limits']=limits
|
||||
require(all(role.get(k)==v for k,v in LIMITS.items()) and role.get('token_policies')==[ROLE],'role_limits_mismatch');row['limits']=dict(LIMITS)
|
||||
elif action=='verify':
|
||||
row.update(verify_session_cleanup(client))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -28,11 +28,22 @@ class TestProbe(unittest.TestCase):
|
|||
def test_server_failure_is_not_revocation_proof(self):
|
||||
with self.assertRaisesRegex(ValueError,'revocation_probe_not_definitive'):self.check(500)
|
||||
def test_reconciled_prior_phase(self):
|
||||
prior={'phase':'verify_attempt_started','failure_code':'revoked_token_still_usable','actions':[{'action':'apply','approval_id':m.IDS['apply'],'exit_code':0,'limits':{'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}}]}
|
||||
prior={'phase':'verify_attempt_started','failure_code':'revoked_token_still_usable','actions':[{'action':'apply','approval_id':m.PRIOR_IDS['apply'],'exit_code':0,'limits':{'token_ttl':900,'token_max_ttl':1800,'secret_id_ttl':900,'secret_id_num_uses':1,'token_num_uses':8}}]}
|
||||
with patch.object(Path,'read_text',return_value=json.dumps(prior)):
|
||||
self.assertEqual(m.resume_receipt(),prior)
|
||||
prior['actions'][0]['approval_id']='other'
|
||||
with patch.object(Path,'read_text',return_value=json.dumps(prior)):
|
||||
with self.assertRaisesRegex(ValueError,'prior_apply_not_verified'):m.resume_receipt()
|
||||
def test_fresh_apply_branch(self):
|
||||
hcl='path "auth/token/lookup-self" {\n capabilities = ["read"]\n}\n'
|
||||
role=dict(m.LIMITS,token_policies=[m.ROLE])
|
||||
self.assertEqual(m.fresh_apply_plan(hcl,None,None),(tuple(m.IDS),None))
|
||||
actions,row=m.fresh_apply_plan(hcl,hcl+'\n',role)
|
||||
self.assertEqual(actions,('verify','exec'))
|
||||
self.assertNotIn('apply',actions)
|
||||
self.assertEqual(row,{'action':'apply','already_satisfied':True,'limits':dict(m.LIMITS)})
|
||||
self.assertNotIn('approval_id',row)
|
||||
for existing,live in ((hcl,None),(None,role),('other\n',role),(hcl,dict(role,token_ttl=1)),(hcl,dict(role,token_policies=[m.ROLE,'default'])),(hcl,dict(role,token_policies=m.ROLE))):
|
||||
with self.assertRaisesRegex(ValueError,'existing_native_objects_require_reconciliation'):m.fresh_apply_plan(hcl,existing,live)
|
||||
|
||||
if __name__=='__main__':unittest.main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue