Marketplace de packs complets
Version anglaise : ../../en/guides/marketplace.md
Le Marketplace distribue des packs métiers complets par tenant et par environnement. Un pack est signé, porte son SBOM, son analyse de vulnérabilités, ses rapports de tests et d'évaluations, et n'est installé qu'après un contrôle préalable et une approbation humaine. Les permissions demandées par un pack ne sont jamais celles qu'il obtient : un administrateur accorde un sous-ensemble et la plateforme n'applique que l'ensemble accordé.
Prérequis
| Besoin | Commande | Remarques |
|---|---|---|
| Chaîne OCI | tools/oci/fetch.sh | oras 1.3.6, cosign 2.6.5, zot 2.1.22 (minimal), versions officielles, épinglées, sha256 vérifié, dans /tmp/toolchains |
| Outils de politique | /tmp/toolchains/opa, /tmp/toolchains/fga, /tmp/toolchains/trivy | opa 1.21.4, fga 0.8.2, trivy 0.76.1, récupérés par tools/oci/fetch.sh (épinglés, sha256 vérifié) ; opa test, fga model test, trivy fs (base hors ligne, téléchargée une fois par trivy image --download-db-only) |
| Contrôles d'observabilité | /tmp/toolchains/promtool | promtool 3.15.1, récupéré par tools/oci/fetch.sh (épinglé, sha256 vérifié) |
| Interpréteur des packs | packs/bootstrap.sh | /tmp/toolchains/packs-venv, dépendances de packs/requirements.lock installées avec --require-hashes (SDK Python MCP 2.3.0, MIT) |
| SDK et CLI | pip install -e 'sdks/python[dev]' | commande enterprise-ai |
Un outil absent arrête la commande avec l'indication de récupération (cosign not found: run tools/oci/fetch.sh ...) ; rien n'est ignoré en silence.
Structure d'un pack
plugin.yaml (manifeste Plugin, spec.format: pack), README.md, LICENSE, CHANGELOG.md, et les dossiers
agents, subagents, skills/<nom>/SKILL.md, prompts, rules, policies/opa (avec _test.rego),
policies/openfga (modèle et tests *.fga.yaml), mcp/servers, mcp/tools, mcp/schemas, connectors,
workflows, rag, evaluations (configuration promptfoo, JSONL Ragas), security,
observability/alerts (règles Prometheus et SLO), tests/unit, tests/integration, tests/authz,
tests/security, docs/en, docs/fr, examples. Les dossiers optionnels (subagents, rag, workflows,
mcp/*, connectors, examples, policies/openfga) ne peuvent être omis qu'avec une raison dans
spec.layout.omitted. Un pack ne livre aucun tableau de bord (ADR-0169) : un dossier dashboards sous
observability est refusé par plugin validate et par le contrôle schema ; les tableaux de bord de la plateforme
sont dans le Navin Manager (machines, services) et le portail (agents, passerelle LLM, FinOps, SLO, sécurité).
Le manifeste déclare license, compatibility {platform, sdk, runtimes}, dependencies,
requestedPermissions [{scope, reason, sensitive, classification}], dataProtection, approvals {install, sensitive, production}, docs {en, fr}, evaluations et tests. signedArtifact est rempli par la construction
et la signature dans le descripteur publié.
Développer, construire, signer, publier
enterprise-ai plugin create packs/my-legal --domain legal --name my-legal --lock packs/requirements.lock
enterprise-ai plugin validate packs/my-legal
enterprise-ai plugin build packs/my-legal --out /tmp/my-legal-dist
COSIGN_PASSWORD=... enterprise-ai plugin sign packs/my-legal --out /tmp/my-legal-dist --key cosign.key --signer acme
enterprise-ai plugin publish packs/my-legal --out /tmp/my-legal-dist --key cosign.key \
--oci <harbor-host>/packs/my-legal:1.0.0
build: archive tar gzip reproductible (entrées triées, propriétaire et date fixesSOURCE_DATE_EPOCH, 0 par défaut) : deux constructions donnent la même empreinte sha256.<nom>-<version>.spdx.jsonest un document SPDX 2.3 qui liste chaque fichier avec son SHA-256 et les dépendances épinglées derequirements.txt.sign:cosign sign-blob --key(paire de clés hors ligne,--tlog-upload=false) sur l'empreinte et sur le SHA-256 de chaqueSKILL.md; écrit<nom>-<version>.pack.json.publish: lance les suites pytest (unit, integration, authz, security) avec l'interpréteur des packs,opa test,fga model test,promtool check rules, les évaluations promptfoo et Ragas,trivy fs, pousse l'archive, le SBOM et le descripteur en un seul artefact OCI avec ORAS (typeapplication/vnd.enterprise-ai.pack.v1), signe l'empreinte du manifeste aveccosign sign --key, puis envoiePOST /v1/marketplace/packages(ou écrit le corps avec--body-out).
Enregistrez d'abord la clé publique de l'éditeur (tenant_admin ou security_officer) :
POST /v1/marketplace/publishers {"name": "acme", "public_key": "<contenu de cosign.pub>"}
Contrôles de publication
La publication est refusée (422 publication_gate_failed, chaque contrôle dans details.gates) dès qu'un
contrôle échoue ou que son entrée manque : schema (manifeste, structure, chaque manifeste d'agent, d'outil et de
connecteur), signature (empreinte du pack et chaque skill avec une clé d'éditeur active), sbom (chaque fichier
et sa somme), vulnerability_scan (rapport Trivy lié à l'empreinte, aucune vulnérabilité CRITICAL ou HIGH, aucun
secret), tests, evaluations (score au-dessus du seuil), licence (MIT, Apache-2.0, ou une autre licence déclarée
dans licenseDeclaration avec une raison), permissions (aucun droit dangereux : jokers, secrets, platform,
tenants, keys, audit, policies, authz, identity, billing, licenses, kill-switch, ou une action
admin, impersonate, bypass, delete-all ; chaque droit utilisé par un agent, une skill ou un outil est
demandé), docs, secrets, provenance (attestation in-toto Statement v1 au prédicat SLSA provenance v1 dans
provenance: {statement, signature}, sujet = empreinte du pack, SBOM et rapports liés comme sous-produits, signée
par l'éditeur du pack ; enterprise-ai plugin publish --key la produit), privacy (G6 : détection et masquage des
données personnelles quand le pack en traite, DLP, résidence, externalExportDefault: deny), security
(signedArtifactRequired, sandboxRequired, dynamicAuthorization, auditRequired à true), approvals
(requiredFor couvre install, upgrade, sensitivePermissions, production et resume), configuration
(configSchema est un JSON Schema d'objet), resilience (G9 : délai borné de chaque outil, outil à effet de bord
idempotent avec une clé d'idempotence, workflow qui s'arrête ou compense en cas d'échec). Le manifeste porte aussi
namespace, category, publisher et displayName {en, fr}, enregistrés dans le catalogue, et testFlags
(sdkConformance, authorization, security) : la conformité SDK de chaque objet est un résultat du rapport de
tests. Un pack signé qui demande un droit dangereux est refusé. Une version publiée est
immuable (409 marketplace_version_exists).
Production : POST /v1/marketplace/packages/{name}/versions/{version}/production vérifie les contrôles
enregistrés, la signature courante (une clé révoquée échoue) et l'empreinte OCI, puis ouvre une approbation à
quatre yeux. Installer en prod demande une version au statut production.
Installer par tenant et par environnement
enterprise-ai plugin install hr --version 1.0.0 --env dev --grant hr.employees.read --grant hr.leave.read \
--secret-ref hr-hris=openbao://tenants/acme/hr/hris
- Contrôle préalable : environnement, statut de la version, compatibilité plateforme, dépendances installées dans
le même environnement, empreinte et signature vérifiées à nouveau, permissions accordées demandées par le pack
et sûres, références de secrets (
openbao://ouenv://) des connecteurs, aucun conflit de nom. Essai à blanc :POST /v1/marketplace/preflight. - Approbation par le service d'approbations (
marketplace.install) : quorum deapprovals.install, au moins deux approbateurs distincts quand une permission accordée est sensible (déclarée sensible, action d'écriture, de paiement, d'exécution, d'approbation, de virement ou de suppression, données restreintes ou secrètes) ou quand l'environnement estprod. Le demandeur n'approuve jamais (403separation_of_duties). - Application (
POST /v1/marketplace/installations/{id}/apply) : les objets sont créés par les registres existants et nommés<objet>-<environnement>: agents (droits accordés seulement), skills (signature vérifiée par le Skill Registry), outils (statutblockedquand leurs droits ne sont pas accordés), connecteurs (références de secrets), prompts, politiques OPA (endraft: activer une politique du tenant reste une action explicite), serveurs MCP enregistrés dans la passerelle MCP quandconfig.mcp_servers.<nom>.urlest donnée, une base de connaissances par modèle RAG. Les règles, modèles OpenFGA, serveurs MCP, workflows, modèles RAG, alertes et migrations du pack sont inscrits dansassets(eai.marketplace_assets) avec leur empreinte et leur statut :active,blocked(workflow dont un outil n'est pas accordé),pending_endpoint(serveur MCP sans adresse),suspended. La configuration est validée contre leconfigSchemadu pack (422config_invalid). - Tests de fumée : chaque objet est enregistré, les agents n'ont que les droits accordés, les skills accordées se
chargent pour leurs agents, les outils hors périmètre sont bloqués, chaque serveur MCP enregistré répond à un
vrai
initializepuis la liste des outils MCP (méthode tools list) avec tous les outils déclarés, chaque workflow actif n'utilise que des outils approuvés. Un échec annule la modification (422smoke_failed).
À l'usage, une permission demandée mais non accordée est refusée par le Skill Loader (403
skill_permission_denied), par la passerelle d'outils (403 tool_blocked) et par
POST /v1/marketplace/installations/{id}/authorize, que les serveurs MCP des packs appellent avant chaque outil
(403 permission_not_granted).
Mise à niveau, retour arrière, désinstallation
- Mise à niveau :
POST /v1/marketplace/installations/{id}/upgrade {version, approved_permissions}(contrôle préalable et approbation, puis/apply) ; la version et les droits précédents sont conservés. - Retour arrière :
POST /v1/marketplace/installations/{id}/rollbackréinstalle la version précédente avec ses droits précédents et retire ce que la nouvelle version avait ajouté. - Désinstallation :
POST /v1/marketplace/installations/{id}/uninstallretire chaque objet créé par l'installation, avec ses relations. Historique :GET /v1/marketplace/installations/{id}/events.
Kill switch, suspension et supervision
- Suspendre une installation ou certaines de ses capacités :
POST /v1/marketplace/installations/{id}/status {status: suspended, permissions?: [...], reason}. L'effet est immédiat : avecpermissions, seules ces permissions sont refusées (403permission_suspended) et leurs outils bloqués ; sans, tous les outils sont bloqués, les agents suspendus, les serveurs MCP désactivés et les contenus suspendus (403installation_suspended). - Reprendre :
{status: installed}ouvre une approbationmarketplace.resume(quorum 2, jamais le demandeur, 202), puis le même appel avec l'approval_idapprouvé rétablit l'état accordé. Aucun contournement : sans approbation approuvée la reprise est refusée. - Kill switch d'un paquet :
POST /v1/marketplace/packages/{name}/status {status: suspended}suspend d'un coup toutes les installations du tenant et refuse installations, mises à niveau, publications, mises en production et reprises (409package_suspended) ;{status: active}le lève avec une approbationmarketplace.package.resume. - Supervision :
GET /v1/marketplace/installations/{id}/supervisionagrège l'activité (appels d'outils, exécutions, refus), la qualité (évaluations, tests de fumée, taux de réussite), les coûts des exécutions et les incidents qui nomment les objets créés. - Une permission qui envoie des données du pack hors de la plateforme (action
export,external,share) est refusée à l'usage (403external_export_denied) carexternalExportDefaultvautdeny.
Dépôt local pour un site sans accès réseau
- Côté connecté :
enterprise-ai plugin publish <pack> --key cosign.key --oci <registre>/packs/<pack> --body-out <pack>-<version>.pack-body.jsonproduit le corps de publication complet (archive, signature, SBOM, rapports, provenance SLSA). Copier l'artefact et sa signature cosign dans une disposition OCI :oras cp <registre>/packs/<pack>@<empreinte> --to-oci-layout transfer/<pack>:<version>etoras cp <registre>/packs/<pack>:sha256-<hex>.sig --to-oci-layout transfer/<pack>:sha256-<hex>.sig. - Transporter le dossier
transfer/et le fichier.pack-body.jsonsur le support autorisé. - Côté isolé : pousser la disposition dans le registre local (zot ou Harbor du client) avec
oras cp --from-oci-layout transfer/<pack>:<version> <miroir>/packs/<pack>:<version>(et la signature), vérifier que l'empreinte est identique (oras manifest fetch --descriptor) et la signature (cosign verify --key cosign.pub --insecure-ignore-tlog=true), puis importer le corps avecclient.marketplace.import_publication(corps, oci_ref="<miroir>/packs/<pack>:<version>")(SDK Python). Le Control Plane revérifie tous les contrôles hors ligne avec la clé d'éditeur enregistrée.
Chaque route prend d'abord une décision de politique (actions marketplace.*) et écrit un événement d'audit, refus
compris.
Packs de référence et modèles
| Pack | Contenu |
|---|---|
packs/hr | annuaire aux coordonnées masquées, soldes et politique de congés, demande de congé idempotente, bulletin personnel seulement ; SIRH simulé sur des salariés fictifs |
packs/finance | factures, soldes du grand livre, paiement exécuté une seule fois (clé d'idempotence, pas de double paiement, reprises concurrentes), rapprochement ; ERP simulé sur un grand livre fictif |
packs/templates/<domaine> | banking, risk-compliance, legal, it, cybersecurity, sales-crm, marketing, procurement, support, document-intelligence |
Chaque connecteur a une interface d'adaptateur, une implémentation simulée sur des données fictives et une implémentation qui passe par le Connector Broker de la plateforme : aucun système réel n'est contacté tant que le tenant n'a pas configuré la référence de secret et la règle d'egress.
Procédures dans le portail
Les écrans sont Marketplace > Catalogue des packs (onglets Paquets, Contrôle préalable, Éditeurs de
confiance), Marketplace > Installations et Marketplace > Pipeline de changement
(portal/src/screens/kit-platform.tsx).
-
Enregistrer la clé de l'éditeur. Sans clé d'éditeur active, le contrôle
signaturerefuse chaque pack de cet éditeur.Écran : Catalogue des packs > Éditeurs de confiance > Ajouter un éditeur, collez le contenu de
cosign.pub. API : POST /v1/marketplace/publishers.Résultat attendu : l'éditeur est listé comme actif.
En cas d'échec : 403
forbiddensignale que vous n'êtes nitenant_adminnisecurity_officer. -
Publier le pack. La publication passe tous les contrôles : un pack présent au catalogue est complet et signé.
enterprise-ai plugin publish packs/my-legal --out /tmp/my-legal-dist --key cosign.key --oci <harbor-host>/packs/my-legal:1.0.0Résultat attendu : la version apparaît dans Catalogue des packs > Paquets avec son SBOM et ses rapports (GET /v1/marketplace/packages/{name}/versions/{version}).
En cas d'échec : 422
publication_gate_failedliste chaque contrôle en échec dansdetails.gates; 409marketplace_version_existssignale une version déjà publiée (publiez une nouvelle version). -
Lancer le contrôle préalable. Il montre, avant tout changement, ce que le pack demande et ce dont l'installation a besoin.
Écran : Catalogue des packs > Contrôle préalable. API : POST /v1/marketplace/preflight.
Résultat attendu : les permissions demandées, la configuration requise et chaque contrôle préalable réussi.
En cas d'échec : chaque contrôle en échec est nommé ; corrigez l'environnement, les dépendances ou les références de secrets.
-
Installer le pack. L'assistant accorde un sous-ensemble des permissions demandées et ouvre l'approbation.
Écran : Marketplace > Installations > Installer un pack : paquet, version, environnement, permissions accordées, configuration et références de secrets. CLI : la commande
enterprise-ai plugin installci-dessus.Résultat attendu : une installation au statut
pending_approval.En cas d'échec : 409
package_suspendedsignale le kill switch du paquet actif ; 409marketplace_object_conflictsignale un objet du même nom déjà présent dans l'environnement. -
Faire approuver l'installation. D'autres personnes décident dans Agents > Approbations ; le demandeur n'approuve jamais.
Résultat attendu : l'approbation atteint son quorum.
En cas d'échec : 403
separation_of_dutiesquand le demandeur tente d'approuver. -
Appliquer. L'application crée les objets, puis lance les tests de fumée.
Écran : Installations, action Appliquer sur l'installation. API : POST /v1/marketplace/installations/{id}/apply.
Résultat attendu : statut
installed; les actions events et supervision montrent l'historique et l'activité.En cas d'échec : 422
config_invalid(configuration hors duconfigSchema) ou 422smoke_failed(la modification est annulée). -
Suivre un changement d'un objet de pack. Le pipeline de changement fait avancer une nouvelle version étape par étape, avec ses preuves : brouillon, test, revue de sécurité, approbation métier, préproduction, production, surveillance.
Écran : Marketplace > Pipeline de changement > Nouveau changement, puis faites-le avancer avec ses preuves.
Résultat attendu : le changement atteint
production, puismonitoring.En cas d'échec : une étape qui exige une approbation attend son
approval_id; rejetez le changement avec une raison pour l'arrêter.
Tests d'acceptation
cd services/control-plane && .venv/bin/python -m pytest -q tests/test_marketplace.py tests/test_marketplace_governance.py
cd sdks/python && .venv/bin/python -m pytest -q tests/test_packs.py
Limites
- Les signatures utilisent des paires de clés cosign hors ligne, sans journal de transparence ; la signature sans clé n'est pas utilisée.
- Les configurations promptfoo s'exécutent avec des fournisseurs
exec:et des assertions déterministes ; les métriques jugées par un modèle s'exécutent dans le service d'évaluation de la plateforme. Les jeux Ragas sont notés hors ligne avec le rappel du contexte. - Les règles d'alerte sont vérifiées par
promtool check rulesà la publication (dans le contrôletests) ; les tests ne les chargent pas dans un Prometheus actif.
Dépannage
| Statut | Code | Cause | Correction |
|---|---|---|---|
| 422 | publication_gate_failed | un contrôle a échoué ou son entrée manque | lisez details.gates, corrigez le pack, republiez |
| 409 | marketplace_version_exists | la version est déjà publiée | montez la version dans plugin.yaml |
| 422 | config_invalid | configuration hors du configSchema du pack | corrigez la configuration |
| 422 | smoke_failed | un test de fumée a échoué après l'application ; la modification est annulée | lisez le test en échec, corrigez les droits accordés ou la configuration |
| 403 | separation_of_duties | le demandeur a tenté d'approuver | faites décider d'autres approbateurs |
| 409 | package_suspended | kill switch du paquet actif | levez-le avec une approbation marketplace.package.resume |
| 409 | marketplace_object_conflict | un objet du même nom existe déjà | renommez ou retirez l'objet existant |
| 403 | permission_not_granted, tool_blocked, skill_permission_denied | une permission demandée mais non accordée | mettez à niveau l'installation avec la permission dans approved_permissions |
| 403 | permission_suspended, installation_suspended | installation ou permission suspendue | reprenez avec une approbation marketplace.resume approuvée |
| 403 | external_export_denied | une permission qui exporte des données du pack | gardez les données dans la plateforme |