Passer au contenu

    EXEMPLE : une entreprise fictive. Pas un client d'Adwaizer.

    Version française de l'exemple de rapport en anglais. Même contenu et mêmes chiffres que la version anglaise ; en cas d'écart, la version anglaise fait foi. Les noms de fichiers, les commandes, le code et les sorties de journal restent en anglais.

    Correctif d'application Shopify : rapport de préparation à l'examen et résumé du correctif pour Tidewell Restock Alerts (exemple)

    Préparé par : Adwaizer AI Consulting Inc. · Mandat : correction de bogue ou petite fonctionnalité dans une application Shopify, niveau Starter (un correctif dans une application, 6 jours ouvrables) · Version du rapport : exemple, octobre 2026

    Ce qu'est cette page. Voici le rapport de remise que le client conserve à la fin du correctif d'application Shopify. Tidewell Restock Alerts, son développeur Tidewell Apps et chaque personne, boutique, dépôt, commit et chiffre ci-dessous sont inventés pour montrer la forme et le niveau de détail ; rien de tout cela n'existe. Dans un vrai mandat, chaque ligne renvoie au dépôt du client, à sa pull request et à sa boutique de développement.

    Comment lire les preuves. Une « preuve » est ce qu'un réviseur peut ouvrir et vérifier : un fichier et une ligne dans le dépôt, le nom d'un test, une commande et sa sortie, ou un écran de la boutique de développement. Rien ici n'a été exécuté sur une vraie application.


    1. Sommaire

    Tidewell Restock Alerts est une application Shopify publique fictive qui envoie un courriel aux clients lorsqu'une variante de produit en rupture de stock est de nouveau disponible. Son développeur nous a demandé de corriger un seul bogue : certaines livraisons du webhook de confidentialité obligatoire customers/redact étaient rejetées avec un code HTTP 401, de sorte que la demande d'effacement d'un client pouvait rester sans réponse.

    • Le bogue : le gestionnaire du webhook vérifiait la signature X-Shopify-Hmac-SHA256 sur le corps JSON après l'avoir analysé puis resérialisé, et non sur le corps brut de la requête. Toute charge utile dont les octets changeaient à la resérialisation (noms non ASCII, caractères échappés, espacement différent des clés) échouait à la vérification.
    • Le correctif : les routes de webhook lisent maintenant les octets bruts du corps, vérifient la signature sur ces octets avec une comparaison à temps constant, et n'analysent le JSON qu'une fois la vérification réussie. Une fonction utilitaire partagée remplace trois copies de la vérification.
    • Le test : un nouveau test signe, sur ses octets bruts, une charge utile de référence contenant un nom de client non ASCII. Il échouait avec l'ancien code (401) et réussit avec la modification (200). La suite existante de 212 tests réussit toujours.
    • Préparation à l'examen : sur les 14 points de notre liste de vérification pour l'examen des applications Shopify, 10 sont conformes, 1 a été corrigé par cette modification, 2 exigent un correctif hors de cette portée et 1 ne s'applique pas (section 4).
    • Incidence côté Shopify : aucune étendue d'accès (access scope), aucun abonnement webhook, aucune facturation et aucune configuration d'extension n'a changé, donc aucun nouveau consentement des marchands n'est attendu. Le client publie une nouvelle version de l'application ; un nouvel examen par l'App Store n'est pas attendu pour un correctif côté serveur, mais c'est Shopify qui en décide, pas nous.

    2. Portée écrite (jour 1, convenue par écrit avant le travail)

    ÉlémentConvenu
    Le bogueLivraisons de customers/redact rejetées avec 401 pour certains clients ; observé dans les journaux de l'application pour 3 livraisons de test sur 20 dans la boutique de développement
    Comportement attenduChaque livraison de webhook authentique de Shopify réussit la vérification HMAC et reçoit un code de la série 200 ; une livraison avec une mauvaise signature est rejetée avec 401
    Fichiers modifiésapp/routes/webhooks.*.tsx (3 routes), un nouveau app/lib/verify-webhook.server.ts, des tests dans test/webhooks/
    Changements d'étendues d'accès, de webhooks, de facturation ou de configuration d'extensionAucun. shopify.app.toml n'est pas modifié
    Hors portéeLe changement de chargement d'App Bridge et les captures d'écran de la fiche trouvés lors de la vérification d'examen (section 4) ; les deux appels à l'API REST Admin ; toute modification de la boutique en production
    Vérifications d'acceptationLes quatre vérifications de la section 6

    3. Le correctif

    3.1 Bogue reproduit (jour 2)

    • Test en échec : test/webhooks/customers-redact.test.ts › "accepts a genuine delivery whose payload has non-ASCII characters". La référence est une charge utile customers/redact pour un client de test nommé « Zoë Ménard » (fictif), signée avec le secret de test de l'application de développement sur ses octets bruts.
    • Résultat avec l'ancien code : statut attendu 200, reçu 401.
    • Dans la boutique de développement tidewell-dev.myshopify.com (fictive, données de test seulement) : un client de test au nom accentué a été créé et une demande d'effacement a été déclenchée depuis l'interface administrateur de la boutique ; le journal de l'application affichait webhook hmac mismatch topic=customers/redact. Aucune boutique en production n'a été utilisée.
    • Cause racine : app/routes/webhooks.customers-redact.tsx appelait await request.json(), puis calculait le HMAC sur JSON.stringify(body). La resérialisation modifiait les caractères échappés, si bien que l'empreinte différait de celle de Shopify.

    3.2 Modification (jour 3-4)

    FichierModification
    app/lib/verify-webhook.server.ts (nouveau)Lit request.arrayBuffer(), calcule le HMAC-SHA256 avec le secret de l'application, le compare à l'en-tête avec crypto.timingSafeEqual et ne renvoie la charge utile analysée qu'en cas de correspondance
    app/routes/webhooks.customers-redact.tsx, webhooks.customers-data-request.tsx, webhooks.shop-redact.tsxUtilisent la fonction utilitaire ; répondent 401 en cas de non-correspondance, 200 une fois la tâche mise en file d'attente
    test/webhooks/*.test.tsNouveau test de la section 3.1, plus un test par route vérifiant qu'une mauvaise signature est rejetée avec 401

    Pull request : tidewell-apps/restock-alerts#58 (fictive). Diff : +74 / -41 lignes dans 6 fichiers.

    3.3 Vérifications effectuées sur la modification

    VérificationRésultat
    Nouveau test avec l'ancien codeÉchoue : 401, 200 attendu
    Nouveau test avec la modificationRéussit
    Suite complète (npm test)215 réussis, 0 en échec (212 existants + 3 nouveaux)
    Lint et vérification des types (npm run lint, npx tsc --noEmit)0 erreur
    Boutique de développement : demande d'effacement pour le client de test au nom accentuéLe journal de l'application affiche customers/redact accepted, réponse 200
    Boutique de développement : livraison avec un corps altéré (envoyée depuis un script local)Rejetée avec 401
    Session de révision distincte, par rapport à la portée écriteApprouvée ; aucun fichier hors de la portée n'a été modifié
    Analyse des commits à la recherche de secrets (gitleaks)Aucune fuite trouvée

    4. Tableau de préparation à l'examen

    Chaque point de notre liste de vérification gratuite (adwaizer.com/shopify-app-review-checklist), vérifié dans la boutique de développement et dans le dépôt au commit corrigé. Le statut est l'un de Conforme, Corrigé (par cette modification), À corriger (trouvé, hors de cette portée) ou Sans objet.

    #Point de la listeStatutPreuve qu'un réviseur verrait
    1OAuth s'exécute avant toute autre chose à l'installation et à la réinstallationConformeUne nouvelle installation et une désinstallation suivie d'une réinstallation dans la boutique de développement ouvrent toutes deux d'abord l'écran d'autorisation et mènent à l'accueil de l'application après acceptation ; app/shopify.server.ts utilise l'authentification du cadre d'application pour chaque route d'administration
    2L'application intégrée s'authentifie avec des jetons de sessionConformeauthenticate.admin(request) sur chaque loader et action de app/routes/app.* ; aucun témoin (cookie) d'authentification ni jeton en stockage local dans grep -rn "localStorage|document.cookie" app/
    3La dernière version d'App Bridge se charge depuis la balise script du CDN de ShopifyÀ corrigerapp/root.tsx charge App Bridge depuis une ancienne version du paquet npm, et non depuis la balise script du CDN comme premier script. Hors de cette portée ; chiffré comme élément distinct
    4Les trois webhooks de confidentialité obligatoires sont abonnés et reçoivent une réponseCorrigéshopify.app.toml déclare customers/data_request, customers/redact et shop/redact ; avec la modification, les trois répondent 200 aux livraisons authentiques (tests dans test/webhooks/, journal de la boutique de développement en 3.3)
    5Chaque webhook est vérifié avec sa signature HMACCorrigéLa fonction utilitaire partagée vérifie X-Shopify-Hmac-SHA256 sur le corps brut pour chaque route de webhook ; une livraison altérée est rejetée avec 401 (test "rejects a wrong signature" dans le fichier de test de chaque route)
    6Tous les frais passent par la facturation de ShopifySans objetL'application est gratuite et ne facture rien : aucun code ni forfait de facturation dans le dépôt, aucun frais dans l'historique de l'application de la boutique de développement
    7L'application ne demande que les étendues d'accès qu'elle utiliseConformeshopify.app.toml demande read_products, read_inventory, read_customers ; chacune correspond à une fonctionnalité (liste des variantes, webhook de niveau de stock, courriel du client à l'inscription) ; inchangé par ce correctif
    8L'accès aux données client protégées est demandé avant qu'elles soient luesConformeL'application conserve les courriels des clients pour les alertes ; le Partner Dashboard affiche la demande d'accès aux données client protégées approuvée pour le courriel (capture d'écran fournie par le client, puisque nous n'avions pas accès au Partner Dashboard)
    9Les nouvelles applications publiques appellent l'API GraphQL Admin, pas RESTConformeToutes les lectures de produits et de stocks utilisent l'API GraphQL Admin ; deux appels REST subsistent dans app/jobs/legacy-sync.server.ts, qui ne s'exécute que pour les boutiques installées avant le passage à GraphQL. Signalé au client ; hors de cette portée
    10Les fonctionnalités de la vitrine utilisent des extensions d'application de thèmeConformeLe bouton « Notify me » est un bloc d'application dans extensions/notify-button/ ; aucune écriture par l'Asset API et aucun ScriptTag dans le code
    11L'application s'installe et fonctionne sans erreurConformeInstallation, inscription à une alerte, réapprovisionnement et courriel d'alerte, désinstallation : aucun écran en échec et aucune erreur dans la console du navigateur dans la boutique de développement
    12L'application ne ralentit pas la vitrineConformePerformance Lighthouse sur la page produit de la boutique de développement (thème par défaut gratuit, mobile) : 81 sans l'application, 78 avec le bloc d'application, une baisse de 3 points
    13L'application est servie avec un certificat TLS valideConformeL'URL de l'application et le point de terminaison du webhook présentent tous deux un certificat valide, sans erreur dans le navigateur ni avec curl -v
    14La fiche ne décrit que ce que fait l'applicationÀ corrigerDeux captures d'écran de la fiche montrent une page de paramètres retirée dans une version antérieure. Hors de cette portée ; le client les remplace avant la prochaine mise à jour de la fiche

    Shopify met ses exigences à jour ; chaque point de la page de la liste de vérification renvoie à la page Shopify dont il provient. Ce tableau ne garantit pas l'approbation.


    5. Vérification Shopify de la modification (jour 5)

    QuestionRéponse
    Étendue d'accès ajoutée ou retirée?Non
    Les webhooks de confidentialité obligatoires reçoivent-ils toujours une réponse?Oui, les trois, y compris maintenant les charges utiles qui échouaient auparavant
    Vérifications HMAC du webhook et de session intactes ou toujours testées?Vérification HMAC réécrite et testée pour chaque route ; vérifications de session intactes
    Appel à l'API Admin retiré d'une version d'API prise en charge?Non
    Facturation touchée?Non (l'application n'en a pas)
    La configuration des extensions se déploie-t-elle toujours?Oui : shopify app info et la validation de la configuration sur l'application de développement n'ont montré aucun changement d'extension ni de configuration
    Publication d'une version de l'application ou nouvel examen par l'App Store?Le client publie une nouvelle version de l'application avec sa commande habituelle shopify app deploy. La modification est uniquement côté serveur, donc un nouvel examen par l'App Store n'est pas attendu ; c'est Shopify qui en décide

    6. Liste d'acceptation (pour le client)

    1. Le nouveau test échoue avec votre ancien code et réussit avec la modification (npm test -- test/webhooks).
    2. Votre suite de tests existante réussit toujours (npm test).
    3. Dans votre boutique de développement, une demande d'effacement pour un client au nom accentué reçoit une réponse 200.
    4. La vérification Shopify de la section 5 ne montre aucun changement d'étendue d'accès, de webhook, de facturation ou d'extension que la portée écrite ne nommait pas.

    Une vérification en échec est corrigée dans un délai de 5 jours ouvrables, sans frais.

    7. Étapes de publication que vous exécutez

    1. Révisez et fusionnez la pull request #58 dans votre dépôt.
    2. Déployez le serveur de l'application comme vous le faites d'habitude.
    3. Exécutez shopify app deploy pour publier la version de l'application (elle ne contient aucun changement de configuration ni d'extension).
    4. Surveillez le journal des webhooks de l'application pendant une journée : les livraisons de customers/redact ne devraient afficher que 200.

    Nous ne fusionnons, ne déployons, ne publions et ne soumettons jamais rien à Shopify à votre place, et nous ne touchons jamais à votre boutique en production.

    8. Trouvé mais non corrigé (pour une portée distincte)

    ÉlémentPourquoi c'est importantProchaine étape suggérée
    App Bridge depuis un ancien paquet npm (ligne 3)Shopify demande aux applications de l'App Store de charger la dernière version d'App Bridge depuis son CDNUn petit correctif : passer à la balise script du CDN et retester les écrans intégrés
    Captures d'écran de la fiche périmées (ligne 14)L'examen compare la fiche à l'application soumiseTâche du client : nouvelles captures d'écran de la page de paramètres actuelle
    Deux appels à l'API REST Admin (ligne 9)Ce n'est pas un obstacle à l'examen pour cette application aujourd'hui ; REST pourrait perdre des fonctionnalités avec le tempsMigrer legacy-sync vers GraphQL au moment opportun