Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help


id: ADR-018 title: La sécurité à l’exécution et la provenance reposent sur des frontières de décision détenues par le runtime date: 2026-08-17 status: proposé relates-to:

  • https://github.com/zeroclaw-labs/zeroclaw/issues/7142
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6971
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6954
  • https://github.com/zeroclaw-labs/zeroclaw/issues/7432
  • https://github.com/zeroclaw-labs/zeroclaw/issues/7141
  • https://github.com/zeroclaw-labs/zeroclaw/issues/7155
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6996
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6909
  • https://github.com/zeroclaw-labs/zeroclaw/issues/3767
  • https://github.com/zeroclaw-labs/zeroclaw/issues/6105
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8583
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8289
  • https://github.com/zeroclaw-labs/zeroclaw/issues/8290
  • https://github.com/zeroclaw-labs/zeroclaw/pull/10425
  • docs/book/src/architecture/request-lifecycle.md
  • docs/book/src/architecture/background-work-lifecycle.md
  • docs/book/src/architecture/tool-execution-lifecycle.md
  • docs/book/src/security/model.md
  • crates/zeroclaw-api/src/ingress.rs
  • crates/zeroclaw-runtime/src/agent/turn/mod.rs
  • crates/zeroclaw-runtime/src/security/ingress.rs
  • crates/zeroclaw-runtime/src/security/audit.rs
  • crates/zeroclaw-runtime/src/approval/mod.rs
  • crates/zeroclaw-runtime/src/cron/scheduler.rs
  • crates/zeroclaw-runtime/src/tools/send_message_to_peer.rs
  • crates/zeroclaw-runtime/src/tools/spawn_subagent.rs

ADR-018 : Sécurité d’exécution et provenance : utiliser des frontières de décision détenues par le runtime

Contexte

ZeroClaw possède plusieurs chemins sensibles en matière de sécurité qui doivent tous apporter la même réponse à trois questions : qui ou quoi a déclenché ce travail, quelle politique l’a autorisé, et quelle preuve atteste que la frontière a été appliquée avant que l’effet ne se produise. Les appels d’outils, les commandes shell, les mutations gateway et RPC, les tâches planifiées, les étapes SOP, les messages de pilotage et les dispatches vers d’autres agents ont historiquement répondu à ces questions à des endroits différents.

Cette séparation crée deux modes de défaillance. Un nouveau chemin d’action peut oublier une étape, comme l’approbation, l’apposition de la provenance, la validation finale de la cible ou les preuves d’audit. Un nouveau point d’extension peut aussi devenir trop puissant : s’il peut décider de la politique, supprimer les preuves canoniques et gérer la réponse aux incidents à travers un seul fournisseur remplaçable.

Trois RFC acceptées décrivent l’architecture qui corrige ce problème à la frontière d’exécution :

  • #7142 accepte un pipeline de décision de sécurité géré par le runtime pour les actions protégées. Ce pipeline combine la politique intégrée, les autorisations de principal canoniques, les exigences d’approbation, les contraintes de sandbox, les superpositions restrictives, les empreintes d’action, les permis d’exécution à usage unique du runtime, les événements d’audit canoniques et les enregistrements de résultats.
  • #6971 accepte l’autorité de surface des identifiants, le rapport de posture de sécurité et un unique chemin d’admission de modèle géré par le runtime. Les champs de configuration de type identifiant exigent des classifications de traitement explicites, les valeurs protégées restent absentes des chemins de sauvegarde et de lecture des propriétés, et la carte des limites d’identifiants du runtime identifie les endroits où des identifiants en clair peuvent circuler. Chaque tour destiné au modèle et chaque injection de pilotage reçoit une enveloppe d’entrée de confiance avant que le modèle ne la voie, tandis que l’authentification au niveau de la couche de transport et les contrôles d’abus restent en dehors de cette couche d’admission de modèle partagée.
  • #6954 accepte une provenance détenue par le runtime pour les tours initiés en interne. Les tâches cron, daemon, SOP, sous-agent et agent pair doivent porter des principaux internes, une liaison de conversation, une provenance de réponse, un comportement explicite en cas de contexte manquant, et des résultats distincts pour l’exécution, la livraison et la persistance.

Ces décisions sont connexes, sans pour autant remplacer la décision relative au principal canonique dans #7141, la décision relative à la confirmation des commandes et outils dans #7155, la décision relative au bac à sable du système de fichiers dans #6996, ni la validation des cibles propres aux consommateurs, comme dans #6909.

