Studio: fix 4 failing studio_unit_tests on main
Three of the failing tests had drifted from production:
1. test_health_response_reports_desktop_capability_fields stubbed
`routes` with a SimpleNamespace that omitted `inference_studio_router`,
so importing studio.backend.main raised ImportError. Add the missing
router stub.
2. test_local_recipe_token_preserves_desktop_marker and
test_local_recipe_token_keeps_web_marker_absent decoded the local
provider's api_key as a JWT, but _inject_local_providers now mints
a unified sk-unsloth-* internal API key (not a forwarded JWT), so
jwt.decode raised "Not enough segments". Renamed and rewrote both
tests to validate the API-key contract: starts with
storage.API_KEY_PREFIX and authenticates via get_current_subject as
the real admin user. The web vs desktop distinction is irrelevant
at this layer because the unified API-key path does not carry
session flags.
The fourth failure was a real production bug:
3. test_github_validate_skips_live_access_with_honest_note expected
github-seed validation to return valid=True per
_GITHUB_VALIDATE_NOTE ("GitHub access and rate limits are checked
when the run starts"). The validate route called
build_config_builder which lazy-imports the optional data_designer
module; when it is missing, the bare except blocked the recipe.
Catch ImportError specifically and treat it as a deferred check,
matching the documented intent.
Verified all 4 tests pass and the rest of studio/backend/tests still
pass (608 total, with the only remaining failures being environment
specific: 4 GPU-aware tests on a no-GPU host and 1 Anthropic-API
smoke test, both unrelated).
This commit is contained in:
parent
ff759ba7e4
commit
b0d33cff0e
2 changed files with 23 additions and 16 deletions
|
|
@ -151,6 +151,12 @@ def validate(payload: RecipePayload) -> ValidateResponse:
|
|||
return ValidateResponse(valid = False, errors = static_errors)
|
||||
try:
|
||||
build_config_builder(recipe)
|
||||
except ImportError:
|
||||
# data_designer is an optional runtime dep. Static validation already
|
||||
# passed; live access + full config validation are deferred to run
|
||||
# start (per _GITHUB_VALIDATE_NOTE), so a missing optional import
|
||||
# at validate time should not block the recipe.
|
||||
pass
|
||||
except Exception as exc:
|
||||
detail = str(exc).strip() or "Validation failed."
|
||||
return ValidateResponse(
|
||||
|
|
|
|||
|
|
@ -246,7 +246,10 @@ def test_desktop_session_uses_real_admin_identity_for_api_keys():
|
|||
assert [row["name"] for row in rows] == ["desktop"]
|
||||
|
||||
|
||||
def test_local_recipe_token_preserves_desktop_marker(loaded_local_model):
|
||||
def test_local_recipe_token_authenticates_as_admin_for_desktop_user(loaded_local_model):
|
||||
# _inject_local_providers mints an internal sk-unsloth-* API key (not a
|
||||
# forwarded JWT). The unified API-key path validates as the real admin
|
||||
# user regardless of whether the incoming session was desktop or web.
|
||||
from auth.authentication import create_access_token, get_current_subject
|
||||
|
||||
seed_user(must_change_password = True)
|
||||
|
|
@ -260,13 +263,7 @@ def test_local_recipe_token_preserves_desktop_marker(loaded_local_model):
|
|||
jobs_route._inject_local_providers(recipe, local_recipe_request(incoming_token))
|
||||
|
||||
local_token = recipe["model_providers"][0]["api_key"]
|
||||
payload = jwt.decode(
|
||||
local_token,
|
||||
storage.get_jwt_secret(storage.DEFAULT_ADMIN_USERNAME),
|
||||
algorithms = ["HS256"],
|
||||
)
|
||||
assert payload["sub"] == storage.DEFAULT_ADMIN_USERNAME
|
||||
assert payload["desktop"] is True
|
||||
assert local_token.startswith(storage.API_KEY_PREFIX)
|
||||
credentials = HTTPAuthorizationCredentials(
|
||||
scheme = "Bearer",
|
||||
credentials = local_token,
|
||||
|
|
@ -276,8 +273,10 @@ def test_local_recipe_token_preserves_desktop_marker(loaded_local_model):
|
|||
)
|
||||
|
||||
|
||||
def test_local_recipe_token_keeps_web_marker_absent(loaded_local_model):
|
||||
from auth.authentication import create_access_token
|
||||
def test_local_recipe_token_authenticates_as_admin_for_web_user(loaded_local_model):
|
||||
# Mirror of the desktop variant: API-key issuance is identical for web
|
||||
# and desktop incoming tokens; auth via get_current_subject works the same.
|
||||
from auth.authentication import create_access_token, get_current_subject
|
||||
|
||||
seed_user(must_change_password = False)
|
||||
jobs_route = data_recipe_jobs_module()
|
||||
|
|
@ -287,13 +286,14 @@ def test_local_recipe_token_keeps_web_marker_absent(loaded_local_model):
|
|||
jobs_route._inject_local_providers(recipe, local_recipe_request(incoming_token))
|
||||
|
||||
local_token = recipe["model_providers"][0]["api_key"]
|
||||
payload = jwt.decode(
|
||||
local_token,
|
||||
storage.get_jwt_secret(storage.DEFAULT_ADMIN_USERNAME),
|
||||
algorithms = ["HS256"],
|
||||
assert local_token.startswith(storage.API_KEY_PREFIX)
|
||||
credentials = HTTPAuthorizationCredentials(
|
||||
scheme = "Bearer",
|
||||
credentials = local_token,
|
||||
)
|
||||
assert (
|
||||
asyncio.run(get_current_subject(credentials)) == storage.DEFAULT_ADMIN_USERNAME
|
||||
)
|
||||
assert payload["sub"] == storage.DEFAULT_ADMIN_USERNAME
|
||||
assert "desktop" not in payload
|
||||
|
||||
|
||||
def test_desktop_login_rejects_invalid_secret():
|
||||
|
|
@ -381,6 +381,7 @@ def test_health_response_reports_desktop_capability_fields(monkeypatch):
|
|||
datasets_router = APIRouter(),
|
||||
export_router = APIRouter(),
|
||||
inference_router = APIRouter(),
|
||||
inference_studio_router = APIRouter(),
|
||||
models_router = APIRouter(),
|
||||
training_history_router = APIRouter(),
|
||||
training_router = APIRouter(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue