À proposExpertiseRéalisationsR&DBlogOutilsCommencerContact

Un manifeste d'agent Copilot est une frontière de sécurité. Voici le vérificateur.

Toutes les propriétés de portée d'un manifeste d'agent Microsoft 365 Copilot sont facultatives et, dans six cas, en omettre une donne la portée la plus large au lieu de la plus étroite. Un validateur JSON Schema approuve ces manifestes, parce qu'aucun n'a quoi que ce soit d'invalide : il manque quelque chose de facultatif. Nous avons donc écrit la vérification qui les attrape. Elle trouve six problèmes dans un manifeste qui passe tous les autres tests.

pH7x Systems® · · 7 min de lecture

Un agent déclaratif pour Microsoft 365 Copilot n'est pas du code. C'est un manifeste JSON qui indique au modèle à quoi il sert, ce qu'il peut lire et ce qu'il peut faire. Le modèle, l'orchestration et le filtrage par permissions viennent de Copilot. Les frontières, elles, viennent de vous.

Presque toutes les propriétés qui définissent ces frontières sont facultatives. Dans six cas, en omettre une ne restreint pas l'agent. Elle lui donne la portée la plus large qui existe.

La ligne qui accorde tout

Un manifeste a besoin de trois champs : name, description et instructions. Tout le reste relève des capacités, et voici celle qui pèse le plus.

json
{
  "capabilities": [
    {
      "name": "OneDriveAndSharePoint",
      "items_by_url": [
        { "url": "https://tenant.sharepoint.com/sites/Tenders/Documents/Live" }
      ]
    }
  ]
}

Supprimez maintenant le tableau items_by_url. La documentation est explicite : sans items_by_url ni items_by_sharepoint_ids, l'agent peut désormais accéder à toutes les sources OneDrive et SharePoint de l'organisation.

Pas à quelques-unes. À toutes. Et la version fautive ne provoque aucune erreur : elle produit un agent qui fonctionne, répond aux questions et fonde ses réponses sur tous les sites auxquels la personne qui lui parle a accès.

Copilot applique toujours le filtrage de sécurité de cette personne, l'agent ne lit donc rien qu'elle-même ne pourrait ouvrir. Cette garantie est réelle, et nous avons écrit sur la même frontière dans l'assistant IA qui ne lit que ce que l'utilisateur peut lire. Mais filtrer n'est pas délimiter. Qui dispose d'un accès large se retrouve avec un agent d'appels d'offres qui répond à partir de fichiers de ressources humaines et de comptes rendus de conseil, parce que rien ne lui a dit non.

La même règle apparaît six fois :

Capacité Omettre ceci Et l'agent obtient
OneDriveAndSharePoint items_by_url, items_by_sharepoint_ids Toutes les sources SharePoint et OneDrive de l'organisation
GraphConnectors connections Tous les connecteurs Copilot de l'organisation
TeamsMessages urls Tous les canaux, réunions et conversations
Meetings items_by_id Toutes les réunions
WebSearch sites Le web ouvert
Email folders La boîte aux lettres entière

C'est un choix défendable : un agent qui ne lirait rien par défaut serait inutile à l'installation. Mais il inverse l'habitude de qui écrit de la configuration de sécurité, où une règle manquante signifie d'ordinaire refusé. Ici, le silence veut dire oui.

Le piège qui survit à la connaissance du schéma

Le schéma 1.8 a ajouté deux capacités d'écriture, EmailActions et MeetingActions. La première couvre le tri, l'envoi supervisé, la suppression, les règles de boîte de réception, la réponse automatique et la gestion des dossiers.

La documentation indique que EmailActions fonctionne indépendamment de Email et que les restrictions de portée définies sur Email, y compris folders, shared_mailbox et group_mailboxes, ne s'y appliquent pas. Ce manifeste ne fait donc pas ce qu'on voulait :

json
{
  "capabilities": [
    { "name": "Email", "folders": [ { "folder_id": "inbox" } ] },
    { "name": "EmailActions" }
  ]
}

La lecture reste limitée à la boîte de réception. Supprimer, déplacer et créer des règles ne l'est pas du tout. Il n'y a aucun moyen de délimiter EmailActions : l'objet possède exactement une propriété, son nom. La décision est binaire et doit être prise délibérément.

Ce manifeste est l'œuvre de quelqu'un qui faisait attention. Faire attention au mauvais endroit donne un fichier qui a l'air prudent et ne l'est pas.

La vérification qui l'attrape

Un validateur JSON Schema approuve tous les manifestes fautifs qui précèdent, parce qu'aucun n'a quoi que ce soit d'invalide. Il manque quelque chose de facultatif, ce qui est différent, et c'est la seule chose qui compte ici.

Autrement dit, la revue doit chercher des absences, et c'est un travail mécanique, ce qui veut dire qu'il ne devrait pas revenir à une personne qui lit attentivement à dix-sept heures.

python
# Each capability, the properties that scope it, and what happens without them.
SCOPE = {
    "OneDriveAndSharePoint": (("items_by_url", "items_by_sharepoint_ids"),
                              "every SharePoint and OneDrive source"),
    "GraphConnectors": (("connections",), "every Copilot connector"),
    "TeamsMessages":   (("urls",),        "every channel, meeting and chat"),
    "Meetings":        (("items_by_id",), "every meeting"),
    "WebSearch":       (("sites",),       "the open web"),
    "Email":           (("folders", "shared_mailbox", "group_mailboxes"),
                        "the whole mailbox"),
}
# Write capabilities. There is no way to scope them: the choice is binary.
WRITES = {"EmailActions": "delete, move and create inbox rules",
          "MeetingActions": "book meetings and change the calendar"}

