net-kingdom/tools/agent-status/token_expiry.py
tegwick 06291a97da
All checks were successful
Bounded-execution contracts / contracts (push) Successful in 1m30s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Agent status token: 12 h (founder decision 65d8aed4, exception to SI-14 for nk-agent-status)
make agent-status-token requests --duration=12h and prints the real expiry from the token's exp claim
(tools/agent-status/token_expiry.py, never the token), since the API server may cap a duration.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
2026-11-06 08:02:40 +01:00

39 lines
1.3 KiB
Python

#!/usr/bin/env python3
"""Print when the agent status token expires, never the token (NK-WP-0058-T05).
python3 tools/agent-status/token_expiry.py ~/.kube/nk-agent-status.token
Reads only the JWT's `exp` claim; the signature and every other claim are ignored and nothing else is printed.
The API server may cap a requested duration, so this reports the expiry the token really has. Exit 1 when the file
is missing, malformed or already expired.
"""
import base64
import datetime as dt
import json
import sys
from pathlib import Path
def expiry(path):
parts = Path(path).read_text().strip().split('.')
if len(parts) != 3:
raise ValueError('not_a_jwt')
payload = parts[1] + '=' * (-len(parts[1]) % 4)
return dt.datetime.fromtimestamp(int(json.loads(base64.urlsafe_b64decode(payload))['exp']), dt.timezone.utc)
def main(argv=None):
path = (argv if argv is not None else sys.argv[1:])[0]
try:
exp = expiry(path)
except (OSError, ValueError, KeyError):
print('agent-status-token: unreadable')
return 1
left = exp - dt.datetime.now(dt.timezone.utc)
hours = left.total_seconds() / 3600
print(f'agent-status-token: valid until {exp:%Y-%m-%d %H:%M}Z ({hours:.1f} h)')
return 0 if hours > 0 else 1
if __name__ == '__main__':
sys.exit(main())