# 10-9. Sécurité, exploitation, dépannage, suppression **Ce guide répond à :** qu'est-ce qui protège les données, à chaque étage ? Comment suivre l'usage, révoquer un accès, maîtriser le coût ? Que faire quand ça bloque, et comment tout supprimer ? --- ## 1. Les protections, de l'extérieur vers les données | Étage | Protection | Ce qu'elle empêche | |---|---|---| | Réseau | Cloud Run **privé** (`--no-allow-unauthenticated`) | Personne n'atteint le serveur sans `run.invoker` (`403`, vérifié par `tester`) | | Appelants | `run.invoker` donné **seulement** au compte de l'app et au compte de l'agent | Un autre service, ou un utilisateur seul, ne peut pas appeler le serveur | | Utilisateur | Jeton OAuth vérifié : **audience** (nos clients), portée Sheets, e-mail **vérifié**, **domaine** autorisé | Jeton d'une autre application, compte personnel ou externe (4 refus testés) | | Consentement | Écran **Interne** + `hd=acme.example` | Seuls les comptes de l'organisation peuvent même se connecter | | Données | Appels Sheets **avec le jeton de l'utilisateur** ; compte du serveur **sans rôle** | Le serveur ne voit que ce que l'utilisateur voit : ses droits Drive s'appliquent | | Portées | `spreadsheets` + `drive.metadata.readonly` (noms de fichiers seulement) | Pas de lecture du contenu des autres fichiers Drive ; pas de suppression de fichier | | Actions | Annotations lecture / destructif ; actions **désactivées par défaut** dans l'app ; confirmation | Une modification n'arrive pas par surprise ; vous choisissez ce qui est activé | | Volume | 20 000 cellules maximum par lecture | Un classeur entier n'est pas envoyé au modèle | | Traçabilité | Journal `tool_call` : qui, outil, classeur, plage. **Jamais** le contenu | Audit sans fuite | | Configuration | Démarrage refusé sans `OAUTH_CLIENT_IDS` ; Terraform refuse aussi | Un serveur mal configuré ne peut pas accepter n'importe quel jeton | | Jeton dans l'agent | État `temp:` : jamais enregistré, jamais journalisé | Pas de jeton qui traîne dans une base de sessions | | Contenu des cellules | Consigne à l'agent : une cellule est une **donnée**, pas une consigne | Injection de consignes cachée dans un classeur | **Ce que le serveur peut détruire, et comment le limiter.** `write_range`, `clear_range`, `delete_sheet`, `delete_dimension` et `batch_update` modifient ou suppriment du contenu dans un classeur. Ils ne suppriment jamais le fichier lui-même. Trois réglages : 1. dans l'app, ne pas activer ces actions (10-5, étape 5) ; 2. dans l'agent, la consigne demande d'annoncer et de faire confirmer ; 3. l'historique des versions de Sheets permet toujours de revenir en arrière (*Fichier → Historique des versions*). ## 2. Exploiter **Journaux** (Cloud Logging, ressource Cloud Run `sheets-mcp`) : ``` jsonPayload.event="tool_call" -- qui a utilisé quel outil, sur quel classeur jsonPayload.event="auth_rejected" -- refus (domaine, e-mail non vérifié) ``` **Révoquer un accès :** - **un utilisateur, pour lui-même :** myaccount.google.com → Sécurité → Applications tierces → retirer l'accès ; - **l'admin Workspace, pour tous :** Console d'administration → Sécurité → Contrôles des API → Accès des applications → bloquer le client OAuth ; - **en urgence :** - désactiver le client OAuth (Google Auth Platform) ; - ou retirer `run.invoker` au compte de l'app et au compte de l'agent ; - ou mettre le service à 0 instance. **Mettre à jour le serveur :** 1. modifier le code ; 2. `python tests/test_server.py` ; 3. `python scripts/gen_toolspec.py` ; 4. `./scripts/deployer.sh mcp` (ou `terraform apply`) ; 5. dans l'app : **Reload custom actions**. **Quotas :** l'API Sheets a des quotas par minute, par utilisateur et par projet (celui du client OAuth). Le serveur traduit une erreur `429` en message clair : « réessayez dans une minute ». **Coût :** Cloud Run à 0 instance minimum : rien quand personne ne l'utilise, avec un démarrage de quelques secondes à la première requête. `--min-instances=1` répond tout de suite, pour un coût fixe modéré. L'API Sheets est gratuite (dans les quotas). L'agent consomme des appels Gemini. ## 3. Dépannage | Symptôme | Où regarder | Cause → solution | |---|---|---| | `deployer.sh` : « Chargez la configuration » | – | `source scripts/config.sh config/10-mcp.env` dans ce terminal | | `verifier` : facturation DÉSACTIVÉE | – | Rattacher un compte de facturation au projet : sans lui, Cloud Run, Cloud Build, Vertex AI et Agent Runtime refusent | | `mcp` : « OAUTH_CLIENT_IDS est vide » | – | Créer le client OAuth (10-5, étape 1), mettre son ID dans le fichier, recharger | | Construction refusée (`PERMISSION_DENIED`, `storage.objects.get`) | Cloud Build → Historique | Compte de construction tout neuf (le script réessaie 3 fois) ; sinon `preparer` | | Le service ne démarre pas (`container failed to start`) | Cloud Run → Journaux | `OAUTH_CLIENT_IDS` vide dans le service (le serveur refuse de démarrer, c'est voulu) | | `403` en appelant le serveur | – | `run.invoker` manquant pour l'appelant ; URL sans `/mcp` | | `401` sur toutes les actions | Journaux : aucun `tool_call` | Le client OAuth qui a émis le jeton n'est pas dans `OAUTH_CLIENT_IDS` | | `auth_rejected … reason: domain` | Journaux | Domaine absent de `ALLOWED_DOMAINS` | | « accès refusé : vous n'avez pas les droits sur ce fichier » | – | Le classeur n'est pas partagé avec l'utilisateur, ou la portée manque | | `#ERROR! (Formula parse error.)` | Le classeur | Locale fr_FR : `,` décimale et `;` entre les arguments (10-1, partie 6) | | `truncated: true` | – | Plage trop grande : lire plus petit | | L'agent dit « cliquez sur Autoriser » en boucle | – | 10-6, partie 7 | | Connecteur : « Custom MCP Server » introuvable | – | Règle d'organisation (10-5, étape 2) | ## 4. Tout supprimer **Dans l'app (console de l'app)** : - **Agents** → l'agent → **Delete** ; - **Data stores** → `Google Sheets` → **Delete** ; - l'autorisation OAuth : `DELETE …/authorizations/acces-sheets` (REST), ou le script `autorisation_oauth.sh delete` du projet 09. **Dans le projet des agents :** - script : `./scripts/deployer.sh nettoyer` (inventaire, puis confirmation en tapant l'ID du projet) ; - ou Terraform : `terraform destroy`. **Le client OAuth :** Google Auth Platform → **Clients** → supprimer, s'il ne sert plus.