Skip to content

Port upstream 0.64.0: Hugging Face 12 h identity cache, billing-permission message, API-only without cookies - #725

Draft
Finesssee wants to merge 2 commits into
port/upstream-0.64.0from
port/micro-0.64.0-huggingface-identity-billing
Draft

Finesssee wants to merge 2 commits into
port/upstream-0.64.0from
port/micro-0.64.0-huggingface-identity-billing

Conversation

@Finesssee

Copy link
Copy Markdown
Collaborator

Summary

Three Hugging Face parity fixes on the API/billing lane:

  • GAP-11: whoami-v2 identity is cached for 12 h per token (SHA-256 key, raw token never stored, 32-entry cap). Expired (>= 12 h), clock-skewed (age < 0), failed or empty lookups are never served stale. Switching tokens never reuses another account's identity.
  • GAP-12: a 403 from the billing endpoint now says "The Hugging Face token lacks billing access. Use a classic read token or enable Billing read on a fine-grained token." instead of mapping to AuthRequired ("sign in again"). 401 stays AuthRequired; 429 and 5xx messages are unchanged. Optional calls (whoami, ZeroGPU, wallet pages) stay best-effort.
  • GAP-18: API-only refresh (SourceMode::OAuth) makes no browser-cookie call and requests no browser billing page. In Auto mode the cookie/wallet step runs only after the token identity is known and has a user id, and the browser identity is still re-verified on every refresh, so a cached identity cannot keep a wallet after the browser account changes.

Upstream reference

