Audits · août 2026Audit — pilier marketplace

Audit — pilier marketplace

Huitieme tour de la rotation (docs/team/roster.md, @codebase-auditor). Lecture seule sur le code. Ce tour differe des six precedents : les six piliers restants ont ete audites en une passe, a la demande. La profondeur…

Huitieme tour de la rotation (docs/team/roster.md, @codebase-auditor).

Lecture seule sur le code. Ce tour differe des six precedents : les six piliers restants ont ete audites en une passe, a la demande. La profondeur par pilier est donc moindre, et chaque document dit ou il s'arrete. La sonde commune est la meme partout : les invariants que le roster declare pour le pilier, parce que six tours ont montre que c'est la que l'ecart se loge.

Perimetre : src/services/marketplace|sell|sponsor/**, routes marketplace, vendor et sell.

Etat du depot : origin/main a 3e23edb7, 27 aout 2026.

Ce qui a ete verifie

SondeResultat
Invariant — payout vendeur en escrow, jamais au checkoutrespecte
Appels de transfert Stripe hors du cron marketplace-payouts0
La fenetre de dispute est-elle une constante uniqueoui — DISPUTE_WINDOW_DAYS = 14
… importee par le cron de payoutoui
La fenetre est-elle verifiee cote serveur a l'ouverture d'une disputeoui

Aucun constat, et c'est le resultat

Le roster declare pour ce pilier :

« Le payout vendeur est en escrow jusqu'a la fin de la fenetre de dispute (14j), verse par le cron marketplace-payouts : jamais au checkout. »

L'invariant tient, et il tient proprement :

  • DISPUTE_WINDOW_DAYS = 14 est declare une fois (services/marketplace/disputes.ts:25) et importe par le cron (api/cron/marketplace-payouts/route.ts:33). Les deux moities de la regle, « on refuse une dispute apres 14j » et « on paie apres 14j », lisent le meme nombre. C'est exactement ce que billing/0054 et integrations/0060 reprochaient a d'autres valeurs : ici, c'est fait.
  • grep sur transfers.create, transfer_data et application_fee dans services/marketplace, api/marketplace et api/vendor : aucune occurrence. Il n'existe pas de chemin qui transfere au vendeur en dehors du cron.
  • L'ouverture d'une dispute revalide la fenetre cote serveur (disputes.ts:95), donc un client ne peut pas la contourner en rejouant la requete.

Je n'ouvre pas d'item. La regle du role veut qu'un audit produise des items ; en produire un ici serait du remplissage, et le remplissage est ce qui fait qu'on cesse de lire les audits. Ce que ce document livre est une verification, datee et reproductible, de l'invariant le plus couteux du pilier : celui ou une erreur envoie l'argent d'un acheteur au mauvais moment.

Ce que cet audit n'a pas couvert

Beaucoup, et c'est le prix de la passe unique :

  • Stripe Connect — onboarding Express, account.updated, payout.failed : non ouverts.
  • KYC et signatures legales (V5.1) : non ouverts. Ce sont pourtant les surfaces qui manipulent de la PII chiffree.
  • Le calcul du montant transfere : cet audit verifie quand le payout part, jamais combien. Une erreur de montant serait invisible pour lui.
  • L'idempotence du cron de payout, la presence d'un garde-fou never transferred est ecrite dans l'en-tete du cron ; elle n'a pas ete exercee.
  • Les remboursements et l'arbitrage admin : non ouverts.

Un auditeur qui ne borne pas sa portee laisse croire qu'il a tout vu.