Deferred from #214, which shipped the device-code flow.
State
The flow is implemented and covered by automated tests: the state machine against wiremock (string interval, 403 and 404 as pending, deadline expiry, 404-means-unsupported, 500 aborts), the presenter path, and the clipboard handoff in the view. tests/e2e_codex_signin_device_code.rs exists and is #[ignore]d; it requests a real code from auth.openai.com, prints the URL and code, polls until approval, and asserts the resulting grant is usable rather than merely returned.
What has not happened is a person approving a real code at auth.openai.com/codex/device. That is the one step in #214 that cannot be automated, and it is also the first time the app writes a grant it obtained itself rather than one handed to it.
Why it is deferred rather than dropped
Device code exists as the fallback when port 1455 is already bound, since ChatGPT registers that port and there is nothing to negotiate. In an app that already puts a window on screen the browser flow is the normal path, so the fallback matters less than it would for a headless client. Browser PKCE has been exercised against the live endpoint; this is the remaining untested branch.
To run
cargo test --test e2e_codex_signin_device_code -- --ignored --nocapture
Open the printed URL, enter the printed code, approve. Nothing is written to the keychain unless PA_E2E_CODEX_PERSIST=1.
The test uses serdes_ai_providers::chatgpt_oauth_config().client_id, so a client-id drift upstream fails here rather than silently in production.
Refs #214.
Deferred from #214, which shipped the device-code flow.
State
The flow is implemented and covered by automated tests: the state machine against wiremock (string interval, 403 and 404 as pending, deadline expiry, 404-means-unsupported, 500 aborts), the presenter path, and the clipboard handoff in the view.
tests/e2e_codex_signin_device_code.rsexists and is#[ignore]d; it requests a real code fromauth.openai.com, prints the URL and code, polls until approval, and asserts the resulting grant is usable rather than merely returned.What has not happened is a person approving a real code at
auth.openai.com/codex/device. That is the one step in #214 that cannot be automated, and it is also the first time the app writes a grant it obtained itself rather than one handed to it.Why it is deferred rather than dropped
Device code exists as the fallback when port 1455 is already bound, since ChatGPT registers that port and there is nothing to negotiate. In an app that already puts a window on screen the browser flow is the normal path, so the fallback matters less than it would for a headless client. Browser PKCE has been exercised against the live endpoint; this is the remaining untested branch.
To run
Open the printed URL, enter the printed code, approve. Nothing is written to the keychain unless
PA_E2E_CODEX_PERSIST=1.The test uses
serdes_ai_providers::chatgpt_oauth_config().client_id, so a client-id drift upstream fails here rather than silently in production.Refs #214.