Problem
`tracebloc cluster info` prints:
```
expires in: ~10m0s (server may cap shorter)
```
That's the *requested* expiration. The kube-apiserver may cap shorter via `--service-account-max-token-expiration` (often set to 1h or shorter on hardened clusters). Customers reading the displayed value and pasting it into a script expecting that exact validity window get confusing 401s when the token actually expires earlier.
Fix
After `MintIngestorToken` succeeds, parse the JWT's `exp` claim and show the actual expiration window:
```go
import "github.com/golang-jwt/jwt/v5" // or hand-roll: the JWT payload is base64-decoded JSON
claims := jwt.MapClaims{}
// JWT format: header.payload.signature; we only need the payload
parts := strings.Split(tok.Token, ".")
if len(parts) == 3 {
payload, _ := base64.RawURLEncoding.DecodeString(parts[1])
_ = json.Unmarshal(payload, &claims)
if exp, ok := claims["exp"].(float64); ok {
actualExp := time.Until(time.Unix(int64(exp), 0))
printf "expires in: %s (server-decided)", actualExp
}
}
```
Hand-rolling avoids the jwt dep + signature-validation complexity — we don't need to verify the token, we just want to read its expiry.
Static-secret tokens are unbounded; existing "never (static-secret fallback)" message stays accurate.
Acceptance criteria
- A TokenRequest-minted token with a server-capped expiration displays the capped value, not the requested one
- The displayed window decrements correctly across multiple invocations of the same minted token (verify by storing + re-displaying)
- Static-secret path unchanged
- Malformed JWT (truncated, wrong format) falls back gracefully to the requested-value display rather than crashing
Found by
Self-review of PR #2. Filed as v0.2 hardening; the existing display is accurate-enough for the MVP and the misleading-window concern doesn't actually break any v0.1 flow (the token is short-lived enough that customers don't keep it around).
Problem
`tracebloc cluster info` prints:
```
expires in: ~10m0s (server may cap shorter)
```
That's the *requested* expiration. The kube-apiserver may cap shorter via `--service-account-max-token-expiration` (often set to 1h or shorter on hardened clusters). Customers reading the displayed value and pasting it into a script expecting that exact validity window get confusing 401s when the token actually expires earlier.
Fix
After `MintIngestorToken` succeeds, parse the JWT's `exp` claim and show the actual expiration window:
```go
import "github.com/golang-jwt/jwt/v5" // or hand-roll: the JWT payload is base64-decoded JSON
claims := jwt.MapClaims{}
// JWT format: header.payload.signature; we only need the payload
parts := strings.Split(tok.Token, ".")
if len(parts) == 3 {
payload, _ := base64.RawURLEncoding.DecodeString(parts[1])
_ = json.Unmarshal(payload, &claims)
if exp, ok := claims["exp"].(float64); ok {
actualExp := time.Until(time.Unix(int64(exp), 0))
printf "expires in: %s (server-decided)", actualExp
}
}
```
Hand-rolling avoids the jwt dep + signature-validation complexity — we don't need to verify the token, we just want to read its expiry.
Static-secret tokens are unbounded; existing "never (static-secret fallback)" message stays accurate.
Acceptance criteria
Found by
Self-review of PR #2. Filed as v0.2 hardening; the existing display is accurate-enough for the MVP and the misleading-window concern doesn't actually break any v0.1 flow (the token is short-lived enough that customers don't keep it around).