RPF-WP-0046-T06: eso.token-renewal assurance signal; plan finished
Some checks are pending
CI Smoke / container-smoke (push) Waiting to run
CI Smoke / host-smoke (push) Successful in 0s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 150322@bnt-lap001
Assistant-Session: 16a7b788-374e-4915-a1df-fc87ffd9a5e4
This commit is contained in:
codex 2026-09-24 00:48:24 +02:00
parent 8f7aa1bb77
commit 52224b84f8
5 changed files with 60 additions and 2 deletions

View file

@ -95,6 +95,10 @@
"forgejo-db.restore": { "forgejo-db.restore": {
"owner": "railiance-platform", "owner": "railiance-platform",
"max_age_seconds": 2592000 "max_age_seconds": 2592000
},
"eso.token-renewal": {
"owner": "railiance-platform",
"max_age_seconds": 129600
} }
} }
} }

View file

@ -54,6 +54,13 @@ lag guarantee. The fleet ESO aggregate is deliberately a conservative inventory
check; an obsolete resource must be explicitly classified by its owner before check; an obsolete resource must be explicitly classified by its owner before
it is excluded. One ESO failure cannot disappear inside an average. it is excluded. One ESO failure cannot disappear inside an average.
`eso.token-renewal` (RPF-WP-0046) is the last successful run of the
`external-secrets/eso-token-renewer` CronJob. The CronJob keeps the periodic
parent tokens of the five dynamic-database stores alive. The signal reads
CronJob status timestamps only. It fails when a newer scheduled run has not
succeeded within an hour, and it goes stale after 36h. The tokens lapse after
7 days without renewal.
The following remain missing until a native value-safe adapter and acceptance The following remain missing until a native value-safe adapter and acceptance
exist: validated isolated restore receipts, exist: validated isolated restore receipts,
OpenBao snapshot/restore proof, and offsite upload/restore receipts. Missing OpenBao snapshot/restore proof, and offsite upload/restore receipts. Missing

View file

@ -36,6 +36,21 @@ def memory_bytes(value):
return float(match.group(1)) * multipliers[unit] return float(match.group(1)) * multipliers[unit]
def renewal_signal(status, now):
"""Classify eso-token-renewer CronJob status (RPF-WP-0046) from timestamps only."""
success = status.get('lastSuccessfulTime') or ''
scheduled = status.get('lastScheduleTime') or ''
if not success:
return 'unavailable', now.isoformat()
succeeded_at = datetime.fromisoformat(success.replace('Z', '+00:00'))
if scheduled:
scheduled_at = datetime.fromisoformat(scheduled.replace('Z', '+00:00'))
# A newer scheduled run that has not succeeded within an hour failed.
if (scheduled_at - succeeded_at).total_seconds() > 3600 and (now - scheduled_at).total_seconds() > 3600:
return 'fail', scheduled
return 'pass', success
def capture(): def capture():
contract = read_contract(ROOT / 'assurance/service-contract.json') contract = read_contract(ROOT / 'assurance/service-contract.json')
uid = query(['get', 'namespace', 'kube-system', '-o', 'go-template={{printf "%q" .metadata.uid}}']) uid = query(['get', 'namespace', 'kube-system', '-o', 'go-template={{printf "%q" .metadata.uid}}'])
@ -94,6 +109,13 @@ def capture():
except (ValueError, KeyError, TypeError, subprocess.TimeoutExpired): except (ValueError, KeyError, TypeError, subprocess.TimeoutExpired):
add('eso.ready', 'unavailable') add('eso.ready', 'unavailable')
add('eso.refresh', 'unavailable') add('eso.refresh', 'unavailable')
try:
status = query(['get', 'cronjob', 'eso-token-renewer', '-n', 'external-secrets', '-o',
'go-template={"lastSuccessfulTime":{{printf "%q" (or .status.lastSuccessfulTime "")}},"lastScheduleTime":{{printf "%q" (or .status.lastScheduleTime "")}}}'])
result, when = renewal_signal(status, datetime.now(timezone.utc))
add('eso.token-renewal', result, when)
except (ValueError, KeyError, TypeError, subprocess.TimeoutExpired):
add('eso.token-renewal', 'unavailable')
# No token, Secret, application data/logs or seal/unseal mutation. # No token, Secret, application data/logs or seal/unseal mutation.
# Receipt timestamps are preserved; reads never renew recovery evidence. # Receipt timestamps are preserved; reads never renew recovery evidence.
signals.update(recovery_signals(datetime.now(timezone.utc))) signals.update(recovery_signals(datetime.now(timezone.utc)))

View file

@ -166,3 +166,21 @@ class CollectorTests(unittest.TestCase):
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
def test_eso_token_renewal_signal_classification():
import importlib.util
from datetime import datetime, timezone
from pathlib import Path
spec = importlib.util.spec_from_file_location(
'capture', Path(__file__).resolve().parents[1] / 'scripts/capture_service_observation.py')
capture = importlib.util.module_from_spec(spec)
spec.loader.exec_module(capture)
now = datetime(2026, 9, 25, 12, 0, tzinfo=timezone.utc)
assert capture.renewal_signal({}, now)[0] == 'unavailable'
ok = {'lastSuccessfulTime': '2026-09-25T02:40:09Z', 'lastScheduleTime': '2026-09-25T02:40:00Z'}
assert capture.renewal_signal(ok, now) == ('pass', '2026-09-25T02:40:09Z')
failed = {'lastSuccessfulTime': '2026-09-24T02:40:09Z', 'lastScheduleTime': '2026-09-25T02:40:00Z'}
assert capture.renewal_signal(failed, now) == ('fail', '2026-09-25T02:40:00Z')
running = {'lastSuccessfulTime': '2026-09-24T02:40:09Z', 'lastScheduleTime': '2026-09-25T11:30:00Z'}
assert capture.renewal_signal(running, now)[0] == 'pass'

View file

@ -4,7 +4,7 @@ type: workplan
title: "Keep the dynamic-database ESO parent tokens alive: periodic tokens and a renewer" title: "Keep the dynamic-database ESO parent tokens alive: periodic tokens and a renewer"
domain: financials domain: financials
repo: railiance-platform repo: railiance-platform
status: active status: finished
owner: railiance-platform owner: railiance-platform
topic_slug: railiance topic_slug: railiance
created: "2026-09-23" created: "2026-09-23"
@ -165,7 +165,7 @@ ready.
```task ```task
id: RPF-WP-0046-T06 id: RPF-WP-0046-T06
status: todo status: done
priority: medium priority: medium
state_hub_task_id: "2f528e56-ebf0-547e-8d4f-3cb34c348d46" state_hub_task_id: "2f528e56-ebf0-547e-8d4f-3cb34c348d46"
``` ```
@ -210,3 +210,10 @@ state_hub_task_id: "2f528e56-ebf0-547e-8d4f-3cb34c348d46"
State Hub `/repos` returns 200. No workload now depends on a lease from the State Hub `/repos` returns 200. No workload now depends on a lease from the
replaced max-TTL tokens. Those tokens expire on their own, from about replaced max-TTL tokens. Those tokens expire on their own, from about
2026-10-10. 2026-10-10.
- **T06 done.** Hand-offs sent 2026-09-23. rapp-postgres and audit-core were
asked to retire or change their 768h mint scripts. railiance-telemetry was
asked for an alert on a failed run or no success for 48h. activity-core was
told the October re-mint is not needed. `assurance-capture` now emits
`eso.token-renewal` (CronJob status timestamps only, 36h budget), and it is
healthy on the first live check. The owners' follow-through is tracked in
their own repos.