def check(manifest: dict) -> list[tuple[str, str]]:
    found = []
    caps = {c.get("name"): c for c in manifest.get("capabilities", [])
            if isinstance(c, dict)}

    for name, cap in caps.items():
        if name in SCOPE:
            props, everything = SCOPE[name]
            if not any(cap.get(p) for p in props):
                found.append(("OPEN", f"{name} without {' or '.join(props)}:"
                                      f" reads {everything}"))
        if name in WRITES:
            found.append(("WRITES", f"{name} can {WRITES[name]}"))

    # Email is scoped, EmailActions is not, and the file gives no sign of it.
    if "EmailActions" in caps and any(caps.get("Email", {}).get(p)
                                      for p in SCOPE["Email"][0]):
        found.append(("TRAP", "Email is scoped but EmailActions ignores that limit"))

    if not manifest.get("behavior_overrides", {}).get(
            "special_instructions", {}).get("discourage_model_knowledge"):
        found.append(("INVENTS", "answers from model knowledge when sources are silent"))
    if not manifest.get("disclaimer", {}).get("text"):
        found.append(("NO NOTICE", "the reader is not told where answers come from"))
    return found

Ajoutez-y vingt lignes qui lisent un fichier et renvoient un code de sortie différent de zéro, puis lancez-le sur un manifeste que tous les autres outils approuvent :

bash
$ python check_agent.py tender-desk.json
Tender Desk  schema v1.8
  OPEN      OneDriveAndSharePoint without items_by_url or items_by_sharepoint_ids:
            reads every SharePoint and OneDrive source
  WRITES    EmailActions can delete, move and create inbox rules
  OPEN      WebSearch without sites: reads the open web
  TRAP      Email is scoped but EmailActions ignores that limit
  INVENTS   answers from model knowledge when sources are silent
  NO NOTICE the reader is not told where answers come from

6 to review
$ echo $?
1

Délimitez correctement ce même agent et il se tait et sort avec zéro. C'est ce qui lui permet de bloquer une publication, au lieu de rester dans un document que personne n'ouvre.

La ligne TRAP justifie le script entier. Elle ne se déclenche que lorsque quelqu'un a délimité Email puis ajouté EmailActions à côté, c'est-à-dire précisément le manifeste qu'écrit une personne soigneuse.

Nous l'avons lancé sur un manifeste réaliste pour notre propre tenant, avec le site SharePoint correctement délimité, et il avait encore quelque chose à dire : TeamsMessages avait été ajouté sans tableau urls, un agent prévu pour une seule bibliothèque de documents pouvait donc lire tous les canaux et conversations auxquels appartient son utilisateur. Personne n'a décidé cela. C'était une ligne qui n'a jamais été là.

Ce qu'elle n'attrape pas

Cela mérite d'être dit clairement, car une vérification qui exagère ce qu'elle couvre est pire que rien.

Elle lit un fichier. Elle ne sait pas si l'URL SharePoint pointe vers un dossier de douze documents ou vers un site de quarante mille, et cette différence pèse plus que tout ce que le script mesure. Elle ne peut pas dire si les instructions sont bonnes. Et elle ne dit rien sur le fait de savoir si les personnes qui utilisent l'agent devraient seulement avoir accès à ce contenu, une question de permissions antérieure à l'agent et qui lui survivra.

Ce qu'elle épargne, c'est la partie de la revue où une personne est la plus mauvaise : remarquer que quelque chose n'est pas là.

Pourquoi cela compte

L'attrait d'un agent déclaratif tient à l'absence de code à maintenir. Un manifeste, quelques sources de connaissance, et quelque chose de véritablement utile pour une équipe qui n'aurait jamais eu d'application sur mesure.

C'est vrai, et c'est aussi pourquoi la portée pèse davantage ici que dans une application. Personne ne relit un fichier JSON comme il relit une pull request. Il n'y a pas de suite de tests. Il n'y a pas de compilateur pour dire que le tableau omis signifie le tenant entier.

Maintenant, il y a au moins un script.

Poursuivre la lecture

Développement et automatisation

SPFx avant la version 1.0 : trois de nos web parts dans les samples officiels de Microsoft

La developer preview du SharePoint Framework est sortie en août 2016. La version 1.0 est arrivée en février 2017. Notre première contribution au dépôt officiel des samples Microsoft 365 date d'octobre 2016, cinq mois avant qu'il existe une 1.0 sur laquelle construire. Trois de nos web parts s'y trouvent aujourd'hui, et voici à quoi sert chacune.

·5 min de lecture
Développement et automatisation

Nous mesurons encore les ingénieurs sur la partie qui a été automatisée.

En 2025, DORA a jeté son propre tableau de bord. Les paliers low, medium, high et elite, que le secteur a cités pendant une décennie, ont cédé la place à sept archétypes d'équipe sur huit mesures. Ce n'est pas une note de méthodologie. C'est le cadre de mesure le plus utilisé du logiciel qui admet que les instruments ne lisent plus ce qui décide de la survie d'un système.

·11 min de lecture
IA et agents

Un agent est une intégration. Cent sont un problème de gouvernance.

Les agents ont obtenu une identité de production avant de disposer d'un moyen stable d'enregistrer ce qu'ils ont fait. Microsoft Entra Agent ID est disponible, avec des parrains et des dates d'expiration. Les conventions OpenTelemetry pour les traces d'agents restent expérimentales. Cet écart n'est pas un détail : il décide de ce qu'il est raisonnable de mettre en production cette année, et transforme une question d'IA en une question de gouvernance.

·12 min de lecture