- P0 path-traversal fix: run-name class is dot-free with \z anchors, so
'.', '..', and %0A-trailing values can never escape TRIMSP_TMPROOT. The
deployed path allowlist is derived from the configured root instead of the
old hardcoded /tmp prefix.
- Replacing external with an alarm() watchdog that kills the
engine's whole process group (setpgrp + kill KILL -pid), matching
muSRFlow; describe_result maps -2/-1/signal to 124/127/128+sig.
- prune_stale_jobs() ages out dirs (TrimSP.cfg marker only), orphaned .tgz,
and leaked per-request logs; safe in shared /tmp (symlinks skipped,
remove_tree safe mode, never touches non-trimsp dirs).
- Archive is serialized per run with flock (.trimsp-lock); per-point engine
runs stay concurrent.
- Symlink/non-dir run dirs refused; mode 0700 so results are not
world-readable. read/download also reject symlinked targets.
- Request caps: MAX_REQUEST_LINES 20000, MAX_REQUEST_BYTES 4 MiB -> 413.
- action=health deployment self-check; env overrides TRIMSP_BIN, TMPROOT,
CMD_TIMEOUT, JOB_MAXAGE (sed anchor for the binary path kept intact).
- Wire contract preserved: ok/phase/message/exitCode/archiveUrl/log JSON,
text read, gzip download, real HTTP statuses. No TrimSPweb.js change.
- New tests/cgi-tests.sh drives the real CGI offline (18 cases: traversal,
%0A, escaping round-trip, success/fail/hang engine, 124 watchdog, archive+-
download, pruner, symlink refusal, 413). deploy-web.sh now verifies the
sed substitution embedded the selected engine path.