Le codebase actuel contient des bases importantes, mais pas la cible complète. IngressContext, TurnOrigin et IngressDecision existent ; le moteur de tours appelle la politique d’entrée à l’entrée de boucle et lors du drainage de la steering ; la politique par défaut renvoie Loop ; AuditLogger est un échafaudage de chaîne de hachage réutilisable ; et les bases du principal canonique ont commencé. La tranche principal interne et résultat séparé est encore en cours de revue dans #10425. Cette ADR décrit l’architecture cible et reste à l’état proposé tant que les portes ci-dessous ne sont pas franchies.

Décision

Conserver le runtime comme autorité de sécurité obligatoire

Les actions protégées passent par un seul pipeline de décision de sécurité détenu par le runtime, avant toute exécution ou modification. Ce pipeline construit une requête typée à partir du contexte de confiance du runtime, résout les octrois de la politique intégrée et ceux du principal canonique, applique les contraintes d’absence d’élévation de privilèges et de sandbox, compose des superpositions restrictives, recueille une approbation de confiance lorsqu’elle est requise, revalide la fraîcheur immédiatement avant l’effet, crée des preuves d’audit canoniques, émet un permis d’exécution unique pour le runtime, puis consomme ce permis à la frontière d’exécution qu’il détient.

Le permis constitue le relais entre la décision et son effet. Il est lié à l’action normalisée, au principal, aux générations de politique, à l’époque d’exécution, à l’identité de la cible, à l’expiration de l’approbation et au schéma d’empreinte. Il ne peut pas être sérialisé, reconstruit à partir des arguments, dupliqué pour une action sœur, ni consommé plus d’une fois.

Le travail sensible en matière de sécurité est refusé lorsque le runtime ne peut pas le classer. Une nouvelle frontière protégée doit être enregistrée dans l’inventaire des actions ou dans une structure mécaniquement équivalente qui indique le propriétaire, le constructeur de requête, la frontière d’exécution, les couches de politique obligatoires et la classification d’audit.

Les extensions peuvent restreindre la politique, sans remplacer le socle minimal.

Les overlays restrictifs peuvent refuser une action, restreindre ses ressources ou exiger une approbation plus forte ou plus récente. Ils ne peuvent pas transformer un refus en autorisation, élargir les autorisations accordées aux principaux, affaiblir les limites du sandbox ou du profil de risque, se sélectionner eux-mêmes à partir de données de requête non fiables, supprimer les événements d’audit canoniques, ni marquer la réponse de base aux incidents comme terminée.

Les puits d’audit optionnels et les répondeurs sont des points d’extension distincts. Ils peuvent recevoir des projections expurgées ou ajouter des comportements de confinement et de notification, mais ils ne peuvent pas supprimer, réécrire, retarder ni remplacer l’événement canonique créé à l’exécution ni les hooks de base de l’exécution.

Les futures API publiques de plugins, WIT, de politique distante, de bibliothèques dynamiques ou de réponse aux incidents nécessitent chacune leur propre revue d’implémentation et de confiance. Cet ADR acte les frontières d’autorité, et non une ABI de fournisseur de sécurité tiers spéculative.

Préservez la confidentialité des surfaces d’identifiants en les classant et en les protégeant.

Les champs de configuration de type identifiant doivent avoir des classifications de traitement explicites, telles que secret chiffré, référence de chemin uniquement, valeur publique, magasin d’authentification externe, chemin d’environnement de compatibilité ou nécessite un suivi. Un nouveau champ de type identifiant ne peut pas intégrer le schéma sans un test de classification, un audit ou un mécanisme équivalent de type cliquet.

Les valeurs d’identifiants protégées doivent rester à l’écart des chemins de sauvegarde et de relecture des propriétés. La couche de classification indique comment les valeurs sont stockées ou exposées ; elle ne décide pas à elle seule de tous les composants d’exécution susceptibles de recevoir du texte en clair.

Une carte d’frontières des identifiants à l’exécution, distincte, indique où le texte en clair peut circuler entre les clients de fournisseurs et de canaux, les outils, les serveurs MCP, les travaux délégués, les wrappers CLI, les gestionnaires de passerelle, les journaux, les reçus, les événements et les chemins d’erreur. Cet ADR enregistre cette carte comme une étape obligatoire de mise en œuvre et autorise un renforcement ciblé piloté par celle-ci, mais il n’accepte ni un courtier d’identifiants complet ni un nouveau profil d’isolation par défaut.

Utiliser un seul chemin d’admission des modèles pour le contenu entrant

Chaque tour destiné au modèle passe par la politique d’entrée partagée avant l’exécution du modèle. Chaque injection de pilotage reçoit sa propre enveloppe d’entrée de confiance et est évaluée sur cette base, au lieu d’hériter des informations obsolètes sur l’expéditeur, le message, le transport ou la confiance provenant du tour d’origine.

La politique d’entrée produit Loop, Annotate, Gate ou Drop. Le comportement par défaut Loop préserve le comportement actuel et n’alloue aucun travail SOP géré. Annotate présente le contenu comme des données non fiables avant de poursuivre. Gate transmet le tour à un chemin de décision humain ou SOP géré. Drop refuse le tour et consigne la raison.

Les contrôles de la couche transport restent obligatoires et distincts. L’appairage des canaux, les listes d’autorisation des expéditeurs, les vérifications de signature, la validation des charges utiles, la limitation de débit, le filtrage propre à chaque protocole et les contrôles contre l’abus de ressources s’exécutent avant la couche commune d’admission au modèle. La couche commune décide si le contenu normalisé peut entrer dans le modèle ; elle n’authentifie pas le transport.

Avant que la politique configurable non-Loop ne devienne atteignable, les dispositions non-Loop non implémentées doivent échouer en mode sécurisé. Une branche Gate qui retombe silencieusement sur Loop n’est pas compatible avec cette décision une fois que la configuration peut sélectionner Gate.

Horodater la provenance à partir des faits d’exécution

La provenance est apposée par le code d’entrée de confiance du runtime, jamais par le contenu des messages ni par les arguments des outils. L’origine et la confiance sont deux faits distincts. Un travail interne, planifié, délégué ou relayé peut dériver de contenu externe et ne devient pas fiable du simple fait que l’appelant immédiat est interne.

Les principaux canoniques issus de #7141 fournissent l’identité authentifiée de l’acteur et les autorisations lorsqu’un acteur externe ou authentifié existe. Les principaux internes issus de #6954 identifient les initiateurs gérés par le runtime, comme les tâches cron, les tâches du démon, les étapes SOP, la distribution vers des agents pairs et les sous-tours imbriqués. Ces principaux internes sont des faits de provenance, et non des pairs externes : ils n’apparaissent jamais dans les groupes de pairs ni dans les tables d’autorisations comme s’il s’agissait d’utilisateurs du transport.

Les sous-tours conservent la provenance du parent ou enregistrent une chaîne parent, afin que le travail délégué ne perde pas les faits d’identité et de confiance qui l’ont déclenché. Les tours issus d’une SOP et du démon doivent utiliser des noms qui distinguent leurs sources de tâches concrètes dans les traces et les enregistrements d’exécution.

Lier le travail interne aux conversations sans transférer l’autorité

Un tour initié en interne peut porter une seule liaison de conversation interne au runtime. La liaison indique d’où l’historique doit être chargé et où le tour terminé doit être ajouté, sous réserve des règles normales de troncature et de persistance. Cron session_target = "main" lie la session interactive principale de l’agent ; isolated ne porte délibérément aucune liaison.

Le binding n’est ni une livraison ni un rappel de mémoire. Le binding détermine quelle conversation possède le contexte et l’ajout. La livraison détermine où l’utilisateur voit une annonce ou une réponse. Le rappel de mémoire reste contrôlé par la politique d’injection de la mémoire.

Les réponses entre agents homologues utilisent une provenance de réponse opaque, et non une session partagée. Le tour de l’expéditeur capture un identifiant de corrélation, l’identité de l’expéditeur et la liaison de sa conversation avant l’envoi. Le destinataire s’exécute en tant qu’agent distinct et ne peut ni lire ni déréférencer le handle de session de l’expéditeur. À la fin de son exécution, le runtime ajoute ou remet le texte final du destinataire le long de cette provenance.

La provenance des réponses pair V1 est locale au processus. Un tour complet du destinataire dans le processus actif doit soit livrer selon la provenance, soit enregistrer un échec de livraison, mais les envois degrade non liés en cours peuvent être perdus en cas de plantage. Une ligne d’envoi durable ou une file d’attente durable fera l’objet d’un suivi distinct et ne fait pas partie de cette décision V1.

