Přeskočit na obsah

Tiše zahozené porušení constraintu u error-as-value DB klientů

import { Aside } from ‘@astrojs/starlight/components’;

Webhook platební brány při chargebacku označuje objednávku stavem disputed. Handler doběhne, vrátí 200, activity log dostane záznam — vše vypadá zdravě. Objednávka ale v DB zůstane paid a může se normálně expedovat. Nikde žádná chyba.

Dvě věci se potkaly:

  1. DB check constraint neznal hodnotu, kterou kód zapisoval. Constraint vznikl dřív, hodnota disputed se do kódu přidala později a migrace se nedopsala (schéma driftovalo mimo repo).
  2. Klient vrací chyby jako hodnotu, ne výjimku. PostgREST/supabase-js vzor:
await db.from('orders')
.update({ payment_status: 'disputed' })
.eq('order_number', orderNumber);
// ŽÁDNÁ kontrola { error } → constraint violation zmizí beze stopy

await proběhne v pohodě, { error } v návratové hodnotě nikdo nečte, handler pokračuje. Na rozdíl od ORM s výjimkami tu neexistuje ŽÁDNÝ signál — ani crash, ani log.

const { error: updErr } = await db.from('orders')
.update({ payment_status: 'disputed' })
.eq('order_number', orderNumber);
if (updErr) console.error('failed to flag order disputed:', updErr.message);
// + rozšířit constraint o chybějící hodnotu (aditivní ALTER, se zálohou)
// + kritická notifikace adminovi nezávisle na DB zápisu (chargeback = člověk hned)

Jak se tomu vyvarovat v jiných systémech

Sekce “Jak se tomu vyvarovat v jiných systémech”
  • Detection: grep zápisů bez destrukturace erroru: await .*\.(update|insert|delete)\( na řádcích, kde výsledek není přiřazen, nebo přiřazení nedestrukturuje error. Zkřížit hodnoty stavových sloupců v kódu (.update({ status: / payment_status:) proti pg_get_constraintdef živé DB.
  • Anti-pattern: await db.from(...).update(...) jako statement (výsledek zahozen) v kritické cestě; enum/status hodnoty definované jen v kódu bez odpovídajícího constraintu v migracích.
  • Lepší přístup: tenký wrapper mustUpdate() který na {error} hází; CI check porovnávající status hodnoty v kódu se schema dumpem; u stavů s penězi navíc out-of-band alert (e-mail), který nezávisí na úspěchu DB zápisu.

Sister bugs / společníci

Sekce “Sister bugs / společníci”

Stejný vzor zabíjí: audit logy (insert s neexistujícím sloupcem = tichý no-op), usage-checky před mazáním (select na neexistující tabulku → “0 výskytů” → smaž), backfilly. Viz též [[rate-limit-guard-filtered-by-guessed-value]] — jiný druh “kód vypadá, že chrání, ale nikdy se nespustí”.

Přidal aiarchitekt.cz · 12. 6. 2026 2:00
Provozuje aiarchitekt.cz