Skip to content

feat(publish): réglage « publication autonome » par projet (admin, désactivé par défaut) - #302

Merged
bobdivx merged 1 commit into
mainfrom
feat/autonomous-publish-per-project
Nov 2, 2026
Merged

bobdivx merged 1 commit into
mainfrom
feat/autonomous-publish-per-project

Conversation

@bobdivx

@bobdivx bobdivx commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Pourquoi

Mathieu veut que l'agent popcornn puisse mettre en ligne ses nouvelles versions tout seul, sans lever le verrou publish_approval_required pour tout le monde.

Ce que fait le réglage « Publication autonome »

  • Par projet, un seul interrupteur dans l'onglet Git du projet. Désactivé par défaut : aucun projet ne change de comportement à la mise à jour.
  • Activé : trigger_deploy (agent DevForge et appels MCP externes) passe sans l'accord de 15 min, y compris en exécution automatique (réveil, routine). La branche configurée du projet est déployée.
  • Reste verrouillé même activé : sync_workdir_to_github, publish_to_github, create_github_fix, create_github_repo, upsert_env_var, cancel_deployment et les écritures GitHub par MCP.
  • Qui peut le changer : un instance_admin, depuis une session de l'interface uniquement. Un jeton d'API, OAuth ou MCP reçoit un 403, donc un agent ne peut pas s'ouvrir le verrou lui-même.
  • Journal (page Reçus) :
    • chaque changement du réglage → reçu autonomous_publish_setting (qui, quand, activé ou désactivé) ;
    • chaque mise en ligne autonome → reçu autonomous_publish (source agent, « activée par X »), lié au déploiement et réconcilié avec son issue finale. Une ligne en tête des logs du déploiement le signale aussi.
  • Aucun réglage global. Un accord de 15 min en cours reste prioritaire, avec le comportement actuel.

Technique

  • Table project_autonomous_publish (project_uuid PK, enabled_by, enabled_by_label, enabled_at). Pas de ligne = désactivé, et une erreur de lecture vaut aussi « désactivé ».
  • guard::deploy_gate renvoie Grant, Autonomous ou Locked. Il est utilisé par trigger_deploy côté serveur. AUTONOMOUS_TOOLS = ["trigger_deploy"].
  • PublishGate::autonomous (false par défaut) est utilisé dans la boucle agent.
  • API :
    • GET /api/v1/projects/{uuid}/autonomous-publish → {enabled, enabled_by_label, enabled_at, can_edit, covers}
    • PUT avec {enabled} (admin + session UI)

Tests

  • Rust (agent) :
    • le réglage est désactivé par défaut et propre à chaque projet ;
    • l'ordre de priorité accord → réglage, avec retour au réglage quand l'accord a expiré ;
    • seul trigger_deploy est couvert ;
    • dans la boucle, activé : seul le déploiement passe, y compris en exécution automatique ; désactivé : le verrou tient.
  • Rust (serveur) :
    • le reçu de mise en ligne autonome est lié au déploiement puis réconcilié en done ;
    • le changement du réglage laisse un reçu ;
    • admin + session obligatoires ;
    • un jeton d'API, une session expirée ou une requête sans en-tête ne passent pas pour une session UI.
  • Web (vitest) :
    • interrupteur désactivé par défaut, activation par un admin ;
    • interrupteur grisé sans droits admin ;
    • date affichée à l'heure de Paris.

⚠️ Ne pas fusionner ni déployer sans l'accord de Mathieu. Ensuite : release, mise à jour de la prod, puis activation par Mathieu (dans l'UI) pour popcorn-server et popcorn-web uniquement.

…sactivé par défaut)

Un admin de l'instance peut, depuis l'interface, autoriser l'agent à mettre
un projet en ligne (trigger_deploy) sans l'accord de 15 min. Désactivé par
défaut, réglé projet par projet, jamais global. Pousser sur GitHub, créer un
dépôt, modifier les variables de prod ou annuler un déploiement restent
verrouillés. Chaque mise en ligne autonome et chaque changement du réglage
laissent un reçu (qui, quand, résultat).
@bobdivx
bobdivx merged commit e111556 into main Nov 2, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant