railiance-platform/scripts/telemetry_smtp_entry.py
codex 3d43a9b1a3
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Prepare password-free telemetry SMTP entry for attended custody
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e6f1-443f-7783-9920-a16b2ffc467f
2026-09-28 11:11:34 +02:00

55 lines
2 KiB
Python

#!/usr/bin/env python3
"""Silent attended creation of a password-free telemetry SMTP KV entry.
Never overwrite an existing version, including a password subsequently added by
its owner. Run inside warden's attended OpenBao platform-admin login envelope.
"""
import json
import os
import subprocess
import sys
PATH = 'platform/workloads/railiance-telemetry/smtp'
FIELDS = {'SMTP_HOST': 'smtp.ionos.de', 'SMTP_PORT': '587',
'SMTP_USERNAME': 'platform@coulomb.social',
'SMTP_FROM': 'platform@coulomb.social', 'SMTP_STARTTLS': 'true'}
def command(args):
return subprocess.run(['bao', *args], capture_output=True, timeout=30)
def run(invoke=command):
# Read only metadata before CAS=0 creation. No existing credential value is
# needed to refuse an overwrite. The owner can safely rerun after adding it.
before = invoke(['kv', 'metadata', 'get', '-format=json', PATH])
if before.returncode == 0:
metadata = json.loads(before.stdout)['data']
if type(metadata.get('current_version')) is int and metadata['current_version'] >= 1:
return 0
return 20
# Never infer absence from arbitrary errors or an unauthenticated connection.
if b'No value found at ' not in before.stderr + before.stdout:
return 21
created = invoke(['kv', 'put', '-format=json', '-cas=0', PATH,
*[key + '=' + value for key, value in FIELDS.items()]])
if created.returncode:
return 22
if json.loads(created.stdout).get('data', {}).get('version') != 1:
return 23
after = invoke(['kv', 'metadata', 'get', '-format=json', PATH])
if after.returncode or json.loads(after.stdout)['data'].get('current_version') != 1:
return 24
return 0
if __name__ == '__main__':
# The attended lane refuses all child output, including exceptions.
with open(os.devnull, 'w') as sink:
os.dup2(sink.fileno(), 1)
os.dup2(sink.fileno(), 2)
try:
status = run()
except Exception:
status = 25
sys.exit(status)