Commit 51235ba1 authored by Kourser's avatar Kourser
Browse files

Kits : conversion des marqueurs littéraux substituables en variables

L'inventaire a changé le périmètre annoncé. Les crochets des kits ANSSI ne sont pas
une seule chose, mais trois familles :

1. des noms d'entité réellement substituables — [antivirus / EDR], [société
   partenaire], [votre entité], [intranet], [la ville], [au portail RH] ;
2. le PROTOCOLE d'exercice — [EXERCICE-EXERCICE-EXERCICE], [FINEX], [DEBEX] et
   leurs variantes, 87 occurrences, qui doivent rester littérales : les convertir
   aurait cassé le vocabulaire de conduite d'exercice de l'ANSSI ;
3. une longue traîne d'invites à l'animateur et de fragments grammaticalement
   imbriqués — [...], [lister], [date], [de clients], [cette commande] — qu'aucune
   variable unique ne peut remplacer sans casser la phrase.

Seule la première famille est convertie : 166 occurrences sur 11 fichiers. Chaque
règle a été vérifiée sur une occurrence réelle avant application, la phrase devant
rester grammaticale une fois la valeur substituée. Deux cas méritaient attention :
[l'antivirus / EDR] perd son article, sinon « l'Sécuriscan » ; et le « au » de
[au portail RH] sort du crochet, la valeur portant le nom seul.

Deux variables nouvelles, `intranet` et `portail_rh`, avec un repli générique qui
rend la phrase identique à aujourd'hui si l'animateur ne les remplit pas. Le
mécanisme de valeurs par défaut est généralisé : une variable qui y figure ne peut
jamais afficher son jeton brut à un joueur.

Les deux nouvelles sont proposées par l'étape Contexte (les kits les citent, la
dérivation les fait donc remonter) et suggérées par la page Variables.

Les 11 fichiers JSON restent valides — vérifié par analyse syntaxique — et les 87
marqueurs de protocole sont intacts.

373 crochets subsistent, relevant des familles 2 et 3. Ils ne sont pas un oubli.

Non compilé ni exécuté (pas de toolchain Node dans l'environnement utilisé).

Co-Authored-By: Claude (RCA)
parent c54b1c94
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -24,12 +24,16 @@ describe('buildVars', () => {
    expect(buildVars('   ', undefined).secteur).toBeUndefined();
  });

  it('resout toujours les variables non-cyber, saisies ou par defaut', () => {
  it('resout toujours les variables a repli, saisies ou par defaut', () => {
    const defaults = buildVars(null, undefined);
    expect(defaults.cours_deau).toBe('la rivière');
    expect(defaults.prefecture).toBe('la préfecture');
    expect(defaults.gestionnaire_reseau).toBe('le gestionnaire du réseau');
    // Cites par les kits REMPAR25 depuis la conversion des crochets litteraux.
    expect(defaults.intranet).toBe('intranet');
    expect(defaults.portail_rh).toBe('portail RH');
    expect(buildVars(null, { cours_deau: 'la Loire' }).cours_deau).toBe('la Loire');
    expect(buildVars(null, { intranet: 'MéridienNet' }).intranet).toBe('MéridienNet');
  });

  it('accepte un contexte absent', () => {
+21 −9
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ export interface Personalization {
  cours_deau?: string;
  prefecture?: string;
  gestionnaire_reseau?: string;
  intranet?: string;
  portail_rh?: string;
  startAt?: string;
}

@@ -34,6 +36,8 @@ export interface ExerciseContext {
  cours_deau?: string;
  prefecture?: string;
  gestionnaire_reseau?: string;
  intranet?: string;
  portail_rh?: string;
  startAt?: string;
}

@@ -46,15 +50,25 @@ const CONTEXT_KEYS = [
  'cours_deau',
  'prefecture',
  'gestionnaire_reseau',
  'intranet',
  'portail_rh',
  'startAt',
] as const;

/** Valeurs par défaut des variables non-cyber (spec kits §1) si non renseignées. */
const NON_CYBER_DEFAULTS = {
/**
 * Valeurs par defaut. Une variable listee ici est TOUJOURS resolue : son jeton ne
 * peut donc jamais s'afficher brut a un joueur. Reserve aux variables dont le
 * repli generique reste lisible dans la phrase (« le site intranet »).
 */
const VARIABLE_DEFAULTS: Record<string, string> = {
  // Kits non-cyber (spec kits §1).
  cours_deau: 'la rivière',
  prefecture: 'la préfecture',
  gestionnaire_reseau: 'le gestionnaire du réseau',
} as const;
  // Systemes internes cites par les kits REMPAR25.
  intranet: 'intranet',
  portail_rh: 'portail RH',
};

/** Contexte (mise en situation) nettoyé, ou undefined si aucun champ renseigné. */
export function buildContext(p: Personalization | undefined): ExerciseContext | undefined {
@@ -88,12 +102,10 @@ export function buildVars(
    if (typeof value === 'string' && value.trim() !== '') vars[key] = value.trim();
  }
  if (sector && sector.trim()) vars.secteur = sector.trim();
  // Variables non-cyber : toujours résolues (valeur saisie ou défaut) pour éviter
  // qu'un jeton {{...}} reste visible côté joueur dans les kits inondation/black-out/canicule.
  vars.cours_deau = ctx?.cours_deau?.trim() || NON_CYBER_DEFAULTS.cours_deau;
  vars.prefecture = ctx?.prefecture?.trim() || NON_CYBER_DEFAULTS.prefecture;
  vars.gestionnaire_reseau =
    ctx?.gestionnaire_reseau?.trim() || NON_CYBER_DEFAULTS.gestionnaire_reseau;
  // Repli generique : garantit qu'aucun de ces jetons ne reste visible cote joueur.
  for (const [key, fallback] of Object.entries(VARIABLE_DEFAULTS)) {
    if (!vars[key]) vars[key] = fallback;
  }
  return vars;
}

+10 −10

File changed.

Preview size limit exceeded, changes collapsed.

+6 −6

File changed.

Preview size limit exceeded, changes collapsed.

+3 −3

File changed.

Preview size limit exceeded, changes collapsed.

Loading