"""Autenticacion contra la Google Search Console API con una cuenta de servicio.""" import os # Scope de solo lectura: suficiente para Search Analytics y listar sitios. _SCOPE_READONLY = "https://www.googleapis.com/auth/webmasters.readonly" def gsc_auth(credentials_path: str = "", subject: str = "") -> object: """Autentica contra la Google Search Console API v1 con una service account. Construye unas credenciales a partir del JSON de una cuenta de servicio y devuelve el objeto ``service`` de ``googleapiclient`` listo para consumir (lo usa, por ejemplo, ``pull_gsc_search_analytics``). Args: credentials_path: ruta al JSON de la service account. Si esta vacio, se lee de la variable de entorno ``GSC_SA_JSON``. Si tampoco existe, se lanza ``ValueError`` indicando que falta el credential. subject: email para domain-wide delegation (impersonation). Normalmente vacio en Search Console (la SA se anade directamente como usuario en GSC). Si se pasa, se aplica ``.with_subject(subject)``. Returns: El objeto ``service`` (``googleapiclient.discovery.Resource``) para la API ``searchconsole`` v1, autenticado con scope ``webmasters.readonly``. Raises: ValueError: si no se proporciona ``credentials_path`` ni la env var ``GSC_SA_JSON``. """ # Imports diferidos: mantienen la importacion del modulo barata y la # dependencia externa aislada al momento de uso real. from google.oauth2 import service_account from googleapiclient.discovery import build path = credentials_path or os.environ.get("GSC_SA_JSON", "") if not path: raise ValueError( "gsc_auth: falta el credential de la service account. " "Pasa credentials_path o define la env var GSC_SA_JSON con la " "ruta al JSON de la cuenta de servicio." ) creds = service_account.Credentials.from_service_account_file( path, scopes=[_SCOPE_READONLY] ) if subject: creds = creds.with_subject(subject) return build( "searchconsole", "v1", credentials=creds, cache_discovery=False, )