RPF-WP-0046-T06: eso.token-renewal assurance signal; plan finished
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:
parent
8f7aa1bb77
commit
52224b84f8
5 changed files with 60 additions and 2 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)))
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue