The docs promised that writes.test.js pins every write. They now say what
it covers: node:fs writes and shell commands, on the paths it exercises.
They also name what keeps the second layer up: the Defenseurs content is
group-writable, and only the owning group (defenseur, gid 1001, not the
gid 1000 of node and ubuntu) keeps the container out, so a chgrp ubuntu
would drop that layer silently.
Fixes#36
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of PR #39: the spies only watched authenticated requests on
complete fixtures, so a write on an error path passed the whole suite
(reviewer mutations R1, R2, R3 and R11: quarantining a corrupt
agents-map.json, recreating a missing status.json, logging a 401/403 or a
refused payload to disk).
A new case walks rejections (401/403/404), invalid input (400/413), a
corrupt agents-map.json, missing Defenseurs files and a corrupt snapshot,
requires the degraded content (no_data, neverSeen), and requires no write
outside HOSTS_DIR. child_process is now spied the same way as node:fs and
the set of shell commands is pinned to the two read-only ones metrics.js
runs, with GET /health as positive control.
R1, R2, R3 and R11 went from 0 to 1 red each; R4 (touch through
execFileSync) is now caught by this file. A write deferred by a timer
longer than 20 ms (R8b) stays out of sight, as the header says.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both Defenseurs bind mounts are `:ro` since 2026-09-30, set as a suffix
on the Coolify destination path; the reports Directory Mount was recreated
as a Volume Mount with a Source Path to take it. CLAUDE.md, README.md and
.env.example now describe the two layers (mount mode and Unix
permissions), the three checks to run after a redeploy, and the Coolify
gotchas met on the way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The two Defenseurs mounts are now read-only in the container, so a write
added one day under REPORTS_DIR or /data/defenseurs would fail in
production as a 500 (EROFS) while every other test stays green: their
fixtures are writable temp dirs, and CI runs as root.
writes.test.js spies every node:fs write API (callback, Sync and
fs.promises forms) before a fresh require, after purging all runtime
modules from the require cache, and records the calls whose stack goes
through a runtime file. It covers boot (the temp-file sweep), the six GET
routes (no write at all, one macrotask after the response included) and
POST /hosts/<id> (writes only under HOSTS_DIR). Each case proves its own
spies are live, and the require.main block is pinned since it never runs
in-process.
Mutation proofs: a write at module load, in the scan collector, through an
fs function not imported today, in the ingest rename or in metrics.js, a
dead spy, and a new call in the main block each turn the expected case
red. With the cache purge narrowed to index.js, the metrics.js write stays
green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>