What changed
- Kura’s Tuist auth hook now falls back to
/api/cache/access for project-scoped requests when OAuth introspection returns an active token but the returned cache grants do not authorize the requested project/action.
- Added Kura coverage for the stale-grants path: active introspection grants for a different project, followed by successful legacy project access fallback.
- Account-scoped requests remain strict and do not use the legacy project fallback.
Why
Older or stale tokens can miss a newly-created project in their embedded cache grants. Kura already intended to support that by falling back to Tuist’s legacy /api/cache/access endpoint for project-scoped requests. However, the hook only used that fallback when introspection returned active: false or when the introspection client was missing.
If introspection returned active: true with grants that still did not prove access to the requested project/action, Kura skipped the legacy fallback and denied the request. This breaks the compatibility path where the server can still authorize the project through /api/cache/access even though the token grants are stale or incomplete.
Root cause
Kura’s project-scoped legacy fallback was too narrow. It handled inactive introspection responses and missing introspection-client configuration, but not active introspection responses whose grants did not authorize the requested project/action.
Impact
Kura now honors the intended legacy project-access fallback when introspection grants are stale or incomplete for the requested project, while keeping account-scoped requests strict so the fallback cannot widen account-level access.
Validation
mise exec -- cargo test falls_back_to_legacy_cache_access_when_active_introspection_grants_do_not_cover_project from kura/
mise exec -- cargo test tuist_hook from kura/