Créer le schéma SQLite et le DAO des preuves #46

Closed
opened 2026-07-18 17:07:30 +02:00 by fy59 · 0 comments
Owner

Créer le schéma SQLite et le DAO des preuves

Contexte

Labfy Investigation dispose maintenant d’un modèle métier opaque EvidenceRecord.

Le modèle représente une preuve numérique sans dépendre :

  • de GTK ;
  • de SQLite ;
  • du système de fichiers ;
  • du calcul d’empreinte ;
  • de la copie des fichiers.

L’étape suivante consiste à rendre ces enregistrements persistants dans la base SQLite de l’enquête.

Ce ticket ajoute :

EvidenceRecord
→ table SQLite evidence
→ EvidenceDao

Le calcul SHA-256, la copie sûre et l’import depuis l’interface restent hors périmètre.

Objectif

Créer une table SQLite dédiée aux preuves et un DAO capable de :

  • insérer un EvidenceRecord ;
  • charger une preuve par son identifiant ;
  • lister les preuves ;
  • compter les preuves ;
  • détecter les conflits d’identifiant ou de chemin ;
  • reconstruire un EvidenceRecord valide depuis SQLite ;
  • ne jamais exposer directement sqlite3_stmt au reste de l’application.

Le DAO ne doit contenir aucune logique GTK ni aucune opération de fichier.


1. Architecture

Créer de préférence :

include/database/evidence_dao.h
src/database/evidence_dao.c
tests/test_evidence_dao.c

Adapter les chemins seulement si le projet utilise déjà un autre dossier pour les DAO.

Le schéma doit être ajouté au mécanisme existant d’initialisation ou de migration SQLite.

Ne pas exécuter un CREATE TABLE caché dans une fonction d’insertion.


2. Table SQLite

Créer une table :

CREATE TABLE evidence (
    identifier TEXT PRIMARY KEY NOT NULL,
    original_name TEXT NOT NULL,
    internal_name TEXT NOT NULL,
    relative_path TEXT NOT NULL UNIQUE,
    type_identifier TEXT NOT NULL,
    size_bytes INTEGER NOT NULL CHECK (size_bytes >= 0),
    sha256 TEXT NOT NULL,
    imported_at TEXT NOT NULL,
    collected_at TEXT,
    source TEXT,
    description TEXT,
    integrity_status INTEGER NOT NULL
);

Le nom exact peut être adapté aux conventions du schéma existant, mais les informations doivent rester équivalentes.

Contraintes obligatoires

La table doit garantir au minimum :

identifier       NOT NULL + PRIMARY KEY
original_name    NOT NULL
internal_name    NOT NULL
relative_path    NOT NULL + UNIQUE
type_identifier  NOT NULL
size_bytes       NOT NULL + >= 0
sha256           NOT NULL
imported_at      NOT NULL
integrity_status NOT NULL

Ajouter des contraintes SQLite lorsque cela reste lisible et fiable :

CHECK (length(sha256) = 64)
CHECK (integrity_status BETWEEN 0 AND 4)

Le DAO doit continuer à valider les données via EvidenceRecord.

Choix volontaire

sha256 ne doit pas être UNIQUE.

Deux enregistrements peuvent représenter le même contenu provenant de sources ou de contextes différents.

La détection de doublons sera traitée dans le service d’import.


3. Migration et idempotence

L’initialisation du schéma doit être idempotente.

Ouvrir plusieurs fois la même enquête ne doit pas :

  • recréer la table ;
  • supprimer des données ;
  • dupliquer des colonnes ;
  • provoquer une erreur.

Utiliser le mécanisme de migration déjà présent dans le projet.

S’il n’existe pas encore, ce ticket doit introduire une version de schéma explicite, par exemple avec :

PRAGMA user_version;

Une migration doit être exécutée dans une transaction.

En cas d’échec :

ROLLBACK
aucune modification partielle
erreur GLib lisible

4. Type opaque EvidenceDao

Déclarer :

typedef struct EvidenceDao EvidenceDao;

Le DAO emprunte la connexion ou le composant Database existant.

Il ne doit pas ouvrir une seconde connexion SQLite indépendante lorsque la session possède déjà une connexion active.

Le nom du type de connexion doit suivre le module actuel du projet.


5. Erreurs

Définir :

