Repository navigation
feat(cli): sign in with xping login --device, and add --no-browser and --workspace (P4) - #249
Merged
Merged
Conversation
…er wording, device flow tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d --workspace (P4) xping login --device runs the device flow (cli-auth-cli-spec §6): fresh discovery, the page and code printed, the page with the code filled in opened when a browser is available, then polling that always waits the interval first, adds 5 s on slow_down, keeps the interval on network errors, and ends on approval, denial, expiry or the server's error. --no-browser prints the loopback link without looking for a browser. --workspace preselects a workspace on both flows; it must be a ULID, otherwise it is a parse error before any request. The record building and the shared failure messages move out of LoopbackFlow so both flows use them. The fake Cloud's ids are now valid ULIDs (they contained U, which Crockford base32 excludes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…, 429 is transient, deadline-capped wait - §2.4: a 429 without an OAuth body is transient while polling. - §6.1: a user_code with a control character is an incomplete response. - §6.3: the last wait stops at the deadline; the first unreachable poll prints one warning; other poll errors map as §4.8 (invalid_client is CloudUnreachable), control characters dropped. - §3.2: the waiting line never rounds a lifetime to "0 minutes". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…p server text out of the terminal (#249 review) - invalid_client while polling exits 15 with the --cloud-url hint, and invalid_request asks for a bug report, as at the start of the flow. - A user_code with a control character is refused, and server error codes lose their control characters in messages and in --json oauthError. - A 429 while polling waits for the next interval instead of ending the login; the first unreachable poll prints one warning on stderr. - The last wait stops at the deadline, so expiry is reported on time. - The waiting line shows seconds when the lifetime is not whole minutes. - One BrowserChoice decides whether either flow opens a browser; LoginOptions has no unused defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xping-admin
added a commit
that referenced
this pull request
Oct 9, 2026
…fidence in xping report (#265) * feat(cli): add login, logout and auth status shells with global Cloud options (P0) (#243) * docs(cli): name the auth phase branches feat/cli-auth-NN-<name> Git cannot hold feat/cli-auth and feat/cli-auth/... at once, so the sub-branch names in §19 of the CLI auth spec could not be created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): add login, logout and auth status shells with global Cloud options (P0) Phase 0 of cli-auth-cli-spec: the global --cloud-url, --api-key and --verbose options; CliConfiguration (flag > XPING_* > Xping__* > appsettings) with Cloud URL validation and normalization; the auth exit codes; Redaction; a verbose stderr logger for Xping.Cli.* only; Ctrl+C as exit 130; scrubbed reporting of escaping exceptions; a test hook on Program.Run; and the CloudUrl row in the configuration reference. login, logout and auth status print "not implemented" and exit 14. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): tighten the auth spec's redaction rules The JWT pattern in §15.2 matched .NET type names and would mangle --verbose stack traces; it now requires the eyJ header and payload. The form-field list gains access_token, id_token and client_secret, and the same names are scrubbed as JSON members. Phase 8 also removes the temporary ci.yml trigger for feat/cli-auth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the test pipeline on PRs into feat/cli-auth Temporary: the CLI auth phases merge into feat/cli-auth by PR, and those PRs need CI. Removed in the last phase (cli-auth-cli-spec §19, phase 8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): keep Ctrl+C working for report and stop auth errors leaking secrets (P0) Review fixes for the phase 0 scaffold: - Ctrl+C is swallowed only while a command that watches the token runs (login, logout, auth status), and a second press still ends the process. report, where and clear stop at once again, prompt included. - Redaction also covers access_token, id_token and client_secret, and token values in JSON bodies. The JWT rule requires the eyJ header and payload, so verbose stack traces keep their type names. - Cloud URL errors no longer quote the value as given: user info is checked first, and a query or fragment is never echoed. Parse errors are scrubbed as a backstop. - XPING__APIKEY and the other all-capitals nested variables are read, as the SDK reads them. - A missing settings directory holds no settings; an unreadable file is a CliConfigurationException naming the file. - The usage hint names the command when a global option comes first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): add Cloud discovery and the OAuth client for xping login (P1) (#244) * docs(cli): follow the contract's issuer and revocation amendments in the auth spec Contract OQ-17 makes the discovery issuer the Cloud URL followed by one slash, as OpenIddict writes it; OQ-19 lets the revocation body be {}. §2.3 and §14.1 compare against {Cloud URL}/, §2.4 ignores the revoke body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): pin the discovery URL rules and device-poll retries in the auth spec Endpoints in the discovery document must meet the Cloud URL's scheme rule, since codes and refresh tokens are sent there; the gateway URI also refuses a query. PollDeviceAsync makes no retries of its own: the next poll is the retry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): add Cloud discovery and the OAuth client for xping login (P1) Phase 1 of cli-auth-cli-spec: DiscoveryClient validates the discovery document in the §2.3 order (issuer is the Cloud URL plus one slash per contract OQ-17, gateway URI, contract version, minimum CLI version, endpoints) and fails closed with CloudUnreachable or CloudVersionMismatch. Documents are cached for 24 hours under ~/.xping/cache/discovery, owner-only, and revalidated on read; login bypasses the cache. OAuthClient covers the code exchange, refresh (no scope), device start and poll, and revocation (body ignored, OQ-19), with the contract §8.1 retries on an injected TimeProvider. Device polling never retries on its own. Tokens and device codes are registered with Redaction and kept out of ToString. The xping-oauth client follows no redirects, sends no cookies, has a 15 s timeout and no factory logging. Tests run against FakeCloud, an in-process Portal with PKCE, single-use codes, refresh rotation with the 30 s reuse leeway, device grants, revocation, fault injection and a request log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): amend the auth spec for the P1 review fixes The code exchange does not retry after a network failure, since the code may already be redeemed. Network reasons are named broadly (connection failed, TLS error). Temporary files are unique per write, every missing level under ~/.xping is created 0700, and an existing ~/.xping made by the SDK local store in a repository home is tightened to 0700. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): harden discovery and the OAuth client after review (P1) - The code exchange no longer retries after a network failure: the server may have redeemed the single-use code, and the retry's invalid_grant hid the real failure. 5xx answers are still retried. - Temporary files are unique per write; two writers of one file in one process deleted each other's temporary file and lost a write. - An existing ~/.xping with group or other bits is tightened to 0700, and every missing level is created 0700, not only the last one. - Device verification pages follow the server URL rule (https, or http on localhost/127.0.0.1), shared with discovery as ServerUri. - SemVer parsing refuses a trailing newline and non-ASCII digits, and compares numeric prerelease identifiers of any length. - Network reasons read "connection failed" and "TLS error", which is all HttpRequestError can tell apart. - PostAsync loses its unused cloudUrl parameter. Tests: DriveAsync moves the fake clock exactly by each timer the client starts, so retry gaps are exact on any machine and a stuck task fails after 30 s instead of hanging. Each fix has a regression test that fails without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): add the file credential store and the credential resolver (P2) (#245) * docs(cli): amend the auth spec for the file store and the resolver (P2) ReadAsync returns the warning with the result, CredentialStores owns the read order, an unsafe file's entries are never carried into a safe one, and the resolver takes CliConfiguration and leaves when-to-fall-back to the authenticated pipeline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): add the file credential store and the credential resolver (P2) CredentialRecord, ICredentialStore and FileCredentialStore keep sign-ins in ~/.xping/credentials.json (0600 in a 0700 directory, owner-only ACL on Windows, atomic replace). Files others can read are refused with chmod instructions; corrupt entries read as nothing with a warning and are kept. CredentialStores holds the keychain-then-file read order, and CredentialResolver picks --api-key, the stored login, then the ambient key, without a network call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): amend the auth spec for the P2 review fixes A failing credential store no longer stops the lookup or the sign-out, an unreadable store is reported separately from a corrupt entry, and a delete leaves a file it cannot parse untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): harden the file credential store and the resolver after review (P2) - A ~/.xping the user cannot search is a CredentialStoreException, not a raw UnauthorizedAccessException from the mode check. - CredentialStores keeps reading after a store fails, so a locked keychain cannot hide a file login, and DeleteAllAsync tries every store before reporting the failures. - The resolver reports unreadable stores as StoreFailures, apart from corrupt-entry warnings, so auth status can exit 17. - Signing out leaves an unparseable file untouched instead of deleting every Cloud URL's sign-in. - Reads share the file for delete, so on Windows a reader no longer makes the replacing move fail. - XpingHome.Display checks for an empty profile before GetRelativePath. - CredentialStoresTests split out; Display tested without the real HOME; no dictionary copy, one mode check per delete, no Lazy in the selector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): sign in with xping login in the browser, and add logout and auth status (P3) (#247) * docs(cli): amend the auth spec for P3: stderr decides decoration, config key source, flow test seams Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): note that [::1] loopback binding works on Windows only The managed HttpListener of macOS and Linux rejects bracketed IPv6 prefixes, so the §4.3 fallback to [::1] can only bind under http.sys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): sign in with xping login in the browser, and add logout and auth status (P3) xping login runs the loopback PKCE flow (cli-auth-cli-spec §4): fresh discovery, a one-shot listener on 127.0.0.1, the link printed once, the browser opened unless the machine is headless, a 5-minute wait, the code exchange, and the record stored in the file store. It refuses to run without a terminal or with CI set, and every failure has its exit code and, under --json, its JSON document. xping logout revokes the refresh token and removes the sign-in and the caches for the Cloud URL, locally even when revocation fails (§12). xping auth status reports the credential in use without a request (§3.4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): report every auth failure under --json, scrubbed, with the configured Cloud URL (#247 review) - One AuthCommandRunner for login, logout and auth status: a bad XPING_CLOUDURL or settings file now writes the failure document (error "configuration", exit 2), the document names the configured Cloud URL, and every failure message is scrubbed on both streams. - Local listener failures report "local_listener", not "oauth_error". - logout tells "refused" from "could not reach" when revocation fails. - An invalid_request without a description reads cleanly. - Browser launchers run with /dev/null streams through a constant sh script, so a browser they start cannot write into --json output or die on a closed pipe. The launcher's duplicate headless check is gone. - Spec §3.2 and §5.1 amended; AGENTS.md names the --json output as the exception to the IXpingSerializer rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): sign in with xping login --device, and add --no-browser and --workspace (P4) (#249) * docs(cli): amend the auth spec for P4: --workspace format, --no-browser wording, device flow tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): sign in with xping login --device, and add --no-browser and --workspace (P4) xping login --device runs the device flow (cli-auth-cli-spec §6): fresh discovery, the page and code printed, the page with the code filled in opened when a browser is available, then polling that always waits the interval first, adds 5 s on slow_down, keeps the interval on network errors, and ends on approval, denial, expiry or the server's error. --no-browser prints the loopback link without looking for a browser. --workspace preselects a workspace on both flows; it must be a ULID, otherwise it is a parse error before any request. The record building and the shared failure messages move out of LoopbackFlow so both flows use them. The fake Cloud's ids are now valid ULIDs (they contained U, which Crockford base32 excludes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): amend the auth spec for the P4 review: poll errors as §4.8, 429 is transient, deadline-capped wait - §2.4: a 429 without an OAuth body is transient while polling. - §6.1: a user_code with a control character is an incomplete response. - §6.3: the last wait stops at the deadline; the first unreachable poll prints one warning; other poll errors map as §4.8 (invalid_client is CloudUnreachable), control characters dropped. - §3.2: the waiting line never rounds a lifetime to "0 minutes". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): report device poll errors with the right exit code, and keep server text out of the terminal (#249 review) - invalid_client while polling exits 15 with the --cloud-url hint, and invalid_request asks for a bug report, as at the start of the flow. - A user_code with a control character is refused, and server error codes lose their control characters in messages and in --json oauthError. - A 429 while polling waits for the next interval instead of ending the login; the first unreachable poll prints one warning on stderr. - The last wait stops at the deadline, so expiry is reported on time. - The waiting line shows seconds when the lifetime is not whole minutes. - One BrowserChoice decides whether either flow opens a browser; LoginOptions has no unused defaults. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): keep xping login in the OS keychain, with the file as fallback (P5) (#252) * docs(cli): amend the auth spec for P5: libsecret v functions, probe-aware read order, keychain reasons - §7.3: libsecret is bound at run time and called through the non-variadic storev/lookupv/clearv functions; IKeychainCredentialStore adds MaxSecretBytes and Probe; the service name is a constructor argument so tests use xping-cli-tests. - §7.4: Select(cloudUrl); a keychain whose probe failed is left out of that process's read order, so no keyring means exit 10, not 14. - §7.6: "keychain unavailable" for macOS errors other than locked. - §17.2, §18.2: PR CI excludes Category=CredentialStore; flow tests run without a keychain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): keep xping login in the OS keychain, with the file as fallback (P5) Sign-ins go to Windows Credential Manager, the macOS Keychain or the Secret Service when a probe of the real entry succeeds, and to ~/.xping/credentials.json otherwise, with the reason printed at login and listed by auth status. Reads go keychain first, then file, so a login made over SSH still works in a desktop session. - WindowsCredentialStore: CredRead/Write/Delete; records over 2560 bytes drop the access token, and fail if they still do not fit. - MacOsKeychainStore: SecItem* with CoreFoundation dictionaries; writes update in place so "Always Allow" survives. - LibSecretStore: libsecret loaded at run time; missing library or session bus is a fallback reason. - KeychainRecordCodec shares the size and corruption rules. - cli-credential-stores.yml runs the real-keychain tests weekly on Windows, macOS and Ubuntu; ci.yml excludes them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: temporarily run the credential store workflow on the P5 branch Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: name the Windows and macOS credential store step after its stores Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: remove the temporary push trigger from the credential store workflow Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): amend the auth spec for the P5 review: logout reaches an unreachable keychain, one keychain read per command - §7.4: a keychain whose probe failed stays in CredentialStores.Unreachable (unless it cannot hold anything); logout tries it and warns, without failing, when it cannot. The probe's read is reused by the first read. - §7.4: failing to clear the old file entry after a keychain write is a warning, not a store failure. - §17.2: "Weekly", not "Nightly"; the fallback step injects its environment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): sign out of a locked keychain over SSH, and read the keychain once per command (P5) - logout also tries a keychain whose probe failed (locked, no session bus), and warns that a desktop sign-in may remain when it cannot reach it; it no longer says "not signed in" while one is stored there. LibSecretStore fails fast without a session bus instead of letting libsecret autolaunch one. - The macOS and libsecret stores hand the probe's read to the first ReadAsync (ProbedSecret), so an upgrade shows one access dialog, not two. - login no longer exits 14 when only the cleanup of the old file entry fails; it warns instead. - FileCredentialStore decodes entries with the shared CredentialRecordCodec (renamed from KeychainRecordCodec). - The no-bus workflow step drops an env -u that the tests never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): amend the auth spec: native credential stores are excluded from PR coverage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cli): measure P5 coverage where it can run, and cover the login and logout warning paths The Windows, macOS and libsecret stores, and the OS switch that builds them, are excluded from coverage with the reason: the Ubuntu PR runner cannot execute them, and cli-credential-stores.yml tests them weekly against the real stores. New tests cover the two command paths Codecov reported: login warning when the old file entry cannot be removed, and logout combining a failed revocation with an unchecked keychain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): refresh Cloud sign-ins and read the DataGateway with them (P6) (#256) * docs: amend the CLI auth spec for the phase 6 pipeline (P6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): refresh Cloud sign-ins and read the DataGateway with them (P6) TokenRefresher (proactive, single-flight, cross-process lock, reuse handling), BearerTokenHandler and ApiKeyHandler, the xping-cloud client with resilience, CloudApiClient with the status-then-title mapping, and FakeCloud gateway routes. Nothing calls it from report until P7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): keep Cloud sign-ins through cancels, failed writes and stray 401s (P6) Review fixes for #256: - A refresh runs to the end once the lock is held, and the new pair is stored before it is used, so a cancel or attempt timeout cannot leave the old refresh token in the store. - An older stored record no longer replaces a newer one in memory. - Only a 401 on a request retried after a refresh ends the sign-in, and a sign-in stored meanwhile by another login is kept. - The lock wait (now 5 s) is shorter than the 10 s attempt it runs in; the Windows lock file's ACL is set by path and the handle is closed if that fails. - Retries use HttpRetryStrategyOptions and IsTransient; a project list without items is an incomplete answer. - Spec §9.1, §9.4, §9.7 and §10.3 describe the composed pipeline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(cli): check the lock file's ACL and share mode on Windows (P6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): show Xping Cloud confidence in xping report when signed in (P7) (#258) * docs: amend the cli-auth and report specs for Cloud-enriched reports (P7) Answer Q-4 (no branch clause), render the Cloud slots from the cloud objects so JSON metrics and contrast stay local, fix the category and evidence wording, and cache name matches only for stored logins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(sdk): record the pinned project id in local sessions (P7) The CLI reads Xping.ProjectId to bind a local run to its Cloud project without reproducing the Cloud's key derivation (cli-auth spec §11.2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(cli): show Xping Cloud confidence in xping report when signed in (P7) When a credential resolves, report binds the assembly to its Cloud project (--project, XPING_PROJECTID, the session's pin, then a name match cached for 24 h) and reads each reported test from the DataGateway, four at a time inside a 10 s budget. The header gains "· cloud", rows gain "confidence 0.62 · moderately reliable", latest-run rows say "confidence 0.94 over 812 runs" and --id adds cloud pairs. JSON moves to 1.22 with context.cloud and a cloud object per finding and latest-run failure. An invalid sign-in falls back to XPING_APIKEY once; network errors, 5xx and version mismatches never fall back. Every failure leaves the local report and its exit code unchanged, with one stderr hint (the expired-sign-in hint is printed even off a terminal). Existing report tests are isolated from the developer's own credentials. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): say when a Cloud project key names no project, and other review fixes (P7) - A key from --project, XPING_PROJECTID, appsettings or the session pin under which nothing is found is checked with GetProjectAsync; a 404 is now a hint instead of an "ok" report with no data. - Only each assembly's newest session decides its pin. - A cached name match is re-listed only when it came from the cache. - "· cloud" appears only when a row shows a Cloud score. - No sign-up pitch on a report that read Cloud data. - appsettings keys report source "config"; reason is the hint text. - ASCII joins score and category with "-", not the trailer's "|". - Kebab case comes from JsonNamingPolicy.KebabCaseLower. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): document xping login, logout and auth status (P8) (#263) * docs: amend the cli-auth spec to match what P0-P7 shipped Drops state_mismatch (a wrong state is ignored and the CLI keeps waiting), fixes the auth status store-failure exit code (17), and records the hint lines, glyphs and exit-code columns the implementation actually has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): document xping login, logout and auth status Adds the three commands, global options, credential precedence, the full exit-code table, the macOS keychain prompt and the WSL and devcontainer notes, and the Cloud hint lines report can print. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: replace the "landing next" notes now that xping login ships README, the docs home, the NuGet page, local-first, CI setup and troubleshooting now describe signing in and Cloud data in the report, and drop the never-built --source flag from the roadmap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci: run the test pipeline only for PRs to main feat/cli-auth was listed so its phase PRs ran CI; phase 8 is the last one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(cli): close the jq fence that hid half the CLI reference's anchors A closing fence followed by text on the same line kept the fence open, so every heading after the population marker lost its id and in-page links broke. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: correct exit codes, key sources and sign-in storage claims from review Exit 2 for a bad XPING_CLOUDURL is auth-command only, 130 applies to every command, the nested Xping__ApiKey/Xping__CloudUrl forms are listed, the file store is named alongside the keychain, and XPING_MODE is marked as SDK-only. The feat/cli-auth CI trigger stays until the PR to main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): store the sign-in in the file when Windows Credential Manager refuses it (#264) * docs: let a refused keychain write fall back to the file in the cli-auth spec Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): store the sign-in in the file when Windows Credential Manager refuses it A damaged Windows profile passes the read-only probe and then fails every CredWrite with error 8, so xping login exited 17 after a successful sign-in. The sign-in now goes to ~/.xping/credentials.json with a warning, a stale keychain entry is removed so it cannot shadow it, and Windows errors carry their system text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * ci: stop running the test pipeline for PRs to feat/cli-auth The integration branch is merging to main (cli-auth-cli-spec §19, phase 8). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <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.
Phase 4 of
docs/internals/implementation-specs/cli-auth-cli-spec.md(§19).Contract / spec sections
DeviceFlow— fresh discovery, prompt, optional browser open ofverification_uri_complete, polling that waits the interval before every poll,slow_down+5 s, transient errors keep the interval, deadline andexpired_token→ exit 12,access_denied→ 11,invalid_grant/ other → 14.--device,--no-browser,--workspace; §4.2xping_workspace_idon the authorization URL; §5.2--no-browserskips detection.Spec amendments (first commit)
--workspacemust be a ULID; otherwise exit 2 before any request (§3.2, §13).--no-browserfirst line drops "No browser was found…" (§3.2, §5.2).DeviceFlowTestsrun againstFakeCloudwith the realOAuthClient, as the loopback flow is tested (§18.1).Also
SignedInRecordandFlowFailuresextracted fromLoopbackFlowand shared by both flows.FakeCloudids are now valid ULIDs (they containedU).Tests
Login_Device_Success,_SlowDown,_Denied,_Expired,_ServerExpired,_CancelledWhilePolling, browser/headless/--no-browser,--workspace, interactive precondition (LoginDeviceTests).DeviceFlowTests: poll gaps on the fake clock, slow_down accumulation (5/10/15 s), transient errors keep the interval, deadline without an extra poll, error mapping, start refusal.LoginCommandTests:--no-browserwording,--workspaceon the authorize URL, invalid workspace → exit 2.dotnet build -c Releaseclean,tests/Xping.Cli.Tests1979/1979 green,dotnet format --verify-no-changesclean.Still to do (exit criterion)
xping login --deviceover SSH (macOS, file store), approved on another device,xping auth status.🤖 Generated with Claude Code