88from typing import Any
99
1010import gradio as gr
11+ import huggingface_hub as hf
1112import numpy as np
1213import pandas as pd
1314
15+ HfApi = hf .HfApi ()
16+
1417try :
1518 import trackio .utils as utils
1619 from trackio .file_storage import FileStorage
@@ -262,13 +265,63 @@ def toggle_timer(cb_value):
262265 return gr .Timer (active = False )
263266
264267
268+ def check_auth (hf_token : str | None ) -> None :
269+ if os .getenv ("SYSTEM" ) == "spaces" : # if we are running in Spaces
270+ # check auth token passed in
271+ if hf_token is None :
272+ raise PermissionError (
273+ "Expected a HF_TOKEN to be provided when logging to a Space"
274+ )
275+ who = HfApi .whoami (hf_token )
276+ access_token = who ["auth" ]["accessToken" ]
277+ owner_name = os .getenv ("SPACE_AUTHOR_NAME" )
278+ repo_name = os .getenv ("SPACE_REPO_NAME" )
279+ # make sure the token user is either the author of the space,
280+ # or is a member of an org that is the author.
281+ orgs = [o ["name" ] for o in who ["orgs" ]]
282+ if owner_name != who ["name" ] and owner_name not in orgs :
283+ raise PermissionError (
284+ "Expected the provided hf_token to be the user owner of the space, or be a member of the org owner of the space"
285+ )
286+ # reject fine-grained tokens without specific repo access
287+ if access_token ["role" ] == "fineGrained" :
288+ matched = False
289+ for item in access_token ["fineGrained" ]["scoped" ]:
290+ if (
291+ item ["entity" ]["type" ] == "space"
292+ and item ["entity" ]["name" ] == f"{ owner_name } /{ repo_name } "
293+ and "repo.write" in item ["permissions" ]
294+ ):
295+ matched = True
296+ break
297+ if (
298+ (
299+ item ["entity" ]["type" ] == "user"
300+ or item ["entity" ]["type" ] == "org"
301+ )
302+ and item ["entity" ]["name" ] == owner_name
303+ and "repo.write" in item ["permissions" ]
304+ ):
305+ matched = True
306+ break
307+ if not matched :
308+ raise PermissionError (
309+ "Expected the provided hf_token with fine grained permissions to provide write access to the space"
310+ )
311+ # reject read-only tokens
312+ elif access_token ["role" ] != "write" :
313+ raise PermissionError (
314+ "Expected the provided hf_token to provide write permissions"
315+ )
316+
317+
265318def upload_db_to_space (
266319 project : str , uploaded_db : gr .FileData , hf_token : str | None
267320) -> None :
268321 """
269322 Uploads the database of a local Trackio project to a Hugging Face Space.
270323 """
271- fns . check_auth (hf_token )
324+ check_auth (hf_token )
272325 db_project_path = SQLiteStorage .get_project_db_path (project )
273326 if os .path .exists (db_project_path ):
274327 raise gr .Error (
@@ -282,7 +335,7 @@ def bulk_upload_media(uploads: list[UploadEntry], hf_token: str | None) -> None:
282335 """
283336 Uploads media files to a Trackio dashboard. Each entry in the list is a tuple of the project, run, and media file to be uploaded.
284337 """
285- fns . check_auth (hf_token )
338+ check_auth (hf_token )
286339 for upload in uploads :
287340 media_path = FileStorage .init_project_media_path (
288341 upload ["project" ], upload ["run" ], upload ["step" ]
@@ -302,7 +355,7 @@ def log(
302355 is kept for backwards compatibility for users who are connecting to a newer version of
303356 a Trackio Spaces dashboard with an older version of Trackio installed locally.
304357 """
305- fns . check_auth (hf_token )
358+ check_auth (hf_token )
306359 SQLiteStorage .log (project = project , run = run , metrics = metrics , step = step )
307360
308361
@@ -313,7 +366,7 @@ def bulk_log(
313366 """
314367 Logs a list of metrics to a Trackio dashboard. Each entry in the list is a dictionary of the project, run, a dictionary of metrics, and optionally, a step and config.
315368 """
316- fns . check_auth (hf_token )
369+ check_auth (hf_token )
317370
318371 logs_by_run = {}
319372 for log_entry in logs :
0 commit comments