feat(browser): auto-commit con 178 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
---
|
||||
name: gsc_auth
|
||||
kind: function
|
||||
lang: py
|
||||
domain: infra
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def gsc_auth(credentials_path: str = \"\", subject: str = \"\") -> object"
|
||||
description: "Autentica contra la Google Search Console API v1 (searchconsole/webmasters) con una cuenta de servicio JSON. Lee el JSON de credentials_path o, si esta vacio, de la env var GSC_SA_JSON; lanza ValueError claro si falta. Usa service_account.Credentials.from_service_account_file con scope https://www.googleapis.com/auth/webmasters.readonly (solo lectura). subject opcional aplica with_subject(subject) para domain-wide delegation (normalmente vacio en GSC). Construye y retorna el objeto service de googleapiclient.discovery.build('searchconsole','v1', cache_discovery=False) listo para consumir por pull_gsc_search_analytics. Requiere google-api-python-client y google-auth."
|
||||
tags: [seo, gsc, infra, google, search-console, auth, service-account]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [os, google.oauth2.service_account, googleapiclient.discovery]
|
||||
params:
|
||||
- name: credentials_path
|
||||
desc: "ruta al JSON de la service account de GCP. Si esta vacio, se lee de la env var GSC_SA_JSON. Si tampoco existe, se lanza ValueError. El JSON es un secreto: resolver desde pass o una ruta fuera del repo, nunca commitear."
|
||||
- name: subject
|
||||
desc: "opcional. Email para domain-wide delegation (impersonation) via with_subject. Normalmente vacio en Search Console, donde la SA se anade directamente como usuario en GSC sin requerir delegation."
|
||||
output: "object. El service de googleapiclient (googleapiclient.discovery.Resource) para la API 'searchconsole' v1, autenticado con scope webmasters.readonly y cache_discovery=False. Se pasa a funciones consumidoras como pull_gsc_search_analytics."
|
||||
tested: true
|
||||
tests:
|
||||
- "test_build_se_llama_con_searchconsole_v1_y_cache_off"
|
||||
- "test_credentials_se_cargan_con_scope_readonly"
|
||||
- "test_fallback_a_env_var_gsc_sa_json"
|
||||
- "test_subject_aplica_with_subject"
|
||||
- "test_error_cuando_falta_credential"
|
||||
test_file_path: "python/functions/infra/gsc_auth_test.py"
|
||||
file_path: "python/functions/infra/gsc_auth.py"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys
|
||||
sys.path.insert(0, "python/functions")
|
||||
from infra import gsc_auth
|
||||
|
||||
# Opcion A: ruta explicita al JSON de la service account
|
||||
service = gsc_auth(credentials_path="/home/enmanuel/secrets/gsc-sa.json")
|
||||
|
||||
# Opcion B: leer la ruta de la env var GSC_SA_JSON
|
||||
# export GSC_SA_JSON=/home/enmanuel/secrets/gsc-sa.json
|
||||
service = gsc_auth()
|
||||
|
||||
# Verificar la autenticacion listando los sitios verificados:
|
||||
sites = service.sites().list().execute()
|
||||
print([s["siteUrl"] for s in sites.get("siteEntry", [])])
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Antes de `pull_gsc_search_analytics` (o cualquier llamada a la Search Console
|
||||
API): la usas para obtener el objeto `service` autenticado una sola vez y
|
||||
reutilizarlo en las consultas posteriores (Search Analytics, sitemaps, sites).
|
||||
Es el punto de entrada del capability group `seo`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Impura**: lee un JSON del disco y construye un cliente HTTP de Google. No
|
||||
es determinista ni componible en el nucleo puro.
|
||||
- **Dar de alta la SA en Search Console**: el email de la service account debe
|
||||
anadirse manualmente como usuario en Search Console > Settings > Users and
|
||||
permissions (rol Restricted/Full). Sin esto la auth funciona pero las
|
||||
consultas devuelven 403 / sitios vacios.
|
||||
- **Habilitar la API**: la "Search Console API" debe estar habilitada en el
|
||||
proyecto GCP de la service account (consola de APIs & Services). Si no, el
|
||||
primer `.execute()` falla con un error de API deshabilitada.
|
||||
- **El JSON de la SA es un secreto**: no commitear nunca. Guardarlo en `pass`
|
||||
o en una ruta fuera del repo y pasar la ruta por `credentials_path` o la env
|
||||
var `GSC_SA_JSON`.
|
||||
- **`subject` casi siempre vacio**: domain-wide delegation solo aplica si
|
||||
impersonas a un usuario de un dominio Workspace; en GSC lo normal es anadir
|
||||
la SA directamente como usuario y dejar `subject=""`.
|
||||
- **Dependencias**: requiere `google-api-python-client` y `google-auth` en el
|
||||
venv. Ya estan en `python/pyproject.toml`.
|
||||
|
||||
## Capability growth log
|
||||
|
||||
(sin cambios — v1.0.0 inicial)
|
||||
Reference in New Issue
Block a user