typedef enum
{
    EVIDENCE_DAO_ERROR_INVALID_ARGUMENT,
    EVIDENCE_DAO_ERROR_PREPARE,
    EVIDENCE_DAO_ERROR_BIND,
    EVIDENCE_DAO_ERROR_EXECUTE,
    EVIDENCE_DAO_ERROR_CONSTRAINT,
    EVIDENCE_DAO_ERROR_READ,
    EVIDENCE_DAO_ERROR_MODEL,
    EVIDENCE_DAO_ERROR_SCHEMA
} EvidenceDaoError;

Ajouter :

#define EVIDENCE_DAO_ERROR \
    evidence_dao_error_quark()

GQuark evidence_dao_error_quark(void);

Les messages doivent conserver le contexte SQLite sans exposer des informations inutiles à l’utilisateur final.


6. Constructeur et destruction

API indicative :

EvidenceDao *evidence_dao_new(
    Database *database,
    GError **error
);

void evidence_dao_free(
    EvidenceDao *evidence_dao
);

Règles :

  • database est emprunté ;
  • EvidenceDao ne détruit pas la base ;
  • la base doit rester valide pendant la vie du DAO ;
  • evidence_dao_free(NULL) est accepté.

Adapter Database au type réel déjà utilisé par le projet.


7. Insertion

Ajouter :

gboolean evidence_dao_insert(
    EvidenceDao *evidence_dao,
    const EvidenceRecord *evidence_record,
    GError **error
);

Le DAO doit utiliser une requête préparée :

INSERT INTO evidence (
    identifier,
    original_name,
    internal_name,
    relative_path,
    type_identifier,
    size_bytes,
    sha256,
    imported_at,
    collected_at,
    source,
    description,
    integrity_status
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);

Règles :

  • utiliser les fonctions sqlite3_bind_* ;
  • ne jamais construire la requête par concaténation ;
  • binder NULL pour les champs facultatifs absents ;
  • vérifier chaque code de retour ;
  • finaliser le statement sur tous les chemins ;
  • ne pas modifier le EvidenceRecord reçu ;
  • retourner une erreur claire en cas de conflit.

Les conflits suivants doivent être distinguables dans le message :

identifier déjà présent
relative_path déjà présent
autre contrainte SQLite

Aucune suppression ni mise à jour automatique ne doit être effectuée.


8. Recherche par identifiant

Ajouter :

EvidenceRecord *evidence_dao_find_by_identifier(
    EvidenceDao *evidence_dao,
    const char *identifier,
    GError **error
);

Comportement :

preuve trouvée     → nouvel EvidenceRecord
preuve absente     → NULL sans erreur
erreur SQLite      → NULL avec GError
ligne incohérente  → NULL avec EVIDENCE_DAO_ERROR_MODEL

Le modèle retourné appartient à l’appelant.

La requête doit être préparée :

SELECT
    identifier,
    original_name,
    internal_name,
    relative_path,
    type_identifier,
    size_bytes,
    sha256,
    imported_at,
    collected_at,
    source,
    description,
    integrity_status
FROM evidence
WHERE identifier = ?;

9. Liste des preuves

Ajouter :

GPtrArray *evidence_dao_list_all(
    EvidenceDao *evidence_dao,
    GError **error
);

Le tableau doit :

  • être possédé par l’appelant ;
  • utiliser evidence_record_free comme fonction de destruction ;
  • être vide lorsque la table ne contient aucune preuve ;
  • ne jamais contenir de pointeur NULL.

Ordre initial :

ORDER BY imported_at ASC, identifier ASC

Chaque ligne doit être reconstruite avec evidence_record_new().

Une ligne invalide doit faire échouer toute la lecture plutôt que retourner une liste partielle silencieuse.


10. Comptage

Ajouter :

gboolean evidence_dao_count(
    EvidenceDao *evidence_dao,
    guint64 *out_count,
    GError **error
);

Requête :

SELECT COUNT(*) FROM evidence;

Règles :

  • out_count est obligatoire ;
  • initialiser *out_count à 0 avant la requête ;
  • vérifier le type et la plage de la valeur SQLite.

11. Immutabilité des preuves

Ce ticket ne doit pas ajouter :

update générique
delete générique
replace
insert or replace
upsert

Une preuve enregistrée ne doit pas être écrasée silencieusement.

Les futures modifications d’intégrité ou de description devront passer par des opérations métier explicites et auditées.


12. Conversion SQLite vers modèle

Créer une fonction privée centralisée, par exemple :

static EvidenceRecord *evidence_dao_read_record(
    sqlite3_stmt *statement,
    GError **error
);

Elle doit :

  • lire les 12 colonnes ;
  • gérer correctement les colonnes facultatives NULL ;
  • vérifier que size_bytes est positif ou nul ;
  • convertir le statut SQLite vers EvidenceIntegrityStatus ;
  • appeler evidence_record_new() ;
  • propager une erreur si la ligne est incohérente.

Ne pas dupliquer ce code dans find et list.


13. Transactions

Une insertion simple peut être exécutée sans transaction explicite si elle ne modifie qu’une seule ligne.

Le futur service d’import utilisera une transaction englobant :

copie du fichier
+ insertion SQLite
+ éventuel journal

Le DAO ne doit donc pas démarrer ou valider une transaction de manière cachée dans evidence_dao_insert().

Il doit fonctionner lorsqu’une transaction externe est déjà active.


14. Tests attendus

Utiliser une base temporaire dédiée aux tests.

Ajouter au minimum :

  1. création du DAO avec une base valide ;
  2. refus d’une base NULL ;
  3. table evidence présente après initialisation ;
  4. initialisation du schéma deux fois ;
  5. insertion valide ;
  6. insertion avec champs facultatifs NULL ;
  7. insertion d’un fichier de taille zéro ;
  8. récupération par identifiant ;
  9. preuve absente sans erreur ;
  10. chaînes indépendantes après relecture ;
  11. liste vide ;
  12. liste de plusieurs preuves ;
  13. ordre de la liste ;
  14. comptage à zéro ;
  15. comptage après plusieurs insertions ;
  16. conflit d’identifiant ;
  17. conflit de chemin relatif ;
  18. même SHA-256 accepté pour deux preuves ;
  19. statut d’intégrité conservé ;
  20. ligne SQLite invalide refusée par le modèle ;
  21. statement finalisé après une erreur ;
  22. evidence_dao_free(NULL) ;
  23. GError facultatif ;
  24. tous les anciens tests restent valides.

Les tests ne doivent utiliser aucune interface GTK.


15. Base temporaire

Ne pas utiliser la base d’une vraie enquête.

Créer une base temporaire avec les utilitaires GLib, puis la supprimer à la fin du test.

Les tests doivent être indépendants :

un test ne dépend pas d’une donnée créée par un autre test

Privilégier une fixture lorsque cela simplifie la création et la destruction de la base.


16. Propriété mémoire

DAO

possède sa structure privée
emprunte Database
ne possède aucun EvidenceRecord transmis

Insertion

EvidenceRecord reçu → emprunté

Recherche

EvidenceRecord retourné → possédé par l’appelant

Liste

GPtrArray retourné → possédé par l’appelant
EvidenceRecord contenus → possédés par le tableau

Toutes les requêtes préparées doivent être finalisées sur chaque chemin de sortie.


17. Hors périmètre

Ne pas ajouter dans ce ticket :

  • calcul SHA-256 ;
  • copie d’un fichier ;
  • accès à GFile ;
  • dialogue GTK ;
  • sélection de fichier ;
  • aperçu d’une preuve ;
  • modification ou suppression d’une preuve ;
  • extraction de métadonnées ;
  • journal de chaîne de conservation ;
  • relations entre entités ;
  • détection automatique du type de preuve.

18. Audit de sécurité

Aucune requête ne doit être construite avec :

g_strdup_printf()
sprintf()
snprintf()

pour y injecter des données utilisateur.

Cette commande doit confirmer l’utilisation de statements préparés :

rg -n \
    'sqlite3_prepare|sqlite3_bind|sqlite3_step|sqlite3_finalize' \
    src/database/evidence_dao.c

Cette commande ne doit trouver aucune concaténation de valeur dans du SQL :

rg -n \
    'INSERT.*%|SELECT.*%|UPDATE.*%|DELETE.*%' \
    src/database/evidence_dao.c

19. Audit d’architecture

Cette commande ne doit rien afficher :

rg -n \
    '#include <gtk|Gtk|application_|main_window_|workspace_' \
    include/database/evidence_dao.h \
    src/database/evidence_dao.c

Cette commande ne doit rien afficher :

rg -n \
    'GFile|g_file_|open\\(|read\\(|write\\(|stat\\(' \
    include/database/evidence_dao.h \
    src/database/evidence_dao.c

20. Critères d’acceptation

  • La table evidence est créée par le mécanisme de schéma.
  • L’initialisation du schéma est idempotente.
  • Une migration échouée ne laisse aucun état partiel.
  • EvidenceDao est opaque.
  • Le DAO emprunte la connexion existante.
  • L’insertion utilise un statement préparé.
  • Les champs facultatifs sont bindés avec NULL.
  • Les conflits d’identifiant et de chemin ne provoquent aucun écrasement.
  • Un même SHA-256 peut être enregistré plusieurs fois.
  • La recherche par identifiant reconstruit un EvidenceRecord.
  • Une preuve absente retourne NULL sans erreur.
  • La liste possède ses modèles.
  • La liste est ordonnée de manière déterministe.
  • Le comptage fonctionne.
  • Aucune API générique de suppression ou modification n’est ajoutée.
  • Aucun accès GTK ou fichier n’est ajouté.
  • Tous les statements sont finalisés.
  • Tous les nouveaux tests passent.
  • Tous les anciens tests passent.
  • make réussit sans warning.
  • git diff --check ne remonte aucune erreur.
  • Valgrind ne détecte aucune perte directe ou indirecte dans le test ciblé.

21. Validation finale

make clean
make
make test
git diff --check

Puis :

G_DEBUG=gc-friendly \
G_SLICE=always-malloc \
valgrind \
    --leak-check=full \
    --show-leak-kinds=definite,indirect \
    --errors-for-leak-kinds=definite,indirect \
    --track-origins=yes \
    --error-exitcode=1 \
    ./tests/test_evidence_dao

Résultat attendu :

definitely lost: 0 bytes
indirectly lost: 0 bytes
ERROR SUMMARY: 0 errors

22. Fichiers concernés

Les chemins exacts doivent suivre l’organisation existante du module SQLite.

Fichiers attendus :

include/database/evidence_dao.h
src/database/evidence_dao.c
tests/test_evidence_dao.c
Makefile

Ainsi que le ou les fichiers existants responsables :

du schéma SQLite
des migrations
de la version de base

Aucun fichier GTK ne doit être modifié.


Résultat attendu

À la fin du ticket, une enquête peut conserver et relire des EvidenceRecord dans sa base SQLite.

Le ticket suivant ajoutera le calcul SHA-256 d’un fichier sans encore l’importer.

# Créer le schéma SQLite et le DAO des preuves ## Contexte Labfy Investigation dispose maintenant d’un modèle métier opaque `EvidenceRecord`. Le modèle représente une preuve numérique sans dépendre : - de GTK ; - de SQLite ; - du système de fichiers ; - du calcul d’empreinte ; - de la copie des fichiers. L’étape suivante consiste à rendre ces enregistrements persistants dans la base SQLite de l’enquête. Ce ticket ajoute : ```text EvidenceRecord → table SQLite evidence → EvidenceDao ``` Le calcul SHA-256, la copie sûre et l’import depuis l’interface restent hors périmètre. ## Objectif Créer une table SQLite dédiée aux preuves et un DAO capable de : - insérer un `EvidenceRecord` ; - charger une preuve par son identifiant ; - lister les preuves ; - compter les preuves ; - détecter les conflits d’identifiant ou de chemin ; - reconstruire un `EvidenceRecord` valide depuis SQLite ; - ne jamais exposer directement `sqlite3_stmt` au reste de l’application. Le DAO ne doit contenir aucune logique GTK ni aucune opération de fichier. --- # 1. Architecture Créer de préférence : ```text include/database/evidence_dao.h src/database/evidence_dao.c tests/test_evidence_dao.c ``` Adapter les chemins seulement si le projet utilise déjà un autre dossier pour les DAO. Le schéma doit être ajouté au mécanisme existant d’initialisation ou de migration SQLite. Ne pas exécuter un `CREATE TABLE` caché dans une fonction d’insertion. --- # 2. Table SQLite Créer une table : ```sql CREATE TABLE evidence ( identifier TEXT PRIMARY KEY NOT NULL, original_name TEXT NOT NULL, internal_name TEXT NOT NULL, relative_path TEXT NOT NULL UNIQUE, type_identifier TEXT NOT NULL, size_bytes INTEGER NOT NULL CHECK (size_bytes >= 0), sha256 TEXT NOT NULL, imported_at TEXT NOT NULL, collected_at TEXT, source TEXT, description TEXT, integrity_status INTEGER NOT NULL ); ``` Le nom exact peut être adapté aux conventions du schéma existant, mais les informations doivent rester équivalentes. ## Contraintes obligatoires La table doit garantir au minimum : ```text identifier NOT NULL + PRIMARY KEY original_name NOT NULL internal_name NOT NULL relative_path NOT NULL + UNIQUE type_identifier NOT NULL size_bytes NOT NULL + >= 0 sha256 NOT NULL imported_at NOT NULL integrity_status NOT NULL ``` Ajouter des contraintes SQLite lorsque cela reste lisible et fiable : ```sql CHECK (length(sha256) = 64) CHECK (integrity_status BETWEEN 0 AND 4) ``` Le DAO doit continuer à valider les données via `EvidenceRecord`. ## Choix volontaire `sha256` ne doit pas être `UNIQUE`. Deux enregistrements peuvent représenter le même contenu provenant de sources ou de contextes différents. La détection de doublons sera traitée dans le service d’import. --- # 3. Migration et idempotence L’initialisation du schéma doit être idempotente. Ouvrir plusieurs fois la même enquête ne doit pas : - recréer la table ; - supprimer des données ; - dupliquer des colonnes ; - provoquer une erreur. Utiliser le mécanisme de migration déjà présent dans le projet. S’il n’existe pas encore, ce ticket doit introduire une version de schéma explicite, par exemple avec : ```sql PRAGMA user_version; ``` Une migration doit être exécutée dans une transaction. En cas d’échec : ```text ROLLBACK aucune modification partielle erreur GLib lisible ``` --- # 4. Type opaque `EvidenceDao` Déclarer : ```c typedef struct EvidenceDao EvidenceDao; ``` Le DAO emprunte la connexion ou le composant `Database` existant. Il ne doit pas ouvrir une seconde connexion SQLite indépendante lorsque la session possède déjà une connexion active. Le nom du type de connexion doit suivre le module actuel du projet. --- # 5. Erreurs Définir : ```c typedef enum { EVIDENCE_DAO_ERROR_INVALID_ARGUMENT, EVIDENCE_DAO_ERROR_PREPARE, EVIDENCE_DAO_ERROR_BIND, EVIDENCE_DAO_ERROR_EXECUTE, EVIDENCE_DAO_ERROR_CONSTRAINT, EVIDENCE_DAO_ERROR_READ, EVIDENCE_DAO_ERROR_MODEL, EVIDENCE_DAO_ERROR_SCHEMA } EvidenceDaoError; ``` Ajouter : ```c #define EVIDENCE_DAO_ERROR \ evidence_dao_error_quark() GQuark evidence_dao_error_quark(void); ``` Les messages doivent conserver le contexte SQLite sans exposer des informations inutiles à l’utilisateur final. --- # 6. Constructeur et destruction API indicative : ```c EvidenceDao *evidence_dao_new( Database *database, GError **error ); void evidence_dao_free( EvidenceDao *evidence_dao ); ``` Règles : - `database` est emprunté ; - `EvidenceDao` ne détruit pas la base ; - la base doit rester valide pendant la vie du DAO ; - `evidence_dao_free(NULL)` est accepté. Adapter `Database` au type réel déjà utilisé par le projet. --- # 7. Insertion Ajouter : ```c gboolean evidence_dao_insert( EvidenceDao *evidence_dao, const EvidenceRecord *evidence_record, GError **error ); ``` Le DAO doit utiliser une requête préparée : ```sql INSERT INTO evidence ( identifier, original_name, internal_name, relative_path, type_identifier, size_bytes, sha256, imported_at, collected_at, source, description, integrity_status ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); ``` Règles : - utiliser les fonctions `sqlite3_bind_*` ; - ne jamais construire la requête par concaténation ; - binder `NULL` pour les champs facultatifs absents ; - vérifier chaque code de retour ; - finaliser le statement sur tous les chemins ; - ne pas modifier le `EvidenceRecord` reçu ; - retourner une erreur claire en cas de conflit. Les conflits suivants doivent être distinguables dans le message : ```text identifier déjà présent relative_path déjà présent autre contrainte SQLite ``` Aucune suppression ni mise à jour automatique ne doit être effectuée. --- # 8. Recherche par identifiant Ajouter : ```c EvidenceRecord *evidence_dao_find_by_identifier( EvidenceDao *evidence_dao, const char *identifier, GError **error ); ``` Comportement : ```text preuve trouvée → nouvel EvidenceRecord preuve absente → NULL sans erreur erreur SQLite → NULL avec GError ligne incohérente → NULL avec EVIDENCE_DAO_ERROR_MODEL ``` Le modèle retourné appartient à l’appelant. La requête doit être préparée : ```sql SELECT identifier, original_name, internal_name, relative_path, type_identifier, size_bytes, sha256, imported_at, collected_at, source, description, integrity_status FROM evidence WHERE identifier = ?; ``` --- # 9. Liste des preuves Ajouter : ```c GPtrArray *evidence_dao_list_all( EvidenceDao *evidence_dao, GError **error ); ``` Le tableau doit : - être possédé par l’appelant ; - utiliser `evidence_record_free` comme fonction de destruction ; - être vide lorsque la table ne contient aucune preuve ; - ne jamais contenir de pointeur `NULL`. Ordre initial : ```sql ORDER BY imported_at ASC, identifier ASC ``` Chaque ligne doit être reconstruite avec `evidence_record_new()`. Une ligne invalide doit faire échouer toute la lecture plutôt que retourner une liste partielle silencieuse. --- # 10. Comptage Ajouter : ```c gboolean evidence_dao_count( EvidenceDao *evidence_dao, guint64 *out_count, GError **error ); ``` Requête : ```sql SELECT COUNT(*) FROM evidence; ``` Règles : - `out_count` est obligatoire ; - initialiser `*out_count` à `0` avant la requête ; - vérifier le type et la plage de la valeur SQLite. --- # 11. Immutabilité des preuves Ce ticket ne doit pas ajouter : ```text update générique delete générique replace insert or replace upsert ``` Une preuve enregistrée ne doit pas être écrasée silencieusement. Les futures modifications d’intégrité ou de description devront passer par des opérations métier explicites et auditées. --- # 12. Conversion SQLite vers modèle Créer une fonction privée centralisée, par exemple : ```c static EvidenceRecord *evidence_dao_read_record( sqlite3_stmt *statement, GError **error ); ``` Elle doit : - lire les 12 colonnes ; - gérer correctement les colonnes facultatives `NULL` ; - vérifier que `size_bytes` est positif ou nul ; - convertir le statut SQLite vers `EvidenceIntegrityStatus` ; - appeler `evidence_record_new()` ; - propager une erreur si la ligne est incohérente. Ne pas dupliquer ce code dans `find` et `list`. --- # 13. Transactions Une insertion simple peut être exécutée sans transaction explicite si elle ne modifie qu’une seule ligne. Le futur service d’import utilisera une transaction englobant : ```text copie du fichier + insertion SQLite + éventuel journal ``` Le DAO ne doit donc pas démarrer ou valider une transaction de manière cachée dans `evidence_dao_insert()`. Il doit fonctionner lorsqu’une transaction externe est déjà active. --- # 14. Tests attendus Utiliser une base temporaire dédiée aux tests. Ajouter au minimum : 1. création du DAO avec une base valide ; 2. refus d’une base `NULL` ; 3. table `evidence` présente après initialisation ; 4. initialisation du schéma deux fois ; 5. insertion valide ; 6. insertion avec champs facultatifs `NULL` ; 7. insertion d’un fichier de taille zéro ; 8. récupération par identifiant ; 9. preuve absente sans erreur ; 10. chaînes indépendantes après relecture ; 11. liste vide ; 12. liste de plusieurs preuves ; 13. ordre de la liste ; 14. comptage à zéro ; 15. comptage après plusieurs insertions ; 16. conflit d’identifiant ; 17. conflit de chemin relatif ; 18. même SHA-256 accepté pour deux preuves ; 19. statut d’intégrité conservé ; 20. ligne SQLite invalide refusée par le modèle ; 21. statement finalisé après une erreur ; 22. `evidence_dao_free(NULL)` ; 23. `GError` facultatif ; 24. tous les anciens tests restent valides. Les tests ne doivent utiliser aucune interface GTK. --- # 15. Base temporaire Ne pas utiliser la base d’une vraie enquête. Créer une base temporaire avec les utilitaires GLib, puis la supprimer à la fin du test. Les tests doivent être indépendants : ```text un test ne dépend pas d’une donnée créée par un autre test ``` Privilégier une fixture lorsque cela simplifie la création et la destruction de la base. --- # 16. Propriété mémoire ## DAO ```text possède sa structure privée emprunte Database ne possède aucun EvidenceRecord transmis ``` ## Insertion ```text EvidenceRecord reçu → emprunté ``` ## Recherche ```text EvidenceRecord retourné → possédé par l’appelant ``` ## Liste ```text GPtrArray retourné → possédé par l’appelant EvidenceRecord contenus → possédés par le tableau ``` Toutes les requêtes préparées doivent être finalisées sur chaque chemin de sortie. --- # 17. Hors périmètre Ne pas ajouter dans ce ticket : - calcul SHA-256 ; - copie d’un fichier ; - accès à `GFile` ; - dialogue GTK ; - sélection de fichier ; - aperçu d’une preuve ; - modification ou suppression d’une preuve ; - extraction de métadonnées ; - journal de chaîne de conservation ; - relations entre entités ; - détection automatique du type de preuve. --- # 18. Audit de sécurité Aucune requête ne doit être construite avec : ```c g_strdup_printf() sprintf() snprintf() ``` pour y injecter des données utilisateur. Cette commande doit confirmer l’utilisation de statements préparés : ```bash rg -n \ 'sqlite3_prepare|sqlite3_bind|sqlite3_step|sqlite3_finalize' \ src/database/evidence_dao.c ``` Cette commande ne doit trouver aucune concaténation de valeur dans du SQL : ```bash rg -n \ 'INSERT.*%|SELECT.*%|UPDATE.*%|DELETE.*%' \ src/database/evidence_dao.c ``` --- # 19. Audit d’architecture Cette commande ne doit rien afficher : ```bash rg -n \ '#include <gtk|Gtk|application_|main_window_|workspace_' \ include/database/evidence_dao.h \ src/database/evidence_dao.c ``` Cette commande ne doit rien afficher : ```bash rg -n \ 'GFile|g_file_|open\\(|read\\(|write\\(|stat\\(' \ include/database/evidence_dao.h \ src/database/evidence_dao.c ``` --- # 20. Critères d’acceptation - [x] La table `evidence` est créée par le mécanisme de schéma. - [x] L’initialisation du schéma est idempotente. - [x] Une migration échouée ne laisse aucun état partiel. - [x] `EvidenceDao` est opaque. - [x] Le DAO emprunte la connexion existante. - [x] L’insertion utilise un statement préparé. - [x] Les champs facultatifs sont bindés avec `NULL`. - [x] Les conflits d’identifiant et de chemin ne provoquent aucun écrasement. - [x] Un même SHA-256 peut être enregistré plusieurs fois. - [x] La recherche par identifiant reconstruit un `EvidenceRecord`. - [x] Une preuve absente retourne `NULL` sans erreur. - [x] La liste possède ses modèles. - [x] La liste est ordonnée de manière déterministe. - [x] Le comptage fonctionne. - [x] Aucune API générique de suppression ou modification n’est ajoutée. - [x] Aucun accès GTK ou fichier n’est ajouté. - [x] Tous les statements sont finalisés. - [x] Tous les nouveaux tests passent. - [x] Tous les anciens tests passent. - [x] `make` réussit sans warning. - [x] `git diff --check` ne remonte aucune erreur. - [x] Valgrind ne détecte aucune perte directe ou indirecte dans le test ciblé. --- # 21. Validation finale ```bash make clean make make test git diff --check ``` Puis : ```bash G_DEBUG=gc-friendly \ G_SLICE=always-malloc \ valgrind \ --leak-check=full \ --show-leak-kinds=definite,indirect \ --errors-for-leak-kinds=definite,indirect \ --track-origins=yes \ --error-exitcode=1 \ ./tests/test_evidence_dao ``` Résultat attendu : ```text definitely lost: 0 bytes indirectly lost: 0 bytes ERROR SUMMARY: 0 errors ``` --- # 22. Fichiers concernés Les chemins exacts doivent suivre l’organisation existante du module SQLite. Fichiers attendus : ```text include/database/evidence_dao.h src/database/evidence_dao.c tests/test_evidence_dao.c Makefile ``` Ainsi que le ou les fichiers existants responsables : ```text du schéma SQLite des migrations de la version de base ``` Aucun fichier GTK ne doit être modifié. --- # Résultat attendu À la fin du ticket, une enquête peut conserver et relire des `EvidenceRecord` dans sa base SQLite. Le ticket suivant ajoutera le calcul SHA-256 d’un fichier sans encore l’importer.
fy59 closed this issue 2026-07-18 19:20:45 +02:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: fy59/labfy-investigation#46
No description provided.