Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 Manage access requests approval / rejection via API #1535

Closed
Wauplin opened this issue Jun 30, 2023 · 7 comments
Closed

🚀 Manage access requests approval / rejection via API #1535

Wauplin opened this issue Jun 30, 2023 · 7 comments
Labels
enhancement New feature or request

Comments

@Wauplin
Copy link
Contributor

Wauplin commented Jun 30, 2023

Initially from @osanseviero on slack

Models can now be gated with a manual review process. Only users for which usage has been manually granted can access the repo. 5 endpoints exists to see list of pending/accepted/rejected + grant/ungrant access to the model (see screenshot).

At the moment there isn't much usage for this use case. Let's reassess if we see more demand.
We could also add an endpoint to set a repo as Gated (or Manual Approval-gated).

image__54_

Documentation for manual approval: https://huggingface.co/docs/hub/models-gated#manual-approval

@Wauplin Wauplin added the enhancement New feature or request label Jun 30, 2023
@Wauplin
Copy link
Contributor Author

Wauplin commented Jun 30, 2023

EDIT: use user (actual username on the Hub) instead of user_id (hex id in database). Much more user-friendly this way :) (see #1535 (comment))

As of now, I wrote a quick (untested) implementation if needed.
It would need to be reworked to be included in huggingface_hub (especially better method naming, add them to HfApi, maybe handle pagination, test them, document them).

from huggingface_hub.constants import ENDPOINT
from huggingface_hub.utils import get_session, build_hf_headers, hf_raise_for_status
from typing import Optional, Literal
from tqdm.contrib.concurrent import thread_map


def get_pending_requests(repo_id: str, *, token: Optional[str]) -> None:
    response = get_session().get(
        f"{ENDPOINT}/api/models/{repo_id}/user-access-request/pending", headers=build_hf_headers(token=token)
    )
    hf_raise_for_status(response)
    return response.json()


def get_accepted_requests(repo_id: str, *, token: Optional[str]) -> None:
    response = get_session().get(
        f"{ENDPOINT}/api/models/{repo_id}/user-access-request/accepted", headers=build_hf_headers(token=token)
    )
    hf_raise_for_status(response)
    return response.json()


def get_rejected_requests(repo_id: str, *, token: Optional[str]) -> None:
    response = get_session().get(
        f"{ENDPOINT}/api/models/{repo_id}/user-access-request/rejected", headers=build_hf_headers(token=token)
    )
    hf_raise_for_status(response)
    return response.json()


def handle_access(
    repo_id: str, user: str, status: Literal["accepted", "rejected", "pending"], *, token: Optional[str]
) -> None:
    response = get_session().post(
        f"{ENDPOINT}/api/models/{repo_id}/user-access-request/handle",
        headers=build_hf_headers(token=token),
        json={"user": user, "status": status},
    )
    hf_raise_for_status(response)
    return response.json()


def grant_access(repo_id: str, user: str, *, token: Optional[str]) -> None:
    response = get_session().post(
        f"{ENDPOINT}/api/models/{repo_id}/user-access-request/grant",
        headers=build_hf_headers(token=token),
        json={"user": user},
    )
    hf_raise_for_status(response)
    return response.json()


if __name__ == "__main__":
    repo_id = "username/my-cool-model"

    # Get listing
    pending_users = get_pending_requests(repo_id)
    accepted_users = get_accepted_requests(repo_id)
    rejected_users = get_rejected_requests(repo_id)

    # WARNING: user_id is not the username but the id returned by the listing endpoints above!

    # Grant access to a user
    grant_access(repo_id, "osanseviero")

    # Grant access to a list of users (multithreaded)
    users = ["Wauplin", "julien-c", "osanseviero"]
    thread_map(lambda user: grant_access(repo_id, user), users)

    # Reject access for a user
    handle_access(repo_id, "apolinario", "rejected")

@apolinario
Copy link
Contributor

Btw, requring the hex userId may be not ideal for giving user access (in handle_access) . It is not documented, but user with their HF username also works and I think could be preferred.

@osanseviero
Copy link
Contributor

user was not supported until Friday in https://github.com/huggingface/moon-landing/pull/6842 :) cc @SBrandeis

We now support user rather than the hexadecimal, so indeed let's go with that :)

@Wauplin
Copy link
Contributor Author

Wauplin commented Jul 3, 2023

Yep, thanks for the heads up. I've updated the snippet of code ⬆️

@julien-c
Copy link
Member

julien-c commented Jul 3, 2023

cool snippet @Wauplin, and yes i agree to wait to merge until we know if there's a lot of demand for this programattic feature

@Wauplin
Copy link
Contributor Author

Wauplin commented Dec 14, 2023

Opened a PR to officially add this: #1905 🙂

@Wauplin
Copy link
Contributor Author

Wauplin commented Mar 1, 2024

Closed by #1905.

@Wauplin Wauplin closed this as completed Mar 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants