feat(defenseurs): GET /defenseurs/state serves findings-state.json #28
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/vps-health-api#28
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-27-defenseurs-state"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #27
Summary
GET /defenseurs/stateserving the Sergent'sfindings-state.jsonverbatim (DEFENSEURS_FINDINGS_STATE_PATH, default/data/defenseurs/findings-state.json, already covered by the/data/defenseursmount).serveJsonFile()extracted and shared with/defenseurs: raw content, or 200{"status":"no_data"}on any read error. No parse, no freshness check (decisions from the /analyze pass).ROUTESdescriptor withtokenKind: "read".Tests
npm test: 263/263 (new__tests__/state.test.js, 9 cases;/defenseurs/stateadded to theauth.test.js401/404 matrix, +3).bash test-curl.sh: 45/45. Rebased on #26 (merged), then 4 socket-level cases added for/defenseurs/state: file served byte for byte (compared withcmp),no_datawhen absent, 401 without token, 401 with the ingest token.status.json-> 2 red; parse + re-serialise inserveJsonFile()-> 2 red in vitest, 1 red intest-curl.sh; restored, suites green.Docs
README and CLAUDE.md: endpoint, config vars (
DEFENSEURS_STATUS_PATHwas undocumented, added too), mount section, test counts. The README mount list claimed per-file mounts from/home/defenseur/...; it now matches the real/data/defenseursdirectory mount described in CLAUDE.md.Deploy
No auto-deploy: after merge, force a Coolify redeploy, then
curl -H "Authorization: Bearer $TOKEN" https://health.lacompagniemaximus.com/defenseurs/stateshould answer 200 (no_datauntil Sergent v2 has run).🤖 Generated with Claude Code
The Sergent now persists per-finding state (firstSeen, unverified, 30-day history) in findings-state.json next to status.json. The admin dashboard needs it for the drill-down, since it is the only source carrying a finding's age. - New read route GET /defenseurs/state, path from DEFENSEURS_FINDINGS_STATE_PATH (default /data/defenseurs/findings-state.json), already covered by the /data/defenseurs mount. - Extract serveJsonFile() so /defenseurs and /defenseurs/state share one contract: raw content, or 200 {status:"no_data"} on any read error. - Tests: new state.test.js (byte-identical body, no_data, path isolation, 401 x3, 404 on POST) and the route added to the auth.test.js matrix. - Docs: README and CLAUDE.md endpoint, config and mount sections; the README mount list now matches the real /data/defenseurs directory mount. Fixes #27 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>64e4669619to7c14e581cbRevue adversariale — verdict : APPROVE
Remplace la revue du 2026-09-25 00:34Z (commentaire supprime) : elle precedait le rebase sur #26 et le commit
7c14e58(passe socket).Resume : un seul descripteur
ROUTES(tokenKind: "read") ajoute la route ; l'ordre routage -> auth reste intact et l'extraction deserveJsonFile()ne change pas le comportement de/defenseurs. Le tip7c14e58(base = main apres #26) tient sous mutation, en vitest comme en passe socket.Verifications (sur le tip
7c14e58)npm test: 263/263.bash test-curl.sh: 45/45 (41 herites de #26 + 4 nouveaux, ports 3099/3098 libres avant lancement).index.js(sans modification non commitee avant ; backup puis restauration,git diff --statvide a la fin) :DEFENSEURS_STATUS_PATH-> 2 rouges (octet pour octet, isolation des chemins) ;tokenKind: "ingest"sur la route -> 4 rouges ;serveJsonFile()-> 2 rouges (le JSON non canonique des fixtures fait son travail) ;ROUTES-> 8 rouges.test-curl.sh: la comparaison passe parcmpsur fichiers, le newline final entre donc dans le controle (une substitution de commande l'aurait mange). L'instance 3098 recoit un chemin absent pour couvrirno_datasans fixture supplementaire.Content-Type: application/jsonpose globalement. Pas de secret dans le diff.Fixes #27dans le message dea5d1bcd.Suggestions (non bloquantes)
test-curl.sh: 17/17. Left unchanged on purpose: PR #26 rewrites it » et un conflit attendu surCLAUDE.mdavec #26. Or #26 est merge, la branche est rebasee dessus,7c14e58modifietest-curl.shetCLAUDE.mdannonce 45 cas (exact). Mettre le corps a jour pour que l'historique de la PR dise ce qui a ete merge.serveJsonFile():readFileSynca chaque requete sur un fichier qui porte 30 jours d'historique. Negligeable pour un seul consommateur ; a surveiller si le fichier depasse quelques Mo..corrupt-*) qui n'est testee que dansdefenseurs. S'assurer qu'un test l'y tient.state.test.js« 404 (not 401) on POST » recoupe la matrice d'auth.test.js. Redondance sans cout.