Check DATA_ENCRYPTION_KEY at startup; launch skill: bad key broke order analytics (review 2.1.1)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
metatroncubeswdev 2026-10-30 22:35:24 -04:00
parent b7dfe00200
commit 752845302a
3 changed files with 8 additions and 0 deletions

View File

@ -299,3 +299,4 @@ Go to Partner Dashboard › Distribution › **App Store review**.
| Feature "doesn't work" in test | Test products out of stock or not in the collection | Use in-stock products; check the data before recording | | Feature "doesn't work" in test | Test products out of stock or not in the collection | Use in-stock products; check the data before recording |
| Chrome tab "hidden" or screenshot timeouts | Window minimised or not visible | Bring the window forward or open a new tab group; read state with JS | | Chrome tab "hidden" or screenshot timeouts | Window minimised or not visible | Bring the window forward or open a new tab group; read state with JS |
| Review 1.2.2 "fails to register the plan" | App Pricing (enrolled after April 2026) does not populate `currentAppInstallation.activeSubscriptions` or send billing webhooks | Read the plan from the Partner API `activeSubscription(appId, shopId)` (client with "Manage apps"); in the `/app` root loader redirect shops with no subscription **or `cancelAtEndOfCycle: true`** (an uninstall keeps a prepaid period running, so a reinstall still returns a subscription) to `admin.shopify.com/store/<store>/charges/<handle>/pricing_plans` (`target: "_top"`); show `pendingUpdate` (yearly downgrades apply at cycle end); never redirect on API errors | | Review 1.2.2 "fails to register the plan" | App Pricing (enrolled after April 2026) does not populate `currentAppInstallation.activeSubscriptions` or send billing webhooks | Read the plan from the Partner API `activeSubscription(appId, shopId)` (client with "Manage apps"); in the `/app` root loader redirect shops with no subscription **or `cancelAtEndOfCycle: true`** (an uninstall keeps a prepaid period running, so a reinstall still returns a subscription) to `admin.shopify.com/store/<store>/charges/<handle>/pricing_plans` (`target: "_top"`); show `pendingUpdate` (yearly downgrades apply at cycle end); never redirect on API errors |
| Review 2.1.1 "orders not updated in analytics" | `DATA_ENCRYPTION_KEY` was 48 hex chars (`openssl rand -hex 24`), so every `orders/create` webhook threw and returned 500 | Generate with `openssl rand -hex 32` (64 chars); validate the key at startup so the container fails loudly; after any deploy, place one test order and confirm the webhook returns 200 |

View File

@ -6,8 +6,10 @@ import { type EntryContext } from "react-router";
import { isbot } from "isbot"; import { isbot } from "isbot";
import { addDocumentResponseHeaders } from "./shopify.server"; import { addDocumentResponseHeaders } from "./shopify.server";
import { startScheduler } from "./lib/scheduler.server"; import { startScheduler } from "./lib/scheduler.server";
import { assertEncryptionKey } from "./lib/crypto.server";
// Re-publishes offer configurations at every start/end boundary (brief §11.5). // Re-publishes offer configurations at every start/end boundary (brief §11.5).
if (process.env.NODE_ENV === "production") assertEncryptionKey();
startScheduler(); startScheduler();
export const streamTimeout = 5000; export const streamTimeout = 5000;

View File

@ -8,6 +8,11 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes }
let keys: { enc: Buffer; mac: Buffer } | null = null; let keys: { enc: Buffer; mac: Buffer } | null = null;
/** Fails fast at startup: a bad key would otherwise only surface as 500s on every orders/create webhook. */
export function assertEncryptionKey() {
getKeys();
}
function getKeys() { function getKeys() {
if (keys) return keys; if (keys) return keys;
const hex = process.env.DATA_ENCRYPTION_KEY || ""; const hex = process.env.DATA_ENCRYPTION_KEY || "";