concierge: lire airtria_ro depuis l'env/.env + alerte d'echec d'auth
Le mot de passe airtria_ro est desormais lu depuis AIRTRIA_RO_PASSWORD (variable d'environnement, sinon .env monte dans le conteneur), plus depuis .pg-airtria : EVCS renouvelle ce mot de passe, un fichier fige faisait echouer l'auth EN SILENCE. readPgPassword LEVE (rattrapable) au lieu de process.exit ; mot de passe resolu paresseusement dans makeClient. Nouveau module concierge-health.js (meme patron que le moniteur LLM) : battement de coeur horodate a CHAQUE cycle detect, statut live dans HA, et alerte WhatsApp UNIQUEMENT sur transition ok<->erreur (dedup, pas de rappel periodique). Chemin HA independant de PostgreSQL : l'alerte auth KO part meme quand c'est l'auth qui tombe. Best-effort : si les helpers HA manquent, le concierge n'echoue pas. - concierge-health.test.js : machine a etats (dedup + transitions) verifiee, sans reseau - concierge-health-ha-package.yaml.draft : helpers HA (a integrer cote proprietaire) - SPEC : source du secret corrigee + section supervision Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RZsbhyGmRwZogdoBwT6C6y
This commit is contained in:
39
workspace/concierge-health.test.js
Normal file
39
workspace/concierge-health.test.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// concierge-health.test.js — vérifie la MACHINE À ÉTATS des alertes (dédup + transitions).
|
||||
// Aucun réseau, aucun secret : HA_TOKEN_FILE pointe sur un fichier absent → haToken() = null
|
||||
// → aucun appel HA émis ; l'état vit dans un fichier temporaire isolé (pas celui de prod).
|
||||
// Lancer : node concierge-health.test.js
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const STATE = path.join(os.tmpdir(), `concierge-health-test-${process.pid}.json`);
|
||||
process.env.CONCIERGE_HEALTH_STATE = STATE;
|
||||
process.env.HA_TOKEN_FILE = path.join(os.tmpdir(), 'no-such-ha-token-xyz');
|
||||
try { fs.rmSync(STATE, { force: true }); } catch { /* neuf */ }
|
||||
|
||||
const { publish } = require('./concierge-health.js');
|
||||
|
||||
let failures = 0;
|
||||
const check = (label, cond) => { console.log(`${cond ? 'ok ' : 'FAIL'} ${label}`); if (!cond) failures++; };
|
||||
|
||||
(async () => {
|
||||
const s1 = await publish({ ok: true });
|
||||
check('sain au démarrage → aucun message', s1 === '');
|
||||
|
||||
const s2 = await publish({ ok: false, detail: 'password authentication failed' });
|
||||
check('bascule sain→panne → alerte émise', /en panne/.test(s2));
|
||||
|
||||
const s3 = await publish({ ok: false, detail: 'password authentication failed' });
|
||||
check('panne persistante → PAS de ré-alerte (dédup)', s3 === '');
|
||||
|
||||
const s4 = await publish({ ok: true });
|
||||
check('bascule panne→sain → « de nouveau opérationnel »', /opérationnel/.test(s4));
|
||||
|
||||
const s5 = await publish({ ok: true });
|
||||
check('sain persistant → aucun message', s5 === '');
|
||||
|
||||
try { fs.rmSync(STATE, { force: true }); } catch { /* nettoyage */ }
|
||||
if (failures) { console.error(`\n${failures} test(s) en échec`); process.exit(1); }
|
||||
console.log('\nTOUT VERT — machine à états santé concierge conforme');
|
||||
})().catch(e => { console.error('[test]', e); process.exit(1); });
|
||||
Reference in New Issue
Block a user