test(hosts): extend the socket-level pass to the two workstation routes #26

Open
maximus wants to merge 1 commit from issue-16-hosts-monitoring-commissioning into main
Owner

Etend test-curl.sh aux deux routes postes, et documente la mise en service.

Volontairement Refs #16 et pas Fixes #16 : plusieurs criteres d'acceptation ne sont pas encore tenus (ops VPS bloquees, deploiement Vercel bloque en amont). L'issue se ferme a la main quand le dernier tombe, pas au merge de cette PR.

Ce que contient la PR

  • test-curl.sh : 17 -> 41 cas. Les 24 nouveaux couvrent POST /hosts/<id> et GET /hosts au niveau socket — le 413 rendu avant que la connexion soit coupee, les deux tokens qui se refusent mutuellement leurs routes, le 401 avant le 403, la regex de route qui transforme un id malforme et une traversee en 404 avant tout handler, et le round trip ingestion -> persistance -> lecture.
  • Un second serveur sur le port 3098, demarre sans HOSTS_INGEST_TOKEN, pour observer le 503 fail-closed — c'est le seul comportement du lot qu'une instance unique ne peut pas montrer.
  • CLAUDE.md : le compte vitest etait perime (244 -> 251, auth.test.js 19 -> 26) et test-curl.sh n'y figurait pas.

Deux cas ont demande de l'attention pour valoir quelque chose :

  • Le payload hostile insere __proto__ comme du texte. Ecrit __proto__: dans un litteral objet, il aurait pose le prototype et JSON.stringify n'aurait rien emis — le cas aurait teste un payload qui ne portait jamais la cle.
  • Le cas 413 tourne sous set -e pendant que le serveur detruit la socket juste apres avoir vide la reponse. Toutes les sondes passent par un helper qui absorbe ca ; un curl qui n'a vraiment rien recu rapporte 000, ce qui fait echouer le cas au lieu de le laisser passer en silence.

Le trap EXIT deferencait un SERVER_PID non initialise sous set -u : il tombait en erreur au lieu de nettoyer quand quoi que ce soit echouait avant le boot.

Verification

  • npm test : 251 cas verts
  • bash test-curl.sh : 41 cas verts, joue 3 fois de suite pour le cas 413

Hors PR, deja fait

  • Variables Coolify HOSTS_INGEST_TOKEN et HOSTS_ALLOWED_IDS=thinkpad posees, is_runtime=true is_buildtime=false verifie sur les 4 rows (jumeaux preview compris)
  • la-compagnie-maximus@7e3ee04 : procedure d'ajout d'un poste dans docs/coolify-ops.md, rotation conjointe des deux tokens dans docs/secret-rotation-ops.md

Reste a faire

Detaille en commentaire sur #16.

Refs #16

Etend `test-curl.sh` aux deux routes postes, et documente la mise en service. **Volontairement `Refs #16` et pas `Fixes #16`** : plusieurs criteres d'acceptation ne sont pas encore tenus (ops VPS bloquees, deploiement Vercel bloque en amont). L'issue se ferme a la main quand le dernier tombe, pas au merge de cette PR. ## Ce que contient la PR - `test-curl.sh` : 17 -> 41 cas. Les 24 nouveaux couvrent `POST /hosts/<id>` et `GET /hosts` au niveau socket — le 413 rendu avant que la connexion soit coupee, les deux tokens qui se refusent mutuellement leurs routes, le 401 avant le 403, la regex de route qui transforme un id malforme et une traversee en 404 avant tout handler, et le round trip ingestion -> persistance -> lecture. - Un second serveur sur le port 3098, demarre sans `HOSTS_INGEST_TOKEN`, pour observer le 503 fail-closed — c'est le seul comportement du lot qu'une instance unique ne peut pas montrer. - `CLAUDE.md` : le compte vitest etait perime (244 -> 251, `auth.test.js` 19 -> 26) et `test-curl.sh` n'y figurait pas. Deux cas ont demande de l'attention pour valoir quelque chose : - Le payload hostile insere `__proto__` **comme du texte**. Ecrit `__proto__:` dans un litteral objet, il aurait pose le prototype et `JSON.stringify` n'aurait rien emis — le cas aurait teste un payload qui ne portait jamais la cle. - Le cas 413 tourne sous `set -e` pendant que le serveur detruit la socket juste apres avoir vide la reponse. Toutes les sondes passent par un helper qui absorbe ca ; un curl qui n'a vraiment rien recu rapporte `000`, ce qui fait echouer le cas au lieu de le laisser passer en silence. Le trap `EXIT` deferencait un `SERVER_PID` non initialise sous `set -u` : il tombait en erreur au lieu de nettoyer quand quoi que ce soit echouait avant le boot. ## Verification - `npm test` : 251 cas verts - `bash test-curl.sh` : 41 cas verts, joue 3 fois de suite pour le cas 413 ## Hors PR, deja fait - Variables Coolify `HOSTS_INGEST_TOKEN` et `HOSTS_ALLOWED_IDS=thinkpad` posees, `is_runtime=true is_buildtime=false` verifie sur les 4 rows (jumeaux preview compris) - `la-compagnie-maximus@7e3ee04` : procedure d'ajout d'un poste dans `docs/coolify-ops.md`, rotation conjointe des deux tokens dans `docs/secret-rotation-ops.md` ## Reste a faire Detaille en commentaire sur #16. Refs #16
maximus added 1 commit 2026-08-19 00:19:18 +00:00
test-curl.sh predates vitest and still claimed to be the authoritative suite
for one endpoint. It is now the socket-level pass, and its header says so:
vitest covers the logic, this script covers what only a real client and a
real TCP connection can show.

Twenty-four cases for POST /hosts/<id> and GET /hosts, chosen for what they
prove rather than for coverage: the 413 answered before the connection is
cut, the two tokens refusing each other's routes in both directions, 401
landing ahead of 403 so an unauthenticated caller cannot probe the allowlist,
the route regex turning a malformed id and a traversal attempt into 404
before any handler runs, and the ingest-persist-read round trip closing on a
GET that shows the pushed hostname online.

Two cases needed care to be worth anything:

The hostile payload splices "__proto__" into the JSON as text. Written as
__proto__: in an object literal it would set the prototype and JSON.stringify
would emit nothing, leaving the case asserting against a payload that never
carried the key. It now checks the response and the persisted file, whose key
set must be exactly the whitelist.

The 413 case runs under set -e while the server destroys the socket right
after flushing the response, so curl can exit 55/56 having already read the
status line. Every probe goes through an http_code helper that absorbs that;
a curl which truly got nothing reports 000, which fails the case rather than
passing it quietly. -H "Expect:" also suppresses the 100-continue handshake,
which otherwise changes which side notices the reset first.

The fail-closed 503 needs a server booted without HOSTS_INGEST_TOKEN, so the
script now runs a second instance on 3098 for it, and confirms reads still
answer 200 there — the two tokens are independent, including in absence.

The EXIT trap dereferenced an unset SERVER_PID under set -u, which made it
error out instead of cleaning up when anything failed before the boot. Both
PIDs are initialised and the kills guarded.

CLAUDE.md: the vitest count was stale (244 -> 251, auth.test.js 19 -> 26) and
test-curl.sh was undocumented.

Refs #16

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
maximus added the
status:review
type:infra
labels 2026-08-19 00:19:54 +00:00
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-16-hosts-monitoring-commissioning:issue-16-hosts-monitoring-commissioning
git checkout issue-16-hosts-monitoring-commissioning
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: maximus/vps-health-api#26
No description provided.