fix(auth): run pelican under a PTY so fdp login can re-consent - #12
Merged
Conversation
pelican gates interactive token acquisition on its stdout being a TTY: once the cached refresh token expires it must re-consent via the device-code/browser flow, and refuses to start that flow when stdout is a pipe. `_pelican_get_token` captured stdout with subprocess.PIPE, so `fdp login` worked only while silent renewal was possible and failed with "This program must be run in a terminal to acquire a new token" the moment the refresh token lapsed. Add `_run_in_pty()`, which runs pelican with stdin/stdout/stderr all on a pseudo-terminal: pelican sees a real terminal, its approval URL and prompts are streamed live to our stderr, the output is captured for token extraction, and our stdin is forwarded when it is a TTY. Harden `_extract_token` to pull the JWT out of the resulting interleaved warning/URL/token stream (bare JWT or per-line JSON). Tests: switch the login tests to the new `_run_in_pty` seam and add `TestRunInPty` (a child that refuses unless stdout.isatty(), reproducing the bug) plus interleaved-stream extraction tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
fdp loginfails once the cached pelican OAuth refresh token expires:Root cause (confirmed by a controlled PTY experiment against pelican 7.25.0): pelican gates fresh interactive token acquisition on its stdout being a TTY.
_pelican_get_tokencaptured pelican's stdout withsubprocess.PIPE(inheriting only stdin/stderr), so pelican always saw a non-terminal stdout. While the refresh token was valid pelican renewed silently (no terminal needed), which is why login worked; the moment the refresh token lapsed, pelican needed the device-code/browser flow and refused.Fix
_run_in_pty()runs pelican with stdin/stdout/stderr all on a pseudo-terminal. Pelican sees a real terminal; its approval URL/prompts are streamed live to our stderr; output is captured for token extraction; our stdin is forwarded when it is a TTY. Silent renewal still works unchanged._pelican_get_tokenuses it;_extract_tokenhardened to pull the JWT out of the interleaved warning/URL/token stream (bare JWT or per-line JSON).Tests
_run_in_ptyseam.TestRunInPty: a child that refuses unlessstdout.isatty()(reproduces the bug) + interleaved-stream extraction tests.pytest tests/test_auth.py→ 40 passed; auth/cli/env modules → 73 passed, 1 skipped.🤖 Generated with Claude Code