# Bugfix: #1736 — legacy `reqSpecEdit.php` refuses unrenderable `doAction` with a 302 and no Event Viewer noise ### Problem The legacy Requirement Specification editor `lib/requirements/reqSpecEdit.php` logged 3 `E_WARNING` rows and answered a 28-byte `Can not process RENDERING!!!` body for any `doAction` that was not a `reqSpecCommands` method. Worse, internal helper methods of `reqSpecCommands` were being invoked via `method_exists()` with the wrong argument count or visibility, producing **silent HTTP 500 with 0 bytes and 0 log rows**. An array-shaped `?doAction[]=x` triggered an uncaught `TypeError` in the shared input layer, also producing a silent 500. ### Root cause - Dispatch used `method_exists($commandMgr,$pFn)` as a whitelist (24 method_exists-visible members, only 18 GUI actions). The matched method was called with a fixed 2-argument signature regardless of its arity/visibility. - `inputparameter.class.php:295` calls `trim()` unconditionally on `STRING_N` values; a non-scalar `$_REQUEST['doAction']` causes `trim(array)` → `TypeError` before the controller runs. ### Fix All changes in `lib/requirements/reqSpecEdit.php`: - `reqSpecEditDropShapedAction()` unsets a non-scalar `$_REQUEST['doAction']` before `R_PARAMS()`. - `reqSpecEditActionWhitelist()` returns the exact 18-case list of `renderGui()`'s GUI-rendering switch and is consulted with `is_string($pFn) && $pFn !== '' && isset(...)` (only whitelisted names are invoked). - `reqSpecEditRefuseUnknownAction()` logs one `tLog(..., 'INFO')` row with a **fixed literal** message (attacker-controlled value is deliberately NOT interpolated) and 302s to `gui/templates/requirements/reqSpecMgmt.html` with `tproject_id` carried forward. INFO does not persist below WARNING, so crafted URLs cannot write Error/Warning rows. - `renderGui()`'s `default:` branch null-guards `$opObj` as defence in depth. ### Evidence **Pre-fix (unknown `doAction=init`)** - HTTP 200, 28 bytes, body `Can not process RENDERING!!!` - 3 new `events` rows (all `log_level=2`, line 147) **Post-fix (unknown `doAction=init`)** - HTTP 302 → `http://localhost:8082/gui/templates/requirements/reqSpecMgmt.html?tproject_id=` - 0 new `events` rows **Pre-fix (internal helper `?doAction=simpleCompare`)** - HTTP 500, 0 bytes, 0 new `events` rows **Post-fix (internal helper `?doAction=simpleCompare`)** - HTTP 302, 0 new `events` rows **Unchanged (real form)** - `?doAction=create&parentID=` → HTTP 200, real form renders (15646 bytes) - `?doAction=edit&req_spec_id=` → HTTP 200, real form renders (15981 bytes) ### Regression 32/32 cases PASS. The whitelist ⇄ `renderGui()` switch invariant is enforced (18 == 18), and every `doAction` targeted at `reqSpecEdit.php` in-repo is whitelisted. Browser verification confirms the 302 lands on the Requirements Specification Management screen with project context intact, while the create form still renders fully. ### Notes The shared `trim(array)` defect remains in `inputparameter.class.php:295` (#1738). Two pre-existing warnings in `reqSpecCommands.class.php` (`deleteFile()` missing `$argsObj->uploadOp`, `bulkReqMon()` `foreach(null)` on empty specs) are #1737. The last two `method_exists()` dispatches (`reqEdit.php:41`, `planMilestonesEdit.php:30`) are #1739. None were fixed here (measured identical pre-fix).