aws-sso: detect the real session end by a refresh attempt, renew before requests fail
Measured: a session lasted <= 6 h (2026-10-11), not the 8 h assumed, so a clock cannot predict the end. token-providers 3.1127.0 refreshes only inside a 5-min window and, on refusal, silently returns the still-valid token. The keeper now makes that attempt itself (pi's own SDK, same cache) when the window opens, and if expiresAt did not advance, logs in while the old token still works. Clock-based renewal, signed-in and hours commands removed.
This commit is contained in:
@@ -359,44 +359,43 @@ Each extension is a TypeScript module loaded by [jiti](https://github.com/unjs/j
|
||||
### `aws-sso.ts`
|
||||
|
||||
Keeps a Bedrock **AWS SSO** session alive, like Claude Code's `awsAuthRefresh`:
|
||||
shortly before the IAM Identity Center session ends (or when a request fails on
|
||||
an expired token) it runs `aws sso login` for you. **You still approve the login.**
|
||||
Off until you enable it.
|
||||
when the IAM Identity Center session ends it runs `aws sso login` for you, before a
|
||||
request fails. **You still approve the login** (or your browser does it silently
|
||||
while it is signed in). Off until you enable it.
|
||||
|
||||
| Command | Effect |
|
||||
|---|---|
|
||||
| `/aws-sso on` / `off` | Enable/disable (persisted in `~/.pi/agent/aws-sso/state.json`) |
|
||||
| `/aws-sso status` | Mode, profile chain, time left, last login |
|
||||
| `/aws-sso status` | Mode, profile chain, session state, last check, last login |
|
||||
| `/aws-sso now` | Log in now |
|
||||
| `/aws-sso mode mac` | Run `aws sso login` on the Docker host over SSH (`~/.ssh-local/config`, host alias `host` or `$PI_AWS_SSO_SSH_HOST`): your own browser opens. Default when the sidecar config exists. |
|
||||
| `/aws-sso mode device` | Run `aws sso login --use-device-code --no-browser` here and show link + code in pi; approve on any device. For SSH/tmux sessions. |
|
||||
| `/aws-sso continue on\|off` | After a request failed on an expired session and the renewal succeeded, send `continue` (default on) |
|
||||
| `/aws-sso signed-in HH:MM` | Correct the estimated start of the browser's sign-in |
|
||||
| `/aws-sso hours <n>` | Session length if your IdC admin changed it (default 8 h, measured) |
|
||||
|
||||
`PI_AWS_SSO_REFRESH=1` / `=0` force it on / off regardless of the saved state.
|
||||
|
||||
**When it renews — and why not earlier.** Per AWS ("Understanding authentication
|
||||
sessions"), the CLI's 1-hour token is refreshed by the SDK "as long as the underlying
|
||||
user interactive session remains valid" — that is the browser's AWS sign-in,
|
||||
admin-capped (8 h measured 2026-10-10). A login while it is valid completes
|
||||
silently ("…can be used until your session expires") but **inherits its end**, so
|
||||
renewing early gains nothing. The keeper therefore renews **2 minutes after** the
|
||||
estimated end: the browser must sign in again through the IdP (silent while
|
||||
"stay signed in" holds) and a fresh session starts, while the CLI's last 1-hour
|
||||
token still covers the gap. If a request fails on an expired token anyway, it
|
||||
renews and sends `continue` (once per 10 min; `/aws-sso continue off` to disable).
|
||||
**How it detects the end.** Per AWS ("Understanding authentication sessions"), the
|
||||
CLI's 1-hour token is refreshed "as long as the underlying user interactive session
|
||||
remains valid", meaning the browser's AWS sign-in. That sign-in is admin-capped and
|
||||
its length is not predictable (measured 8 h on 2026-10-10, at most 6 h on 2026-10-11).
|
||||
When it ends, the next refresh is refused. Inside the SDK's 5-minute pre-expiry
|
||||
window, a refused refresh is *silent*: the SDK keeps returning the still-valid token.
|
||||
So the keeper makes that refresh attempt itself as soon as the window opens: it uses
|
||||
pi's own `@aws-sdk/token-providers` and the same cache file. It then checks whether
|
||||
`expiresAt` in `~/.aws/sso/cache/<sha1(sso-session)>.json` advanced. If it did not,
|
||||
the session is over, and the keeper logs in right away while the old token still
|
||||
covers requests. Nothing is renewed on a clock: a login while the browser sign-in
|
||||
is still valid completes silently ("…can be used until your session expires") but
|
||||
inherits its end, so it gains nothing. Tokens are only ever logged as `sha256[:8]`
|
||||
fingerprints (`~/.pi/agent/aws-sso/events.jsonl`); the token the SDK returns is
|
||||
dropped unread.
|
||||
|
||||
The session start is not stored anywhere. The keeper watches the refresh token in
|
||||
`~/.aws/sso/cache/<sha1(sso-session)>.json`: a new one **after** the end (or after
|
||||
an observed expiry) starts a new session; a new one **before** the end is a silent
|
||||
renewal and keeps the old end. `/aws-sso signed-in HH:MM` corrects the estimate.
|
||||
Tokens are only ever logged as `sha256[:8]` fingerprints (`~/.pi/agent/aws-sso/events.jsonl`).
|
||||
|
||||
**Triggers:** a 60 s timer (2 min after the estimated end; one attempt per session,
|
||||
so an ignored login does not loop), `before_agent_start` (session already expired →
|
||||
log in and wait before sending the prompt), and `message_end` (a request failed
|
||||
with an expired-token error → log in, then send `continue`).
|
||||
**Triggers:** a 20 s timer that checks every 60 s inside the refresh window (every
|
||||
10 min once the token has run out). Unprompted logins happen at most once per
|
||||
30 min, so a login waiting for you does not pile up tabs. `before_agent_start`
|
||||
checks first if the token is in its window and logs in (and waits) if the session
|
||||
is over. `message_end` is the fallback: if a request still fails on an expired
|
||||
token, the keeper renews and sends `continue` (once per 10 min).
|
||||
Only interactive sessions act; print/JSON children (`task`, `fork`) stay inert.
|
||||
A lock file stops several pi processes from starting several logins.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user