Le contexte manquant est explicite. isolated signifie qu’aucune liaison n’est attendue, require rejette l’envoi lorsque la provenance de la réponse requise ne peut pas être établie, et degrade s’exécute sans la liaison tout en enregistrant la dégradation. Le destinataire ou le contenu du message ne peut pas affaiblir require en degrade.

Garder les résultats et les éléments de preuve de statut séparés

Exécution, livraison, persistance et durabilité de l’audit sont des résultats distincts. Un statut de compatibilité peut les résumer, mais il doit être dérivé des axes indépendants plutôt qu’être écrit comme une source de vérité concurrente.

Les rapports sur la posture de sécurité distinguent l’intention configurée, la capacité résolue ou sondée, et l’application vérifiée à l’exécution. Les termes tels que active et enforced sont réservés aux preuves liées à l’instance d’exécution qui a effectivement appliqué la frontière. Les projections optionnelles, les journaux, les événements d’observateur et les reçus peuvent exposer des preuves utiles, mais ils ne deviennent pas une autre autorité de sécurité.

Lorsque le puits d’audit canonique et durable est activé, l’événement de pré-exécution est validé avant la mutation protégée. Si cette validation échoue, la mutation est refusée et l’état de sécurité indique un état dégradé ou indisponible. Un échec d’écriture du résultat après un effet enregistre un état d’audit explicitement inconnu ou dégradé, car une action déjà exécutée ne peut pas être annulée par la persistance de l’audit.

Déployez par tranches et gardez chaque étape réversible

Implementation suit le tracker de routage dans #7432 ainsi que les issues et PR d’implémentation ciblées liées depuis les RFC sources. Le pipeline de sécurité à l’exécution, le puits d’audit canonique, la classification des surfaces d’identifiants, la carte des frontières d’identifiants à l’exécution, l’estampillage à l’entrée, la politique non-Loop, l’enveloppe de principal interne, la liaison de conversation, la provenance des réponses de pairs et le suivi de la dispatch durable doivent être livrés sous forme de tranches indépendamment relisibles.

Aucune PR ne devrait tenter de faire passer simultanément chaque action, chaque transport, chaque puits d’audit et chaque consommateur de tours internes par la cible complète. Chaque tranche doit préserver le comportement par défaut existant, sauf si cette tranche assume explicitement un changement de compatibilité.

Critères d’acceptation