steipete/CodexBar v0.70.0: Sources/CodexBarCore/Resources/Plugins/huggingface.ts (whoami-v2: + token cache, 43200 s / 43200000 ms window, 403 message, wallet gated on identity.userID), Tests/CodexBarTests/HuggingFacePluginTests.swift (identity cache isolated per token, billing failure classification), HuggingFaceWalletPluginTests.swift (API only never resolves cookies; cached identity cannot retain a wallet), docs/huggingface.md. 0.64.0 audit item G1 (steipete#3399).

Ported / Deferred

Ported: all three behaviors above, with deterministic tests (injected clock and counting fakes; a local TCP server proves an HTML 403 body still yields the permission message).
Deferred: upstream also honors a per-provider cookie "Off"/"Manual" policy for the wallet. Win-CodexBar's FetchContext does not carry that policy for Hugging Face (there is no cookie picker), so only the source-mode gate is ported. A plan-only whoami response (isPro without name/email/id) is no longer cached or shown as an identity, matching upstream's username || email || userID condition.

Validation

  • cargo +1.98.0 fmt --all --check: clean
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: pass
  • cargo +1.98.0 test -p codexbar --lib huggingface: 26 passed
  • cargo +1.98.0 test -p codexbar: 2169 passed, 0 failed, 1 ignored
  • cargo +1.98.0 test -p codexbar-desktop-tauri: 461 passed, 1 failed: commands::tests::bootstrap_payload_exposes_every_provider_variant (79 vs 78) reads the machine's real settings; it is the known environment-dependent test tracked in Isolate bootstrap payload test from real settings #684/Make the bootstrap catalog test hermetic (#684) #711 and does not touch this change.

Affected areas

rust/src/providers/huggingface/ only (mod.rs, wallet.rs, new identity_cache.rs). No frontend, locale, tray, settings or dependency changes (sha2 is already a dependency).

UI proof

Not applicable (backend only).

Implemented by Codex gpt-6-luna (xhigh) via ACPX; reviewed and validated by Claude.

@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…ount

The shell forced the OAuth (API-only) source for any token account with an environment override, which skipped the prepaid wallet. A new Provider::token_account_preserves_auto_source hook lets Hugging Face keep Auto, matching upstream's base-source resolver; an explicit API source still stays API-only.
@Finesssee

Copy link
Copy Markdown
Collaborator Author

Fixes landed at 78d8932

Reviewer issue: desktop users with an active Hugging Face token account never got the prepaid wallet. Confirmed: the shell forced SourceMode::OAuth for any token account with an env override and no cookie domain, and the wallet loader requires Auto.

Change:

  • New Provider::token_account_preserves_auto_source hook (default false), used in commands/providers.rs::build_fetch_context. Hugging Face returns true, so a selected token account with usage source Auto stays Auto (upstream's default selectedAccountSourceModeResolver returns the base mode). An explicit API (OAuth) source, or a stale Web/CLI value, still maps to the API-only lane, so the wallet stays off there.
  • The CLI already kept Auto for token accounts, so CLI and desktop agree again.
  • Regression tests in commands/token_account_source_tests.rs: token account under Auto keeps Auto and the account key; explicit API stays API-only; stale web/cli falls back to API; no account follows the usage source; only Hugging Face opts in across all providers.

Commands run: cargo +1.98.0 fmt --all --check; cargo +1.98.0 clippy --workspace --all-targets -- -D warnings; cargo +1.98.0 test -p codexbar (2169 passed); cargo +1.98.0 test -p codexbar-desktop-tauri (466 passed, 1 known environment failure bootstrap_payload_exposes_every_provider_variant, 79 vs 78, which depends on real local settings, tracked in #684/#711). No frontend change.

@Finesssee

Copy link
Copy Markdown
Collaborator Author

Adversarial validation (Claude Opus 5.5) passed at 78d8932

Scope re-checked (round 2): GAP-11 (12 h token-keyed whoami identity cache), GAP-12 (403 billing-permission message), GAP-18 (no cookie access in API-only mode), plus the new Provider::token_account_preserves_auto_source hook used by build_fetch_context. Compared against upstream v0.70.0 huggingface.ts, HuggingFacePluginTests.swift, HuggingFaceWalletPluginTests.swift and the default selected-account source-mode resolver in ProviderRegistry.

Checks run on this head (detached worktree, gated build):

  • cargo +1.98.0 fmt --all --check: clean
  • cargo +1.98.0 clippy --workspace --all-targets -- -D warnings: pass
  • cargo +1.98.0 test -p codexbar --lib huggingface: 26 passed
  • cargo +1.98.0 test -p codexbar: 2169 passed, 0 failed, 1 ignored
  • cargo +1.98.0 test -p codexbar-desktop-tauri -- --skip bootstrap_payload_exposes_every_provider_variant: 466 passed, 0 failed (the skipped test reads the host's real settings; the 5 new token_account_source_tests pass)

No frontend, locale, dependency or UI change; no file crosses 1000 lines because of this PR.

Finesssee added a commit that referenced this pull request Oct 2, 2026
… billing-permission message, API-only without cookies
Finesssee added a commit that referenced this pull request Oct 2, 2026
…nt isolation folds into the Kimi auto seam and the #725 wallet rule)
@Finesssee

Copy link
Copy Markdown
Collaborator Author

Adversarial validation passed at 417e4fe

Scope: Hugging Face 12h identity cache, billing-permission message, API-only without cookies (#725, upstream 0.64.0), validated as merged into release/v0.70.0 (merge 417e4fe = merge of 78d8932 into 5ad2766).

Attacks (highest-risk semantics, from the merged tree):

  • 12h TTL is boundary-tested: IDENTITY_TTL = 12 * 60 * 60 s; is_fresh requires age >= zero && age < TTL (future timestamps rejected), and the tests pin the exact boundaries — fresh at +60 s and +1 s, expired at +12 h exactly and at -1 s stale insert, refetch at +13 h. A naive <= or a negative-age acceptance would fail these.
  • Token-keyed, capacity-bounded: entries are keyed by SHA-256 of the token (not the raw token — no secret in the map key), capped at 32 entries with the capacity test covering eviction.
  • API-only without cookies: fetch_matching_wallet_balance returns None when source_mode != Auto or the identity has no user_id, so API-only mode never reads cookies — and the Make the bootstrap catalog test hermetic (#684) #711-era follow-up (token_account_preserves_auto_source) is on the merged base, so an explicit token account doesn't force the API-only source.
  • Billing-permission message is actionable: classify_billing_status maps 403 to "The Hugging Face token lacks billing access. Use a classic read token or enable Billing read on a fine-grained token." — the audit's exact message — with 401/403/429 classified distinctly and the test asserting the message text, not just an error kind.

No defects found. READY for the un-draft rule.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant