fix: refuse modes de contrôle et versions de sauvegarde invalides (#74) #80

Merged
Reliodas merged 1 commit from feature/74-validate-save-data into develop 2026-06-22 11:13:09 +00:00
Owner

Closes #74.

Party.from_save_data() convertissait directement n'importe quel entier en ControlMode (une valeur 999 était acceptée) et tolérait un leader vide avec un groupe actif non vide (repli silencieux). GameState._party_from_snapshot() acceptait par ailleurs toute format_version >= 1 comme compatible. Ces données produisaient des membres impilotables ou chargeaient silencieusement un format inconnu. Deuxième correctif de l'audit 0.16.0.

Changements

  • scripts/party/party.gd from_save_data() :
    • valide control_mode{PLAYER, AUTO_ALLY, SCRIPTED_GUEST} (helper _is_valid_control_mode) avant de construire le membre ; sinon null ;
    • contrat de leader explicite : si le groupe actif est non vide, un leader_id nommé et valide est exigé ; s'il est vide, aucun leader ne doit être nommé. Plus de repli silencieux.
  • scripts/game_state.gd _party_from_snapshot() : refuse format_version < 0 ou > SAVE_FORMAT_VERSION ; la migration format_version == 0 (0.15.0) est conservée.
  • Tout refus passe par le chemin atomique existant : apply_save()/SaveManager.load_from_slot() renvoient faux sans modifier Party, carte, positions ni rencontres.

Critères d'acceptation

  • seuls PLAYER, AUTO_ALLY et SCRIPTED_GUEST sont acceptés ;
  • une version future ou négative est refusée proprement ;
  • actif non vide avec leader absent/invalide suit un contrat explicite et testé ;
  • SaveManager.load_from_slot() renvoie faux sans altérer la partie courante ;
  • les sauvegardes 0.15.0 et 0.16.0 valides restent compatibles.

Tests

Suite GUT complète verte : 280 tests (depuis 275).

  • tests/unit/test_party_save.gd : control_mode -1 et 999 refusés ; leader vide avec actif non vide refusé ; format_version négative et SAVE_FORMAT_VERSION + 1 refusées avec état GameState inchangé (héros, carte, positions, rencontres) ; une sauvegarde 0.16.0 courante reste acceptée. La migration 0.15.0 (test_migrates_legacy_hero_only_save) reste verte.
Closes #74. `Party.from_save_data()` convertissait directement n'importe quel entier en `ControlMode` (une valeur 999 était acceptée) et tolérait un leader vide avec un groupe actif non vide (repli silencieux). `GameState._party_from_snapshot()` acceptait par ailleurs toute `format_version >= 1` comme compatible. Ces données produisaient des membres impilotables ou chargeaient silencieusement un format inconnu. Deuxième correctif de l'audit 0.16.0. ## Changements - `scripts/party/party.gd` `from_save_data()` : - **valide `control_mode`** ∈ `{PLAYER, AUTO_ALLY, SCRIPTED_GUEST}` (helper `_is_valid_control_mode`) avant de construire le membre ; sinon `null` ; - **contrat de leader explicite** : si le groupe actif est non vide, un `leader_id` nommé **et** valide est exigé ; s'il est vide, aucun leader ne doit être nommé. Plus de repli silencieux. - `scripts/game_state.gd` `_party_from_snapshot()` : refuse `format_version < 0` ou `> SAVE_FORMAT_VERSION` ; la migration `format_version == 0` (0.15.0) est conservée. - Tout refus passe par le chemin atomique existant : `apply_save()`/`SaveManager.load_from_slot()` renvoient faux **sans modifier** Party, carte, positions ni rencontres. ## Critères d'acceptation - [x] seuls PLAYER, AUTO_ALLY et SCRIPTED_GUEST sont acceptés ; - [x] une version future ou négative est refusée proprement ; - [x] actif non vide avec leader absent/invalide suit un contrat explicite et testé ; - [x] SaveManager.load_from_slot() renvoie faux sans altérer la partie courante ; - [x] les sauvegardes 0.15.0 et 0.16.0 valides restent compatibles. ## Tests Suite GUT complète verte : **280 tests** (depuis 275). - `tests/unit/test_party_save.gd` : `control_mode` -1 et 999 refusés ; leader vide avec actif non vide refusé ; `format_version` négative et `SAVE_FORMAT_VERSION + 1` refusées **avec état GameState inchangé** (héros, carte, positions, rencontres) ; une sauvegarde 0.16.0 courante reste acceptée. La migration 0.15.0 (`test_migrates_legacy_hero_only_save`) reste verte.
fix: refuse les modes de contrôle et versions de sauvegarde invalides (#74)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
4184678642
Party.from_save_data() validait directement n'importe quel entier en
ControlMode (999 accepté) et tolérait un leader vide avec un actif non vide
(repli silencieux). GameState._party_from_snapshot() acceptait toute
format_version >= 1 comme compatible.

Désormais : seuls PLAYER/AUTO_ALLY/SCRIPTED_GUEST sont acceptés ; un groupe
actif non vide exige un leader nommé et valide (sinon refus) ; une
format_version négative ou > SAVE_FORMAT_VERSION est refusée. Tout refus
laisse GameState intact (application atomique). Sauvegardes 0.15.0 et 0.16.0
valides toujours compatibles.

Tests : control_mode -1 et 999 ; version négative et SAVE_FORMAT_VERSION+1
(état inchangé) ; leader vide avec actif non vide ; acceptation d'une
sauvegarde 0.16.0 courante. Suite 280 tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reliodas merged commit c6978e2543 into develop 2026-06-22 11:13:09 +00:00
Sign in to join this conversation.
No reviewers
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: jeux/beaulieu-sur-brume#80
No description provided.