Handle actual Bao absence response and retain safe attempt phases
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a10780-6d41-7952-9718-dfbc1f41236f
This commit is contained in:
parent
a7bc33b867
commit
f0c9a15235
4 changed files with 133 additions and 11 deletions
|
|
@ -3,6 +3,7 @@
|
|||
Does not read/write KV values, change issuer custody, or deploy Kubernetes objects.
|
||||
"""
|
||||
import argparse
|
||||
from datetime import datetime, timezone
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
|
|
@ -10,6 +11,7 @@ import os
|
|||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import uuid
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
CCR = ROOT / 'credential-change-requests/CCR-2026-0032.yaml'
|
||||
|
|
@ -29,8 +31,12 @@ def cli(arguments, payload=None, *, missing_ok=False):
|
|||
except (OSError, subprocess.TimeoutExpired):
|
||||
raise Refused(4) from None
|
||||
if result.returncode:
|
||||
# Only a structured API 404 is absence. Denial/transport failure is not.
|
||||
if missing_ok and result.returncode == 2 and b'Code: 404' in result.stderr:
|
||||
# bao read turns an empty 404 into this exact path-specific diagnostic.
|
||||
# Do not treat arbitrary stderr containing 404, denial or timeout as absence.
|
||||
if (missing_ok and arguments[:2] == ['read', '-format=json']
|
||||
and len(arguments) == 3 and result.returncode == 2
|
||||
and not result.stdout
|
||||
and result.stderr.strip() == ('No value found at ' + arguments[2]).encode()):
|
||||
return None
|
||||
raise Refused(4)
|
||||
if arguments[0] == 'write' and not result.stdout.strip():
|
||||
|
|
@ -86,8 +92,10 @@ def source(expected_digest):
|
|||
return policy, payload
|
||||
|
||||
|
||||
def apply(policy, payload, *, command=cli):
|
||||
def apply(policy, payload, *, command=cli, phase=lambda value: None):
|
||||
phase("read_policy")
|
||||
current_policy = command(['read', '-format=json', 'sys/policies/acl/' + POLICY], missing_ok=True)
|
||||
phase('read_role')
|
||||
current_role = command(['read', '-format=json', ROLE], missing_ok=True)
|
||||
# Check BOTH before mutating either; differing objects require a fresh review.
|
||||
if current_policy is not None and current_policy.get('data', {}).get('policy') != policy:
|
||||
|
|
@ -95,11 +103,15 @@ def apply(policy, payload, *, command=cli):
|
|||
if current_role is not None and not role_matches(current_role.get('data')):
|
||||
raise Refused(3)
|
||||
if current_policy is None:
|
||||
phase('write_policy')
|
||||
command(['write', '-format=json', 'sys/policies/acl/' + POLICY, '-'],
|
||||
json.dumps({'policy': policy}).encode())
|
||||
if current_role is None:
|
||||
phase('write_role')
|
||||
command(['write', '-format=json', ROLE, '-'], json.dumps(payload).encode())
|
||||
phase('verify_policy')
|
||||
verified_policy = command(['read', '-format=json', 'sys/policies/acl/' + POLICY])
|
||||
phase('verify_role')
|
||||
verified_role = command(['read', '-format=json', ROLE])
|
||||
if (verified_policy.get('data', {}).get('policy') != policy
|
||||
or not role_matches(verified_role.get('data'))):
|
||||
|
|
@ -107,6 +119,10 @@ def apply(policy, payload, *, command=cli):
|
|||
|
||||
|
||||
def main():
|
||||
receipt = {'schema': 'requester-metadata-attempt.v1', 'ccr': 'CCR-2026-0032',
|
||||
'phase': 'arguments', 'exit_code': 2, 'native_delivery_verified': False}
|
||||
def phase(value):
|
||||
receipt['phase'] = value
|
||||
try:
|
||||
parser = argparse.ArgumentParser(add_help=False)
|
||||
parser.add_argument('--expected-ccr-sha256', required=True)
|
||||
|
|
@ -118,20 +134,39 @@ def main():
|
|||
args = parser.parse_args()
|
||||
finally:
|
||||
sys.stderr = original
|
||||
phase('attended_boundary')
|
||||
if (Path.home().parent.name != '.warden-attended-login'
|
||||
or os.getenv('BAO_TOKEN') or os.getenv('VAULT_TOKEN')):
|
||||
raise Refused(2)
|
||||
phase('source')
|
||||
policy, payload = source(args.expected_ccr_sha256)
|
||||
phase('identity')
|
||||
identity = cli(['token', 'lookup', '-format=json']).get('data', {})
|
||||
policies = identity.get('policies', [])
|
||||
if 'platform-admin' not in policies or 'root' in policies:
|
||||
raise Refused(2)
|
||||
apply(policy, payload)
|
||||
apply(policy, payload, phase=phase)
|
||||
phase('metadata_verified')
|
||||
receipt['exit_code'] = 0
|
||||
return 0
|
||||
except Refused as exc:
|
||||
receipt['exit_code'] = exc.code
|
||||
return exc.code
|
||||
except BaseException:
|
||||
return 2
|
||||
finally:
|
||||
# Fixed metadata only. Never persist CLI bytes, exception text or identity data.
|
||||
try:
|
||||
directory = ROOT / 'docs/evidence/requester-metadata'
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
receipt['at'] = datetime.now(timezone.utc).isoformat()
|
||||
path = directory / (uuid.uuid4().hex + '.json')
|
||||
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
|
||||
with os.fdopen(fd, 'w') as stream:
|
||||
json.dump(receipt, stream, sort_keys=True)
|
||||
stream.write('\n')
|
||||
except BaseException:
|
||||
return 6 # Receipt could not be retained; metadata may have changed.
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue