Aller au contenu principal

Patterns

Immutabilité du registre fiscal en PostgreSQL

INSERT-only avec triggers BEFORE UPDATE/DELETE

Le registre fiscal Scell.io (table `fiscal_entries`) doit être effectivement immuable : aucune mise à jour ni suppression possible une fois validé, conformément aux exigences ISCA de la DGFiP. Trois niveaux de défense en profondeur. (1) Niveau application : ISCA Guard Eloquent qui bloque toute mutation hors statut `draft`. (2) Niveau DB : trigger `BEFORE UPDATE OR DELETE` qui lève une exception si l'entrée est `validated`. (3) Niveau audit : tout tentative est loggée dans `fiscal_audit_logs` avec sévérité `critical`. La chaîne SHA-256 (chaque entrée hash inclut le hash précédent) rend toute falsification rétroactive immédiatement détectable via `GET /api/v1/fiscal/integrity`. Pattern complémentaire : révoquer le `UPDATE`/`DELETE` au niveau GRANT pour le rôle applicatif, ne donner ce droit qu'à un rôle `dba_emergency` utilisé exclusivement pour les correctifs de schéma (jamais pour modifier des données fiscales). Une suppression GDPR (droit à l'oubli) sur des PII non-fiscales se fait par anonymisation (NULL ou hash), pas par DELETE.

À retenir

  • 3 niveaux : ISCA Guard app + trigger DB + audit log
  • Trigger BEFORE UPDATE/DELETE leve exception sur entrée validated
  • GRANT révoqué côté applicatif, rôle dba_emergency séparé
  • Chaîne SHA-256 détecte toute falsification rétroactive
  • GDPR : anonymisation des PII non-fiscales, jamais DELETE

Exemple de code

-- 1. Trigger d'immutabilité au niveau DB
CREATE OR REPLACE FUNCTION prevent_fiscal_mutation()
RETURNS TRIGGER AS $$
BEGIN
  IF OLD.status = 'validated' THEN
    RAISE EXCEPTION 'Fiscal entry % is immutable (status=validated)', OLD.id
      USING ERRCODE = 'restrict_violation';
  END IF;
  RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER fiscal_entries_immutable
  BEFORE UPDATE OR DELETE ON fiscal_entries
  FOR EACH ROW EXECUTE FUNCTION prevent_fiscal_mutation();

-- 2. Révocation des droits côté applicatif
REVOKE UPDATE, DELETE ON fiscal_entries FROM scell_app;
GRANT  UPDATE, DELETE ON fiscal_entries TO   dba_emergency;

-- 3. Vérification d'intégrité de la chaîne SHA-256
SELECT id, prev_hash, hash,
  encode(sha256((id || prev_hash || data)::bytea), 'hex') AS computed
FROM fiscal_entries
WHERE encode(sha256((id || prev_hash || data)::bytea), 'hex') <> hash;
-- Doit retourner 0 lignes

Voir aussi

Vos préférences cookies

Nous utilisons des cookies pour améliorer votre expérience. Les cookies essentiels sont toujours actifs. Politique cookies.