Cet ADR reste proposé jusqu’à ce que toutes ces conditions soient remplies :

  • the runtime action pipeline has a typed request and decision vocabulary, an action inventory or equivalent ratchet for protected boundaries, a single-use unforgeable permit, generation and runtime-epoch freshness checks, and final target revalidation at the owned execution or mutation boundary;

  • Les chemins d’outils directs, imbriqués, planifiés, délégués, SOP, gateway, RPC et sensibles en matière de sécurité ne peuvent pas contourner la frontière du pipeline enregistré, et les actions protégées inconnues ou non classées échouent en mode fermé.

  • la politique intégrée, les autorisations accordées aux principaux #7141, la règle de non-escalade, la provenance des approbations #7155, les contraintes du bac à sable #6996 et la revalidation propre à chaque consommateur, telle que #6909, demeurent des couches obligatoires, hors du contrôle des superpositions restrictives;

  • credential-shaped config fields have explicit handling classifications, with a schema audit, test, or equivalent ratchet that fails new unclassified fields;

  • protected credential values remain absent from save and property-readback paths, with non-exposure coverage where applicable;

    Wait, that’s the source text unchanged. Translating:

    les valeurs d’identifiants protégées restent absentes des chemins de sauvegarde et de relecture des propriétés, avec une couverture de non-exposition le cas échéant ;

  • la carte des frontières d’identifiants à l’exécution couvre les clients de fournisseurs et de canaux, les outils, les serveurs MCP, les travaux délégués, les wrappers CLI, les gestionnaires de passerelle, les journaux, les reçus, les événements et les chemins d’erreur, les lacunes de durcissement qui en résultent étant transmises à des suivis ciblés plutôt que traitées comme un courtier d’identifiants accepté;

  • la forme minimisée canonique de l’événement de sécurité est créée à l’exécution, inclut les décisions de politique et les preuves de résultat sans charges utiles secrètes, et le puits durable activé enregistre l’événement de pré-exécution avant toute mutation ou refuse la mutation en cas d’échec de persistance ;

  • optional audit sinks and incident responders can add projections or responses but cannot suppress, replace, delay, or rewrite canonical evidence or baseline runtime hooks;

    Wait—I must return the translation, not the source. Here is the French translation:

    les puits d’audit facultatifs et les intervenants en cas d’incident peuvent ajouter des projections ou des réponses, mais ne peuvent ni supprimer, ni remplacer, ni retarder, ni réécrire les preuves canoniques ou les hooks d’exécution de référence;

  • every model-bound turn and steering injection receives its own trusted ingress envelope with transport, sender or principal, message identity where available, origin, and trust facts stamped by entry code rather than message content;

  • configurable Annotate, Gate, et Drop ne peuvent pas être activés tant que les dispositions non Loop non implémentées ne échouent pas en mode fermé avec des preuves d’audit et des tests ;

  • La authentification en périphérie de transport, l’appairage, les listes d’autorisation, les vérifications de signature, la validation des charges utiles, les limites de débit, le filtrage des messages propres et des bots, ainsi que les contrôles anti-abus restent appliqués avant l’admission du modèle normalisé ;

  • internal principals sont implémentés pour les points d’entrée cron, daemon/SOP, peer-agent et subturn, avec des tests démontrant qu’il s’agit de faits de provenance et jamais d’octrois d’appartenance à un pair ;

  • la liaison de conversation charge et ajoute l’historique via un propriétaire sérialisé par conversation, cron session_target = "main" devient visible dans le prochain tour interactif, et isolated reste délibérément non lié;

  • la provenance des réponses entre pairs livre ou enregistre la sortie terminée du processus actif du destinataire sans exposer le handle de session de l’expéditeur au destinataire, et require ne peut être affaibli ni par le destinataire ni par le contenu du message ;

  • L’exécution, la livraison et la persistance des résultats restent stockées ou émises indépendamment, toute agrégation de compatibilité étant dérivée de ces axes ;

  • La documentation sur la posture, les releases et la documentation permanente emploie avec exactitude le vocabulaire de preuves « configuré », « résolu/sondé » et « vérifié à l’exécution », y compris la correction des affirmations antérieures d’application active qui ne relevaient que de l’échafaudage de la phase 1 ; et

  • #7432 et les trackers d’implémentation ciblés identifient les tranches restantes, les responsables, les tests et les notes de publication ou de retour arrière avant que cet ADR ne soit marqué comme accepté.

Conséquences

Conséquences positives :

  • Les relecteurs disposent d’une seule question, gérée à l’exécution, pour les effets protégés : cette action a-t-elle reçu une décision à jour et consommé un permis valide à sa frontière ?
  • Les extensions de sécurité deviennent moins dangereuses parce qu’elles peuvent restreindre ou projeter, mais non remplacer le socle obligatoire.
  • Les décisions relatives au contenu entrant, les messages de pilotage, les travaux planifiés et les réponses des agents pairs partagent le même vocabulaire de provenance, au lieu d’inventer des logiques de confiance locales.
  • Les opérateurs peuvent distinguer la politique configurée, la capacité résolue et l’application vérifiée à l’exécution, au lieu de considérer toutes les sorties d’état comme également prouvées.
  • Le travail interne peut participer à l’historique des conversations et au routage des réponses, sans transformer les tâches cron, les étapes de SOP ni les agents pairs en faux pairs de canaux externes.

Conséquences négatives :

  • Le runtime doit transmettre davantage de contexte structuré à travers les frontières d’action et de tour.
  • Certains chemins de code actuellement utiles ne sont encore que partiellement démontrés tant que leurs tranches d’implémentation n’ajoutent pas les garde-fous et les tests mentionnés ci-dessus.
  • Un déploiement qui préserve les valeurs par défaut est plus lent qu’une réécriture de sécurité globale unique.
  • Le comportement d’entrée autre que Loop et l’envoi durable aux pairs ne peuvent pas être livrés à la légère ; ils nécessitent d’abord des preuves de défaillance, de provenance et de compatibilité.
  • Le audit de durabilité introduit des E/S fichier et un comportement fail-closed lorsqu’il est activé ; la compatibilité et le retour arrière doivent donc être explicites.

Références