Concierge vehicule : code (detection, live, write + test de portee)
Complete le commit doc precedent : ajoute le code JS du concierge, exclu jusqu'ici par la liste blanche workspace/*. Exception ciblee !workspace/concierge-*.js dans .gitignore (aucun secret : les tokens sont lus depuis .ha-token/.pg-airtria, ignores). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RZsbhyGmRwZogdoBwT6C6y
This commit is contained in:
57
workspace/concierge-write.test.js
Normal file
57
workspace/concierge-write.test.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// concierge-write.test.js — Test de PORTÉE D'ÉCRITURE (garde-fou du canal HA).
|
||||
// Doit ÉCHOUER si une écriture peut sortir de la constante airtria_vehicle_label.
|
||||
// À faire tourner à CHAQUE modification, pas une seule fois (cf. EVCS advisor).
|
||||
// Pur statique + require : aucun réseau, aucun token, aucune écriture.
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const SRC = path.join(__dirname, 'concierge-write.js');
|
||||
const src = fs.readFileSync(SRC, 'utf8');
|
||||
const mod = require('./concierge-write.js');
|
||||
|
||||
let ko = 0;
|
||||
const check = (name, fn) => {
|
||||
try { fn(); console.log(` ok ${name}`); }
|
||||
catch (e) { ko++; console.log(` FAIL ${name} : ${e.message}`); }
|
||||
};
|
||||
|
||||
console.log('=== Test de portée d\'écriture concierge-write.js ===');
|
||||
|
||||
// 1. La constante est exactement l'entité attendue.
|
||||
check('constante = input_text.airtria_vehicle_label', () =>
|
||||
assert.strictEqual(mod.HELPER_ENTITY, 'input_text.airtria_vehicle_label'));
|
||||
|
||||
// 2. entity_id n'est JAMAIS accolé à autre chose que la constante
|
||||
// (pas de littéral d'entité, pas d'interpolation, pas de concaténation).
|
||||
check('entity_id uniquement = HELPER_ENTITY', () => {
|
||||
const occ = [...src.matchAll(/entity_id\s*:\s*([^,}\n]+)/g)].map(m => m[1].trim());
|
||||
assert(occ.length > 0, 'aucun entity_id trouvé');
|
||||
for (const v of occ) assert.strictEqual(v, 'HELPER_ENTITY',
|
||||
`entity_id dynamique ou littéral interdit : ${v}`);
|
||||
});
|
||||
|
||||
// 3. Aucune autre entité HA en dur (aucun autre "domaine.entite") que la constante.
|
||||
check('aucune entité HA littérale hors la constante', () => {
|
||||
const decl = "'input_text.airtria_vehicle_label'";
|
||||
const lits = [...src.matchAll(/['"`]([a-z_]+\.[a-z0-9_]+)['"`]/g)].map(m => m[0]);
|
||||
for (const l of lits) assert.strictEqual(l, decl,
|
||||
`littéral d'entité interdit : ${l}`);
|
||||
});
|
||||
|
||||
// 4. Un SEUL appel de service, et c'est input_text/set_value (aucun actionneur).
|
||||
check('seul service = input_text/set_value', () => {
|
||||
const services = [...src.matchAll(/\/api\/services\/([a-z_]+\/[a-z_]+)/g)]
|
||||
.map(m => m[1]);
|
||||
assert.deepStrictEqual(services, ['input_text/set_value'],
|
||||
`services inattendus : ${services.join(', ') || '(aucun)'}`);
|
||||
});
|
||||
|
||||
// 5. La relecture existe (garde-fou rejet silencieux).
|
||||
check('relecture présente (/api/states/)', () =>
|
||||
assert(/\/api\/states\//.test(src), 'pas de relecture après écriture'));
|
||||
|
||||
console.log(ko === 0 ? '\nTOUT VERT' : `\n${ko} test(s) EN ÉCHEC`);
|
||||
process.exit(ko === 0 ? 0 : 1);
|
||||
Reference in New Issue
Block a user