63 lines
2.8 KiB
Python
63 lines
2.8 KiB
Python
|
|
"""Silent exact-reader metadata preflight under the Warden login envelope."""
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
from pathlib import Path
|
||
|
|
import subprocess
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
POLICY = 'workload-kv-read-secrets-engine-approval-client'
|
||
|
|
DATA = 'platform/data/workloads/secrets-engine/approval-client'
|
||
|
|
META = 'platform/metadata/workloads/secrets-engine/approval-client'
|
||
|
|
EXPECTED = {
|
||
|
|
DATA: ['read'], META: ['read'],
|
||
|
|
'platform/data/workloads/approval-engine/operator-client': ['deny'],
|
||
|
|
'platform/metadata/workloads/secrets-engine': ['deny'],
|
||
|
|
'platform/metadata/workloads': ['deny'],
|
||
|
|
'platform/data/workloads/activity-core/llm-connect/llm-connect-provider-secrets': ['deny'],
|
||
|
|
'sys/policies/acl/' + POLICY: ['deny'],
|
||
|
|
'auth/netkingdom/role/secrets-engine-approval-client-workload-kv-read': ['deny'],
|
||
|
|
}
|
||
|
|
RECEIPT = Path('/home/worsch/railiance-platform/docs/evidence/2026-09-14-ccr0019-reader-preflight.json')
|
||
|
|
|
||
|
|
def validate_identity(identity):
|
||
|
|
policies = set(identity.get('policies', [])) | set(identity.get('identity_policies', []))
|
||
|
|
if POLICY not in policies or policies - {POLICY, 'default'}:
|
||
|
|
raise ValueError('unexpected_effective_policies')
|
||
|
|
if not identity.get('entity_id') or not 0 < identity.get('ttl', 0) <= 900:
|
||
|
|
raise ValueError('unbounded_or_unidentified_reader')
|
||
|
|
|
||
|
|
def bao(*args):
|
||
|
|
result = subprocess.run(['bao', *args], capture_output=True, text=True, timeout=30)
|
||
|
|
if result.returncode:
|
||
|
|
raise ValueError('metadata_request_failed')
|
||
|
|
return json.loads(result.stdout)
|
||
|
|
|
||
|
|
def main():
|
||
|
|
receipt = {'observed_at': datetime.now(timezone.utc).isoformat(),
|
||
|
|
'ccr_id': 'CCR-2026-0019', 'secret_values_read': False,
|
||
|
|
'status': 'refused', 'checks': {}}
|
||
|
|
try:
|
||
|
|
if Path.home().parent.name != '.warden-attended-login' or os.getenv('BAO_TOKEN') or os.getenv('VAULT_TOKEN'):
|
||
|
|
raise ValueError('attended_envelope_required')
|
||
|
|
identity = bao('token', 'lookup', '-format=json')['data']
|
||
|
|
validate_identity(identity)
|
||
|
|
receipt['identity_policy_scope_verified'] = True
|
||
|
|
for path, expected in EXPECTED.items():
|
||
|
|
values = bao('token', 'capabilities', '-format=json', path)
|
||
|
|
if sorted(values) != expected:
|
||
|
|
raise ValueError('capabilities_mismatch')
|
||
|
|
receipt['checks'][path] = expected
|
||
|
|
receipt['status'] = 'passed'
|
||
|
|
except Exception as exc:
|
||
|
|
code = str(exc)
|
||
|
|
receipt['failure'] = code if code in {'attended_envelope_required', 'unexpected_effective_policies', 'unbounded_or_unidentified_reader', 'metadata_request_failed', 'capabilities_mismatch'} else 'preflight_failed'
|
||
|
|
raise
|
||
|
|
finally:
|
||
|
|
RECEIPT.write_text(json.dumps(receipt, indent=2) + '\n')
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
try:
|
||
|
|
main()
|
||
|
|
except Exception:
|
||
|
|
raise SystemExit(1) from None
|