Aller au contenu

Ironfang Rig

Documentation développeur

Donnez à l'application testée un monde extérieur jetable : adresses de boîte de réception temporaires, URL de callback publiques, endpoints HTTP simulés et routes vers votre machine, allouées à neuf pour chaque exécution, avec un enregistrement numéroté de tout ce qu'Ironfang a observé.

Démarrage rapide

Créez une clé API avec les portées Rig dans le portail Ironfang, puis committez un ironfang.rig.yaml à côté de l'application. Le fichier déclare les identités externes dont une exécution a besoin et ce que l'exécution doit observer.

version: 1
project: acme-shop
suite: checkout
name: Checkout flow
defaults:
  run_ttl: 30m
resources:
  customer_email:
    type: email
  stripe_callback:
    type: callback
    connector:
      route: stripe
  shipping_api:
    type: mock_http
    rules:
      - match: { method: POST, path: /v1/ship/* }
        respond: { status: 201, json: { tracking: "IF-1" } }
expectations:
  - id: order_email
    resource: customer_email
    event: email.received
    match: { subject_contains: "Your order" }
  - id: stripe_forwarded
    resource: stripe_callback
    event: connector.request.completed
    match: { outcome: delivered, status: 200 }

Le client en ligne de commande synchronise le fichier, démarre une exécution, exporte l'adresse de chaque ressource vers la commande placée après --, l'exécute, puis termine l'exécution avec un verdict.

export IRONFANG_API_KEY=if_live_...
ironfang rig run -- npm test

# In the test process:
#   IRONFANG_RIG_RUN_ID           the run
#   IRONFANG_RIG_CUSTOMER_EMAIL   run-....@inbox.rig.ironfang.uk
#   IRONFANG_RIG_STRIPE_CALLBACK  https://hooks.rig.ironfang.uk/h/...
#   IRONFANG_RIG_SHIPPING_API     https://mock.rig.ironfang.uk/m/...

La même exécution est disponible en HTTP. Chaque requête porte la clé comme jeton bearer, et l'URL de base est https://api.ironfang.uk/rig.

curl -X POST https://api.ironfang.uk/rig/v1/suites/$SUITE_ID/runs \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "ttl": "30m", "external_id": "ci-4821" }'

La description OpenAPI 3.1 complète est servie à https://api.ironfang.uk/rig/openapi.yaml.

Modèle

Les suites persistent, les exécutions sont jetables, les ressources ont une durée de vie explicite. Rien ici n'exécute votre code : Ironfang Rig est le monde extérieur auquel vos tests parlent, et l'enregistrement de ce qu'il a vu.

ObjetCe que c'est
ProjetUn conteneur persistant pour une application, désigné par un slug.
SuiteUne définition versionnée de ressources et d'attendus au sein d'un projet. Chaque révision est conservée avec son SHA-256 ; une exécution nomme toujours la version qu'elle a exécutée.
ExécutionUne exécution de la version courante d'une suite. Elle est active jusqu'à ce qu'elle soit finished, cancelled ou expired par son TTL (30 minutes par défaut, de 1 minute à 24 heures). Une exécution terminée a pour résultat pass, fail ou none.
RessourceUne identité externe que reçoit l'exécution : une boîte de réception, une URL de callback, un endpoint HTTP simulé ou une route vers un connecteur. Impossible à deviner et propre à l'exécution, joignable depuis Internet uniquement tant que l'exécution est active.
ÉvénementUne observation immuable sur la chronologie de l'exécution, avec un numéro de séquence continu à partir de 1. La chronologie est en ajout seul, et en lecture seule une fois l'exécution terminée.
AttenduUne condition déterministe sur la chronologie, stockée avec la suite et évaluée quand l'exécution est terminée.
PanneUne perturbation déterministe armée sur une ressource : retarder, dupliquer, abandonner, réordonner ou modifier le corps d'un callback transmis ; remplacer le statut d'un mock, réinitialiser sa connexion, brider son corps ou le couper court.

Tout est rattaché à une organisation. Un objet qui appartient à une autre organisation est signalé comme introuvable, jamais comme interdit.

Clés API et portées

Les clés API de la plateforme sont créées dans le portail et commencent par if_live_. Les portées d'une clé sont ses autorisations, et elle n'agit que dans l'organisation pour laquelle elle a été créée. Envoyez-la comme jeton bearer.

Authorization: Bearer if_live_...
  • rig:readLister et lire les projets, suites, exécutions, ressources, pannes, connecteurs et événements ; attendre sur la chronologie ; exporter les preuves
  • rig:writeCréer et réviser les projets et les suites
  • rig:runDémarrer, terminer et annuler les exécutions ; allouer des ressources ; modifier les règles de mock ; armer des pannes ; rejouer des callbacks
  • rig:connectorCréer des connecteurs et leurs jetons d'amorçage
  • rig:*Tout ce qui précède

Un jeton utilisateur Warden est également accepté, avec l'organisation agissante dans X-Ironfang-Tenant ; chaque route exige alors la permission de tenant correspondante (rig.read, rig.write, rig.run, rig.connector).

Erreurs

Chaque erreur est un objet JSON avec un code stable, un message lisible par une personne et l'identifiant de requête à communiquer au support.

{
  "error": {
    "code": "run_not_active",
    "message": "the run has already ended",
    "docs": "https://ironfang.uk/rig/docs#errors"
  },
  "request_id": "01a0c375-7bae-7f02-a3d4-91e6b8c25f70"
}

docs est un lien vers cette section, et request_id reprend l'en-tête de réponse X-Ironfang-Request-ID.

StatutCodeSignification
400invalid_json, invalid_queryLe corps n'est pas une unique valeur JSON stricte de la forme documentée, ou un paramètre de requête est inconnu, répété ou mal formé.
401unauthorized, invalid_api_keyAucun identifiant, ou un identifiant qui ne se résout pas.
403forbidden, insufficient_scopeLa clé n'a pas la portée, l'utilisateur n'a pas la permission, ou la requête nomme une autre organisation.
404not_foundAucun objet de ce type dans cette organisation.
409conflict, archived, run_not_activeUn slug est déjà pris, la cible est archivée, ou l'exécution est déjà terminée.
410payload_retiredL'événement existe, mais les octets de sa charge utile ont dépassé la durée de conservation.
422invalid_request, not_replayableUn champ est invalide ; le message le nomme.
429too_many_waiters, replay_limit, connector_limit, fault_limitUne limite par organisation ou par exécution a été atteinte ; le message indique laquelle. Les adresses de callback, de mock et de courrier d'une exécution répondent run_limit de la même façon une fois que l'exécution a atteint sa limite.

Le fichier de suite

ironfang.rig.yaml se trouve dans le dépôt, à côté de l'application qu'il teste. Il contient exactement la définition que l'API stocke, si bien que ce qu'un développeur committe est ce à partir de quoi une exécution est créée. La synchronisation du fichier crée le projet et la suite à la première utilisation et enregistre une nouvelle version de la suite chaque fois que la définition change.

ChampTypeRemarques
versionintegerToujours 1.
projectstringSlug du projet. Créé à la première synchronisation.
suitestringSlug de la suite, unique au sein du projet.
namestringNom d'affichage, jusqu'à 120 caractères.
defaults.run_ttldurationDurée de vie par défaut d'une exécution, de 1m à 24h. Par défaut 30m.
resourcesobjectNom vers spécification de ressource, de 1 à 32 entrées. Les noms respectent ^[a-z][a-z0-9_]{0,63}$ et deviennent des suffixes de variables d'environnement.
expectationsarrayJusqu'à 64 conditions, chacune avec un id, un nom de resource, un type d'event et un match facultatif.

Spécifications de ressource

typeChamps supplémentairesCe que reçoit l'exécution
emailaucunUne adresse de boîte de réception sous inbox.rig.ironfang.uk.
callbackconnector.route (facultatif)Une URL publique qui enregistre chaque requête. Avec une route, chaque requête est aussi transmise à votre connecteur.
mock_httprules (facultatif, jusqu'à 32)Une URL publique qui répond à partir de règles ordonnées.
connector_routerouteUn libellé de route sans adresse publique, auquel les connecteurs se lient.

Les libellés de route respectent ^[a-z0-9][a-z0-9-]{0,62}$. La plateforme ne nomme jamais qu'un libellé ; ce vers quoi il pointe est décidé sur la ligne de commande du connecteur et ne quitte jamais votre machine.

Correspondance

Un objet match est un ensemble de conditions sur les champs de premier niveau des données d'un événement, et chaque clé doit être satisfaite. Une clé simple se compare en JSON : nombres, booléens, chaînes et objets entiers se comparent par valeur. Une clé se terminant par _contains exige que le champ soit une chaîne contenant la valeur. La même règle évalue les attendus de la suite, l'endpoint d'attente et l'option --match de la CLI, si bien qu'une condition a le même sens partout. Jusqu'à 16 clés, de 4096 caractères chacune.

Ressources

Démarrer une exécution alloue chaque ressource déclarée. Chacune est impossible à deviner, n'appartient qu'à cette exécution et cesse d'accepter toute activité quand l'exécution se termine. D'autres peuvent être allouées sur une exécution active avec POST /v1/runs/{runId}/resources.

Boîtes de réception e-mail

Une ressource email est une adresse comme run-k7c3m2wp9e4q5r6t@inbox.rig.ironfang.uk. Le courrier qui lui est destiné est reçu par mx.rig.ironfang.uk, analysé et enregistré comme email.received avec l'expéditeur, le destinataire, l'objet, les liens, les codes de vérification, les pièces jointes et les détails de transport. Le message brut est conservé comme charge utile de l'événement. Les messages jusqu'à 10 MiB et 500 messages par exécution sont acceptés ; au-delà, tout est refusé dès l'échange SMTP, de sorte que l'expéditeur voit le rejet.

Chaque message est aussi vérifié comme le ferait un serveur de messagerie destinataire : SPF pour l'adresse d'envoi par rapport au domaine de l'expéditeur d'enveloppe, DKIM pour chaque signature qu'il porte, et DMARC pour le domaine From avec l'alignement et la politique que demande son enregistrement. Les résultats sont enregistrés sur l'événement sous authentication (spf, dkim[], dmarc avec le domaine, la politique, l'alignement et les motifs) et repris sous forme des champs d'un seul mot spf, dkim et dmarc, pour qu'un attendu ou une attente puisse demander { "dmarc": "pass" }. Ce sont des observations de ce que l'expéditeur publiait au moment de la réception : une défaillance DNS vaut temperror, jamais un verdict.

URL de callback

Une ressource callback est une URL comme https://hooks.rig.ironfang.uk/h/.... Toute méthode et tout chemin sous cette URL sont acceptés. La requête est enregistrée comme callback.received avec sa méthode, son chemin, sa query, son type de contenu, sa longueur en octets et son SHA-256, et l'expéditeur reçoit immédiatement un 200 avec l'identifiant de l'événement. Les octets exacts sont disponibles via l'endpoint de charge utile de l'événement. Les corps de plus de 64 KiB sont refusés avec un 413 et enregistrés comme callback.rejected ; une exécution accepte jusqu'à 1000 callbacks.

{ "received": true, "run_id": "...", "event_id": "...", "sequence": 7 }

Avec une connector.route, chaque requête enregistrée est aussi mise en file pour cette route et transmise par votre connecteur ; voir Connecteur local.

Endpoints HTTP simulés

Une ressource mock_http est une URL de base comme https://mock.rig.ironfang.uk/m/.... Les requêtes sous cette URL reçoivent la réponse de la première règle dont le match est satisfait ; sans correspondance, la réponse est un 404 avec le code no_mock_rule. Chaque requête est enregistrée comme mock.request.received et sa réponse comme mock.response.sent avec la règle correspondante. Les règles peuvent être remplacées tant que l'exécution est active avec PUT /v1/runs/{runId}/resources/{resourceId}/mock, ce qui enregistre mock.rules.updated.

Champ de règleRemarques
match.methodUne méthode HTTP, ou * ou absent pour toutes.
match.pathChemin exact sous l'URL du mock, préfixe se terminant par /*, ou modèle comme /v1/pets/{id} dont les segments entre accolades correspondent à n'importe quel segment ; absent pour tous.
match.headersEn-têtes qui doivent être présents avec exactement ces valeurs.
match.jsonChamps de premier niveau auxquels un corps de requête JSON doit être égal.
respond.statusObligatoire, de 100 à 599.
respond.headersEn-têtes de réponse.
respond.body ou respond.jsonUn corps texte jusqu'à 64 KiB, ou un corps JSON qui définit le type de contenu sauf si un en-tête le fait.
respond.delayAttente avant de répondre, au plus 10s.
respond.templateGénère le corps et les valeurs d'en-tête à partir de la requête : {{request.method}}, {{request.path}}, {{request.query.name}}, {{request.header.Name}}, {{request.body}}, {{request.json.a.b.0}}, {{run.id}}, {{resource.name}}, {{step}}, {{received_at}}. Dans un corps JSON, une variable de substitution se trouve dans une chaîne et y est échappée ; un nom inconnu est refusé dès l'écriture des règles.
sequence, repeatAu lieu de respond : de 2 à 16 réponses que la règle donne tour à tour à ses appels, puis de nouveau la dernière ou, avec repeat: cycle, à partir de la première. L'événement de réponse enregistre le step ; remplacer les règles fait repartir chaque séquence du début.

Déterministe : la même requête face aux mêmes règles, à la même étape, obtient la même réponse, délai compris. Une exécution peut faire jusqu'à 5000 appels de mock.

Un mock peut tenir lieu d'une API documentée au lieu de porter des règles : donnez à la ressource openapi.file (un chemin à côté du fichier de suite, que la CLI intègre) ou openapi.document (le texte OpenAPI 3, en JSON ou YAML, jusqu'à 256 KiB). Une règle est dérivée par opération, dans l'ordre du document : le modèle de chemin est le match, la réponse 2xx la plus basse ou la réponse par défaut est la réponse, et l'exemple documenté, ou une valeur construite à partir du schéma (enum d'abord, chaînes conformes au format, nombres à zéro, un élément de tableau), est le corps. Les références sont résolues dans le document et rien n'est téléchargé. Un mock contient au plus 32 opérations ; nommez celles dont une suite a besoin dans openapi.include sous la forme GET /pets/{id}, et définissez openapi.prefer: schema pour ignorer les exemples.

Routes de connecteur

Une connector_route n'a pas d'adresse publique. Elle existe pour qu'un connecteur puisse se lier au libellé et que des callbacks puissent le nommer. La plupart des suites déclarent la route directement sur le callback et n'ont jamais besoin d'une ressource distincte.

Chronologie et attente

GET /v1/runs/{runId}/events?since=0&limit=100 renvoie les événements de l'exécution dans l'ordre de séquence après since, jusqu'à 500 à la fois, avec next_since pour continuer. Les séquences sont continues à partir de 1 et ne changent jamais, si bien que la même requête renvoie toujours les mêmes événements. Les charges utiles plus volumineuses que ce que porte un événement sont référencées par blob_ref, jamais intégrées.

{
  "id": "...",
  "run_id": "...",
  "resource_id": "...",
  "type": "callback.received",
  "sequence": 7,
  "occurred_at": "2026-09-19T09:14:02.118Z",
  "data": {
    "resource": "stripe_callback",
    "method": "POST",
    "path": "/",
    "content_type": "application/json",
    "byte_length": 812,
    "sha256": "..."
  }
}

POST /v1/runs/{runId}/wait bloque jusqu'à ce qu'un événement postérieur à since corresponde, ou que le délai expire. L'attente lit d'abord la chronologie, si bien qu'un événement déjà survenu obtient une réponse immédiate, puis elle se réveille à l'arrivée de nouveaux événements.

curl -X POST https://api.ironfang.uk/rig/v1/runs/$RUN_ID/wait \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "email.received",
    "resource": "customer_email",
    "match": { "subject_contains": "Your order" },
    "since": 0,
    "timeout": "30s"
  }'

Un délai expiré est un 200 avec matched: false, jamais une erreur : rien ne s'est mal passé, la chose attendue n'est simplement pas encore arrivée, et next_since indique où reprendre. Les délais vont de 1 à 90 secondes (30 par défaut) ; bouclez avec next_since pour attendre plus longtemps. Déterministe : la même chronologie et la même requête renvoient toujours le même événement. Au plus 16 attentes peuvent être ouvertes en même temps par organisation.

Charges utiles

GET /v1/runs/{runId}/events/{eventId}/payload renvoie les octets exacts qu'un callback ou un message transportait, sous forme de pièce jointe opaque quoi que l'expéditeur ait déclaré, afin que le contenu de tiers ne soit jamais rendu sur l'origine de l'API. Le type de média déclaré figure dans X-Ironfang-Payload-Media-Type et le SHA-256 dans X-Ironfang-Payload-SHA256. Les octets de charge utile sont conservés 7 jours après la fin de l'exécution ; ensuite l'événement demeure et l'endpoint répond 410.

Catalogue des événements

Chaque type qu'un attendu ou une attente peut nommer, avec les champs de données qu'un match peut viser. Tous les événements portent aussi resource (le nom déclaré) lorsqu'il y en a un.

TypeQuandDonnées notables
run.startedL'exécution a commencé.suite_version, ttl_seconds, expires_at, external_id
resource.allocatedUne fois par ressource.name, type, expires_at
email.receivedUn message est arrivé pour une boîte de réception.sender, recipient, subject, from, links, codes, message, transport
callback.receivedUne requête a atteint une URL de callback.method, path, query, content_type, byte_length, sha256, source_ip, route
callback.rejectedUne requête a été refusée, par exemple pour un corps dépassant la limite.reason, limit_bytes
callback.forwardedUne livraison a été remise à un connecteur.delivery_id, event_id, route, connector_id, attempt
connector.request.completedLe connecteur a signalé le résultat local.outcome (delivered ou failed), status, headers, body_excerpt, duration_ms, error, delivery_id
callback.replayedUn callback enregistré a été rejoué à la demande.event_id, replay (1, 2, ...), delivery_id, route, requested_by
mock.request.receivedUne requête a atteint un mock.method, path, query, content_type, byte_length, matched, rule
mock.response.sentLe mock a répondu.status, original_status, rule, delay_ms, request_event_id
mock.rules.updatedLes règles ont été remplacées.rules
connector.connected, connector.disconnectedUne session de connecteur s'est ouverte ou fermée.connector_id, name, routes, reason, requeued_deliveries
fault.added, fault.removed, fault.injectedUne panne a été armée, désarmée ou déclenchée.fault_id, type, fired, persistent, status, event_id
expectation.passed, expectation.failedÉvalué à la clôture, un par attendu.expectation, event
run.completed, run.cancelled, run.expiredL'exécution s'est terminée.outcome, passed, failed, total, reason

Connecteur local

Un callback doté d'une connector.route est transmis à une application sur votre machine ou votre runner CI sans ouvrir de port entrant. Le binaire ironfang rig connect contacte la passerelle à wss://connect.rig.ironfang.uk/v1/connect, se lie aux libellés de route et adresse chaque requête transmise à la cible locale que vous avez indiquée pour ce libellé. Le résultat local revient et est enregistré comme connector.request.completed.

Créez un connecteur sur une exécution active. La réponse contient un jeton d'amorçage à usage unique qui expire au bout de dix minutes, l'URL de la passerelle et la ligne de commande à compléter. Le jeton apparaît ici et nulle part ailleurs.

curl -X POST https://api.ironfang.uk/rig/v1/runs/$RUN_ID/connectors \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "ci-runner-3", "routes": ["stripe"] }'

# Then, with the token in the environment rather than an argument:
IRONFANG_CONNECT_TOKEN=ift_boot_... ironfang rig connect \
  --route stripe=http://127.0.0.1:8080/webhooks/stripe

Le connecteur échange le jeton d'amorçage contre un identifiant de session lié à cette organisation, cette exécution et ces routes, qui ne vit pas plus longtemps que l'exécution. Les livraisons pour une route attendent qu'un connecteur la détienne, puis arrivent dans l'ordre, chacune avec un délai local de 30 secondes ; le résultat que signale le connecteur est définitif. Un connecteur qui décroche en cours d'exécution reprend avec son identifiant de session, et les livraisons auxquelles il n'avait pas répondu sont remises en file pour la session suivante avec leur compteur de tentatives incrémenté. GET /v1/runs/{runId}/connectors indique l'état de chaque connecteur et le nombre de livraisons encore en attente. Une exécution peut avoir jusqu'à 16 connecteurs.

Les requêtes transmises portent la méthode, le chemin, la query, les en-têtes et le corps d'origine, plus X-Ironfang-Delivery-ID, X-Ironfang-Event-ID et X-Ironfang-Route, pour que l'application puisse distinguer un rejeu ou un doublon d'une première livraison. Les trames sont limitées à 256 KiB.

Pannes

Une panne est une perturbation déterministe armée sur une ressource d'une exécution active avec POST /v1/runs/{runId}/faults. Elle se déclenche sur la prochaine observation à laquelle elle s'applique, count fois (une fois par défaut) ou, si elle est persistent, jusqu'à son retrait ou la fin de l'exécution. Chaque déclenchement est un événement fault.injected à côté de l'observation sur laquelle il a agi. Aucun hasard : les mêmes pannes face au même trafic donnent la même chronologie.

curl -X POST https://api.ironfang.uk/rig/v1/runs/$RUN_ID/faults \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "type": "duplicate", "resource": "stripe_callback", "copies": 2 }'
typeAgit surEffet
delayUn callback avec une route de connecteurLa livraison est retenue pendant delay, au plus 30s, avant d'être transmise.
duplicateUn callback avec une route de connecteurLa livraison est transmise copies fois de plus (de 1 à 5, 1 par défaut), chaque copie avec son propre identifiant de livraison.
dropUn callback avec une route de connecteurLe callback est enregistré mais jamais transmis.
status_overrideUn endpoint HTTP simuléLe mock répond status quoi que disent ses règles ; le corps et les en-têtes restent inchangés et le statut d'origine est enregistré.
reorderUn callback avec une route de connecteurLes livraisons sont retenues jusqu'à ce que batch d'entre elles (de 2 à 10) soient en attente, puis libérées de la dernière à la première, si bien que le connecteur les reçoit en ordre inverse. La panne se déclenche une fois par lot et nomme l'ordre ; un lot encore incomplet à la fin de l'exécution expire avec le résultat held.
payload_mutationUn callback avec une route de connecteurLa livraison porte un corps modifié par mutations, dans l'ordre : set ou remove à un JSON Pointer, replace de texte, ou truncate à une longueur. Le corps reçu reste intact sur la chronologie ; le corps envoyé est la charge utile de l'événement fault.injected, qui indique aussi quelles modifications ont été appliquées.
connection_resetUn endpoint HTTP simuléLa requête est enregistrée, puis la connexion est fermée sans réponse. En accès direct, l'appelant voit une réinitialisation ; via la périphérie publique, il voit la réponse bad gateway du proxy. Dans les deux cas, il n'y a pas de réponse valide.
bandwidth_limitUn endpoint HTTP simuléLe corps est envoyé à bytes_per_second (de 64 à 1048576), par blocs d'un dixième de seconde. Un corps qui prendrait plus de 30 secondes est envoyé au débit qui convient, et l'événement indique qu'il a été plafonné.
partial_responseUn endpoint HTTP simuléLes en-têtes, avec la longueur de contenu complète, et les premiers bytes du corps sont envoyés, puis la connexion se ferme : l'appelant voit un corps tronqué.

Une panne active de chaque type par ressource, et jusqu'à 64 pannes par exécution. Quand plusieurs s'appliquent à la même livraison, drop l'emporte, puis delay, puis duplicate ; un reorder retient la livraison quel que soit son delay, et une mutation de charge utile façonne chaque copie. Les pannes de mock agissent ensemble dans l'ordre où elles ont été armées : un remplacement de statut change le statut, et une réinitialisation, un bridage ou une coupure s'applique à ce qui est alors envoyé. DELETE /v1/runs/{runId}/faults/{faultId} en désarme une et enregistre fault.removed ; la ligne est conservée, car l'historique des pannes fait partie des preuves. Les pannes n'agissent jamais sur un rejeu, qui est un acte explicite du test lui-même.

Attendus et verdicts

Les attendus sont évalués quand l'exécution est terminée, sur l'ensemble de la chronologie. Chacun est satisfait si un événement de son type sur sa ressource satisfait son match, et le premier de ces événements est enregistré avec le verdict. Le résultat de l'exécution découle des verdicts : pass quand tous les attendus sont satisfaits, fail quand l'un d'eux échoue, none pour une suite sans attendus. Passez un résultat pour remplacer cette déduction quand votre propre harnais de test en sait davantage.

curl -X POST https://api.ironfang.uk/rig/v1/runs/$RUN_ID/finish \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "npm test exited 0" }'
{
  "run": { "id": "...", "status": "finished", "outcome": "pass", ... },
  "expectations": [
    { "id": "order_email", "resource": "customer_email", "event": "email.received",
      "passed": true, "event_id": "...", "sequence": 9 },
    { "id": "stripe_forwarded", "resource": "stripe_callback",
      "event": "connector.request.completed", "passed": true, "event_id": "...", "sequence": 12 }
  ]
}

La clôture enregistre un expectation.passed ou un expectation.failed par attendu, puis run.completed. Une exécution annulée ou qui atteint son TTL se termine par run.cancelled ou run.expired, sans verdict. Envoyez un en-tête Idempotency-Key au démarrage d'une exécution pour qu'une étape de CI relancée récupère l'exécution déjà démarrée.

Rejeu

POST /v1/runs/{runId}/events/{eventId}/replay retransmet à sa route de connecteur un callback reçu par l'exécution, exactement tel qu'enregistré, pour prouver que l'application gère une répétition. L'événement doit être un callback.received sur une ressource dotée d'une route de connecteur, et l'exécution doit être active.

curl -X POST https://api.ironfang.uk/rig/v1/runs/$RUN_ID/events/$EVENT_ID/replay \
  -H "Authorization: Bearer $IRONFANG_API_KEY"

{ "event": { "type": "callback.replayed", "data": { "event_id": "...", "replay": 1, ... } },
  "delivery_id": "..." }

Le rejeu est enregistré comme callback.replayed puis circule comme toute livraison : la chronologie montre ses propres callback.forwarded et connector.request.completed rattachés à l'identifiant de l'événement d'origine, et la complétion nomme le delivery_id que la réponse vous a donné. Les pannes armées n'agissent pas sur un rejeu. Au plus 200 rejeux par exécution ; un 422 not_replayable désigne un événement qui n'est pas un callback transmissible.

Paquet de preuves

POST /v1/runs/{runId}/evidence construit le paquet de preuves de l'exécution à partir de ce qu'elle a enregistré et le diffuse en ZIP. Il est en lecture seule : le paquet contient ce que l'appelant peut déjà lire événement par événement, emballé pour être joint à un ticket, un audit ou une version.

FichierContenu
manifest.jsonL'exécution, les compteurs, ainsi que la taille et le SHA-256 de chaque fichier. Écrit en dernier, si bien qu'un manifeste complet signifie un paquet complet.
events.jsonToute la chronologie dans l'ordre de séquence.
expectations.jsonChaque attendu avec son verdict une fois l'exécution terminée.
faults.json, resources.json, definition.jsonLes pannes avec le nombre de déclenchements de chacune, les ressources avec leurs adresses, et la version de suite que l'exécution a exécutée.
messages/, requests/Chaque message reçu et chaque corps de callback, nommés par séquence et identifiant d'événement.
signature.jsonUne signature Ed25519 sur manifest.json tel qu'écrit, avec l'identifiant de la clé et la clé publique, quand la plateforme dispose d'une clé de signature ; le manifeste indique signing dans tous les cas.

Limité à 10 000 événements et 256 MiB de charges utiles ; le manifeste indique quand une limite a joué et liste les charges utiles que la conservation avait déjà supprimées. Avec Accept: application/json, seul le manifeste est renvoyé, avec le chemin qui télécharge le paquet.

Preuve des actions

Chaque événement porte un hash : SHA-256 sur le hash de l'événement précédent, l'identifiant de l'exécution, la séquence, le type, l'horodatage et les données de l'événement en JSON canonique (clés dans l'ordre des octets, sans espaces, nombres tels qu'écrits), joints par des retours à la ligne. L'exécution porte la tête de la chaîne dans chain_head, le manifeste enregistre la chaîne qu'il a recalculée en construisant le paquet, et un octet modifié n'importe où rompt la chaîne à cet événement. Les événements antérieurs au hachage forment un préfixe non haché, que le rapport signale.

POST /v1/runs/{runId}/receipt est une déclaration signée de l'exécution : projet, suite et version, statut et résultat, chaque verdict, le nombre d'événements et la tête de la chaîne, signée sur son JSON canonique. GET /v1/evidence/keys publie les clés de signature par identifiant. Le paquet comme le reçu portent la clé avec laquelle ils ont été signés, si bien qu'ils se vérifient n'importe où :

ironfang rig evidence verify ironfang-rig-$RUN_ID.zip --key <base64 public key>
ironfang rig receipt $RUN_ID --key <base64 public key>

La commande verify contrôle l'empreinte de chaque fichier par rapport au manifeste, recalcule la chaîne à partir de events.json et vérifie la signature ; avec --key, la signature doit provenir d'une clé en laquelle vous avez confiance, sans cette option c'est la clé portée par le paquet qui est utilisée, et le rapport le signale. Le code de sortie 3 signifie qu'une vérification a échoué.

La conservation supprime les charges utiles après 7 jours et les exécutions après 90. PUT /v1/runs/{runId}/hold avec { "until": "..." } (au plus un an à l'avance) conserve une exécution et tout ce qu'elle a enregistré jusqu'à cette date ; DELETE lève le gel. Les deux sont des événements sur la propre chronologie de l'exécution, retention.held et retention.released.

ironfang rig evidence $RUN_ID -o checkout-$RUN_ID.zip
# prints the bundle's SHA-256

Ligne de commande

ironfang rig est un binaire statique unique pour Linux, macOS et Windows, publié avec un fichier de sommes de contrôle SHA-256 par version sur la page des versions. Il lit la clé dans IRONFANG_API_KEY ou --api-key-file, jamais dans un argument, et s'adresse à https://api.ironfang.uk/rig sauf si IRONFANG_API_URL indique autre chose.

ironfang rig sync     [-f ironfang.rig.yaml]
ironfang rig run      [-f file] [--ttl 30m] [--external-id id] [--output text|env|github|json] [-- command args...]
ironfang rig finish   <run-id> [--outcome pass|fail|none] [--reason text]
ironfang rig status   <run-id>
ironfang rig events   <run-id> [--since 0] [--json]
ironfang rig wait     <run-id> --type <event type> [--resource name] [--match key=value]... [--since 0] [--timeout 30s]
ironfang rig evidence <run-id> [-o ironfang-rig-<run-id>.zip]
ironfang rig replay   <run-id> <event-id>
ironfang rig version

run synchronise la suite, démarre une exécution et affiche ses adresses. Avec une commande après --, il exécute cette commande avec IRONFANG_RIG_RUN_ID et une variable IRONFANG_RIG_<RESOURCE> par ressource, puis termine l'exécution. --output env affiche ces affectations pour qu'un shell les charge ; --output github les écrit dans les sorties et l'environnement du job.

Code de sortieSignification
0Succès ; pour run et finish, le résultat de l'exécution n'est pas fail.
1Une erreur en communiquant avec l'API ou le système de fichiers.
2Usage incorrect : un argument manquant ou une option invalide.
3La commande après -- a échoué, ou le résultat de l'exécution est fail.
4wait n'a vu aucun événement correspondant avant son délai.

GitHub Actions

Deux actions composites du dépôt public ironfang-ltd/rig-action encapsulent la CLI. start synchronise le fichier de suite, démarre une exécution et exporte ses adresses comme sorties d'étape et variables d'environnement du job ; finish termine l'exécution, affiche les verdicts et fait échouer l'étape quand le résultat est fail. Stockez la clé comme secret du dépôt.

jobs:
  integration:
    runs-on: ubuntu-latest
    env:
      IRONFANG_API_KEY: ${{ secrets.IRONFANG_API_KEY }}
    steps:
      - uses: actions/checkout@v4
      - id: test
        uses: ironfang-ltd/rig-action/start@v1
        with:
          suite-file: ironfang.rig.yaml
          ttl: 20m
      - run: npm test
        # IRONFANG_RIG_RUN_ID and IRONFANG_RIG_<RESOURCE> are in the environment
      - if: always()
        uses: ironfang-ltd/rig-action/finish@v1
        with:
          run-id: ${{ steps.test.outputs.run_id }}
EntréeActionRemarques
suite-filestartChemin du fichier de suite. Par défaut ironfang.rig.yaml.
ttlstartDurée de vie de l'exécution, de 1m à 24h. Par défaut, celle de la suite.
external-idstartVotre référence pour l'exécution. Par défaut, l'identifiant de l'exécution du workflow.
run-idfinishObligatoire. La sortie run_id de l'étape start.
outcomefinishpass, fail ou none pour remplacer les verdicts. Par défaut, le résultat déduit.
fail-onfinishfail (par défaut) ou never.
version, binaryles deuxLa version de ironfang rig à télécharger et à vérifier par rapport à ses sommes de contrôle (par défaut : la version avec laquelle l'action a été publiée), ou le chemin d'un binaire préconstruit.

L'étape start expose aussi resources, un objet JSON associant chaque nom de ressource à son adresse, pour les étapes qui préfèrent le lire comme des données.

Outils MCP

Le serveur MCP Ironfang expose le même produit aux assistants de code, pour qu'un agent puisse démarrer une exécution, lire la chronologie, armer une panne et exporter les preuves sans quitter l'éditeur. Chaque outil est rattaché à l'organisation de la connexion et ne coûte aucun crédit. Les outils qui créent ou modifient quelque chose l'indiquent dans leurs métadonnées.

OutilPortéeRôle
rig.project.list, rig.project.createrig:read, rig:writeLister les projets ; en créer un par slug.
rig.suite.list, rig.suite.get, rig.suite.upsertrig:read, rig:writeLire les suites et leur définition courante ; en créer ou en réviser une à partir d'une définition.
rig.run.create, rig.run.get, rig.run.finish, rig.run.cancelrig:run, rig:readDémarrer une exécution et recevoir ses adresses ; la lire ; la terminer pour obtenir les verdicts ; l'annuler.
rig.resource.createrig:runAllouer une ressource de plus sur une exécution active.
rig.event.list, rig.event.waitrig:readParcourir la chronologie page par page ; attendre un événement correspondant.
rig.event.replayrig:runRejouer un callback enregistré vers sa route.
rig.fault.add, rig.fault.removerig:runArmer et désarmer des pannes.
rig.connector.prepare, rig.connector.statusrig:connector, rig:readCréer un connecteur et recevoir la commande à lancer en local ; voir quels connecteurs sont en ligne et ce qui attend.
rig.evidence.export, rig.evidence.receiptrig:readLe manifeste de preuves et où télécharger le paquet, ainsi qu'un reçu signé de ce que l'exécution a fait.

Les octets de charge utile ne sont jamais renvoyés par la connexion ; les outils renvoient ce que la chronologie a enregistré et renvoient vers l'API pour le reste.

Limites et conservation

LimiteValeur
Durée de vie d'une exécutionDe 1 minute à 24 heures ; 30 minutes par défaut
Ressources par suite32
Attendus par suite64, jusqu'à 16 clés de match chacun
Messages par boîte de réception et par exécution500, chacun jusqu'à 10 MiB
Callbacks par exécution1000, corps jusqu'à 64 KiB chacun
Appels de mock par exécution5000 ; 32 règles, corps de 64 KiB et délai de 10 secondes par règle
Pannes par exécution64 ; délai jusqu'à 30 secondes ; jusqu'à 5 copies en double ; count jusqu'à 100
Connecteurs par exécution16 ; délai local de 30 secondes par livraison ; trames de 256 KiB
Rejeux par exécution200
Attentes ouvertes par organisation16 ; délais de 1 à 90 secondes
Événements par page500
Paquet de preuves10 000 événements et 256 MiB de charges utiles
Conservation des charges utiles7 jours après la fin de l'exécution
Conservation des exécutions90 jours après la fin de l'exécution, puis l'exécution et sa chronologie sont supprimées

Exportez le paquet de preuves avant que la conservation ne s'applique si une exécution doit lui survivre. Les suites, leurs versions et les projets persistent.

Référence de l'API

URL de base https://api.ironfang.uk/rig. Le document OpenAPI 3.1 à https://api.ironfang.uk/rig/openapi.yaml contient chaque schéma, exemple et erreur, avec des identifiants d'opération stables pour les clients générés. Les identifiants sont des UUID ; les listes se paginent avec cursor et limit (jusqu'à 100).

EndpointPortéeRôle
GET /v1/projectsrig:readLister les projets.
POST /v1/projectsrig:writeCréer un projet par slug.
GET /v1/projects/{projectId}rig:readObtenir un projet.
GET /v1/suitesrig:readLister les suites, éventuellement par projet.
POST /v1/suitesrig:writeCréer une suite avec sa première version.
GET /v1/suites/{suiteId}rig:readObtenir une suite avec sa version courante.
PUT /v1/suites/{suiteId}rig:writeRéviser la définition ; une définition inchangée ne crée pas de nouvelle version.
GET /v1/suites/{suiteId}/versionsrig:readLister les versions d'une suite.
POST /v1/suites/{suiteId}/runsrig:runDémarrer une exécution et allouer ses ressources. Respecte Idempotency-Key.
GET /v1/runsrig:readLister les exécutions, les plus récentes en premier.
GET /v1/runs/{runId}rig:readObtenir une exécution.
POST /v1/runs/{runId}/finishrig:runTerminer l'exécution et évaluer ses attendus.
POST /v1/runs/{runId}/cancelrig:runAnnuler l'exécution sans verdict.
GET /v1/runs/{runId}/resourcesrig:readLister les ressources de l'exécution avec leurs adresses.
POST /v1/runs/{runId}/resourcesrig:runAllouer une ressource de plus.
PUT /v1/runs/{runId}/resources/{resourceId}/mockrig:runRemplacer les règles d'un mock.
GET /v1/runs/{runId}/faultsrig:readLister les pannes de l'exécution et le nombre de déclenchements de chacune.
POST /v1/runs/{runId}/faultsrig:runArmer une panne.
DELETE /v1/runs/{runId}/faults/{faultId}rig:runDésarmer une panne.
GET /v1/runs/{runId}/connectorsrig:readLister les connecteurs et les livraisons en attente.
POST /v1/runs/{runId}/connectorsrig:connectorCréer un connecteur et son jeton d'amorçage.
GET /v1/runs/{runId}/eventsrig:readLire la chronologie à partir de since.
POST /v1/runs/{runId}/waitrig:readAttendre un événement correspondant.
GET /v1/runs/{runId}/events/{eventId}rig:readObtenir un événement.
GET /v1/runs/{runId}/events/{eventId}/payloadrig:readTélécharger les octets de charge utile d'un événement.
POST /v1/runs/{runId}/events/{eventId}/replayrig:runRejouer un callback enregistré.
POST /v1/runs/{runId}/evidencerig:readExporter le paquet de preuves ou son manifeste.
GET /v1/usagerig:readExécutions et événements sur une période, depuis le début du mois par défaut.
GET /v1/environmentrig:readHôtes, passerelle, version du connecteur, chaque limite et les durées de conservation.
GET /v1/homerig:readCompteurs, étapes de mise en route et exécutions récentes, tels que le portail les affiche.

Interfaces pour machines

InterfaceDétails
Page produithttps://ironfang.uk/rig
Documentationhttps://ironfang.uk/rig/docs
URL de base de l'APIhttps://api.ironfang.uk/rig
Contrat OpenAPIhttps://api.ironfang.uk/rig/openapi.yaml. Le même contrat est servi en JSON à https://api.ironfang.uk/rig/openapi.json.
AuthentificationClé API de la plateforme comme jeton bearer
Erreurshttps://ironfang.uk/rig/docs#errors. Un corps JSON avec un code stable, un message, ce lien et l'identifiant de la requête.
MCPDisponible. Projets et suites, exécutions et leurs ressources, la chronologie et les attentes, le rejeu, les pannes déterministes, l'amorçage du connecteur local, les manifestes de preuves et les reçus signés. Les outils sont nommés rig.*. Référence du serveur MCP ; chaque outil et chaque schéma, sans jeton, à /.well-known/ironfang-mcp.json
Découverte/apis.json, /.well-known/api-catalog et /llms.txt