V3/do not add newline to test body lines#3486
V3/do not add newline to test body lines#3486hnakamur wants to merge 21 commits intoowasp-modsecurity:v3/masterfrom
Conversation
This is needed to test edge cases like a body missing the final newline, for example: [ "a\r\n", "b\r" ] And it is clearer than to add implicit newline to each line except the final line.
when UPDATE_CONTENT_LENGTH env var is set
by running the following command: ``` (cd test; ./regression_tests format) ```
by running the following command: ``` (cd test; UPDATE_CONTENT_LENGTH=1 ./regression_tests format) ```
8fefe12 to
9b49187
Compare
|
I found JSON was corrupted since some of http_version was empty. I fixed it and force pushed. |
|
I fixed tests at aefd4a4 and now all tests pass again. |
|
Hi @hnakamur, thank you for this improved PR. Unfortunately there are two warnings from cppcheck: Also, SonarCloud reported a few new issues (some of them are same as As I mentioned previously, I don't expect to fix all Sonar issues. If the Thank you again. |
|
There was a problem hiding this comment.
Pull request overview
This PR updates the regression-test JSON format to preserve request/response body line endings (no implicit newline per line), adds a format subcommand to reformat/normalize test JSON files, and introduces tooling to auto-update Content-Length headers during formatting.
Changes:
- Added a
formatsubcommand to the regression test runner and optionalUPDATE_CONTENT_LENGTHbehavior. - Updated regression-test parsing structures (e.g.,
std::unique_ptr,std::optional) and introduced aRegressionTestswrapper with JSON serialization. - Mass-updated regression test JSON files to use line-array bodies, normalize escaping, and add
Content-Lengthheaders.
Reviewed changes
Copilot reviewed 117 out of 202 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test-cases/regression/transformations.json | Reformats request/response bodies as arrays; normalizes headers and adds Content-Length |
| test/test-cases/regression/transformation-none.json | Reformats request/response bodies as arrays; normalizes headers and adds Content-Length |
| test/test-cases/regression/secruleengine.json | Adds explicit client/server/request/response blocks for formatting/schema consistency |
| test/test-cases/regression/secmarker.json | Reformats request/response bodies as arrays; normalizes headers and adds Content-Length |
| test/test-cases/regression/secargumentslimit.json | Adds Content-Length and response skeletons to align with new formatting |
| test/test-cases/regression/secaction.json | Reformats request/response bodies as arrays; normalizes headers and adds Content-Length |
| test/test-cases/regression/sec_component_signature.json | Normalizes escaping and adds Content-Length headers |
| test/test-cases/regression/rule-920274.json | Adds Content-Length and moves to body-as-array representation |
| test/test-cases/regression/rule-920200.json | Adds Content-Length and moves to body-as-array representation |
| test/test-cases/regression/rule-920120.json | Updates multipart body line endings and Content-Length |
| test/test-cases/regression/request-body-parser-multipart-crlf.json | Updates multipart body line endings and Content-Length |
| test/test-cases/regression/operator-verifysvnr.json | Updates Content-Length values and expected http_code |
| test/test-cases/regression/operator-verifyssn.json | Updates Content-Length values and expected http_code |
| test/test-cases/regression/operator-verifycpf.json | Updates Content-Length values and expected http_code |
| test/test-cases/regression/operator-verifycc.json | Updates Content-Length values and expected http_code |
| test/test-cases/regression/operator-validate-byte-range.json | Adds Content-Length, changes empty body representation, adds expected http_code |
| test/test-cases/regression/operator-rxGlobal.json | Adds Content-Length, appends expected http_code |
| test/test-cases/regression/operator-rx.json | Normalizes headers/bodies, adds Content-Length/expected http_code across cases |
| test/test-cases/regression/operator-pmfromfile.json | Normalizes escaping and switches response to explicit headers/body |
| test/test-cases/regression/operator-pm.json | Normalizes escaping, adds Content-Length and explicit empty response body |
| test/test-cases/regression/operator-ipMatchFromFile.json | Normalizes paths/headers, adds Content-Length and expected http_code |
| test/test-cases/regression/operator-detectxss.json | Normalizes body escaping, updates Content-Length and expected http_code |
| test/test-cases/regression/operator-detectsqli.json | Updates Content-Length and expected http_code |
| test/test-cases/regression/operator-UnconditionalMatch.json | Adds Content-Length and expected http_code |
| test/test-cases/regression/misc.json | Adds explicit client/server/request/response blocks and expected http_code |
| test/test-cases/regression/misc-variable-under-quotes.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/issue-960.json | Fixes issue metadata fields and normalizes request/response schema |
| test/test-cases/regression/issue-849.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/issue-394.json | Normalizes request/response schema and expected fields |
| test/test-cases/regression/issue-3340.json | Normalizes escaping and response structure |
| test/test-cases/regression/issue-2427.json | Updates multipart body-to-lines representation and Content-Length |
| test/test-cases/regression/issue-2423-msg-in-chain.json | Adds explicit request/response blocks and normalizes expected fields |
| test/test-cases/regression/issue-2196.json | Adds explicit request/response blocks and normalizes expected fields |
| test/test-cases/regression/issue-2111.json | Adds explicit request/response blocks and normalizes expected fields |
| test/test-cases/regression/issue-2000.json | Adds explicit request/response blocks and normalizes expected fields |
| test/test-cases/regression/issue-1960.json | Adds Content-Length/body arrays and normalizes headers |
| test/test-cases/regression/issue-1943.json | Normalizes escaping, adds Content-Length/body arrays |
| test/test-cases/regression/issue-1850.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/issue-1844.json | Updates Content-Length and response headers |
| test/test-cases/regression/issue-1812.json | Normalizes escaping and adds expected http_code |
| test/test-cases/regression/issue-1785.json | Normalizes escaping and adds request/response schema |
| test/test-cases/regression/issue-1743.json | Normalizes escaping and adds request/response schema |
| test/test-cases/regression/issue-1725.json | Normalizes issue metadata and request/response schema |
| test/test-cases/regression/issue-1591.json | Normalizes issue metadata and request/response schema |
| test/test-cases/regression/issue-1576.json | Normalizes issue metadata; adds server/response blocks and Content-Length headers |
| test/test-cases/regression/issue-1565.json | Normalizes issue metadata and request/response schema |
| test/test-cases/regression/issue-1528.json | Normalizes issue metadata and request/response schema |
| test/test-cases/regression/fn-setHostname.json | Adds Content-Length/body array and normalizes client/server fields |
| test/test-cases/regression/debug_log.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/config-xml_external_entity.json | Normalizes resource formatting and adds server/response blocks |
| test/test-cases/regression/config-update-target-by-tag.json | Adds Content-Length/body arrays and normalizes expected fields |
| test/test-cases/regression/config-update-target-by-msg.json | Adds Content-Length/body arrays and normalizes expected fields |
| test/test-cases/regression/config-update-target-by-id.json | Adds Content-Length/body arrays and normalizes expected fields |
| test/test-cases/regression/config-secremoterules.json | Adds format-aligned request/response blocks and expected http_code for parser errors |
| test/test-cases/regression/config-response_type.json | Normalizes escaping; adds Content-Length/body arrays; updates expected http_code |
| test/test-cases/regression/config-remove_by_tag.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/config-remove_by_msg.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/config-remove_by_id.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/config-include-bad.json | Adds explicit request/response schema and expected http_code for parser errors |
| test/test-cases/regression/config-calling_phases_by_name.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/collection-resource.json | Normalizes escaping and adds content-length and empty response bodies |
| test/test-cases/regression/collection-regular_expression_selection.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/collection-lua.json | Normalizes empty body/headers handling and adds expected http_code |
| test/test-cases/regression/collection-case-insensitive.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/action-xmlns.json | Adds explicit request/response schema and expected http_code for parser errors |
| test/test-cases/regression/action-tnf-base64.json | Updates expected output due to newline handling; adds Content-Length/http_code |
| test/test-cases/regression/action-tag.json | Normalizes escaping and adds Content-Length/body arrays |
| test/test-cases/regression/action-skip.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-setuid.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-setsid.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-setrsc.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-setenv.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-msg.json | Normalizes escaping and expected debug output; adds expected http_code |
| test/test-cases/regression/action-initcol.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-id.json | Adds Content-Length and expected http_code to parser-error cases |
| test/test-cases/regression/action-expirevar.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-disruptive.json | Adds explicit client/server/request/response blocks for formatting/schema consistency |
| test/test-cases/regression/action-ctl_rule_remove_target_by_tag.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-ctl_rule_remove_by_tag.json | Adds Content-Length/body arrays and expected http_code |
| test/test-cases/regression/action-ctl_rule_remove_by_id.json | Adds explicit request/response schema and expected http_code |
| test/test-cases/regression/action-ctl_rule_engine.json | Normalizes request bodies/Content-Length and response headers |
| test/test-cases/regression/action-ctl_request_body_processor_urlencoded.json | Updates Content-Length and response headers |
| test/test-cases/regression/action-ctl_request_body_processor.json | Adds server/response blocks and normalizes expected structure |
| test/test-cases/regression/action-ctl_request_body_access.json | Updates Content-Length and expected structure |
| test/test-cases/regression/action-ctl_audit_engine.json | Adds explicit response skeleton and request body array |
| test/test-cases/regression/action-block.json | Adds explicit request/response schema and expected http_code for parser errors |
| test/test-cases/regression/action-allow.json | Adds explicit request/response schema and expected http_code |
| test/regression/regression_test.h | Adds formatting-related fields, switches to unique_ptr/optional, introduces RegressionTests |
| test/regression/regression.cc | Adds format mode that writes normalized JSON and optionally updates Content-Length |
| test/common/modsecurity_test.h | Modernizes member initialization and adds flags for format/content-length updating |
| test/common/modsecurity_test.cc | Adds format-mode JSON loading path and parses format positional + env var |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "uri":"/foo?q=attack", | ||
| "http_version": 1.1 | ||
| "uri": "/foo?q=attack", | ||
| "method": "", |
There was a problem hiding this comment.
An empty HTTP method is not a valid request line and is likely to break request construction/execution for this test. Use a concrete method (e.g., "GET") here (and ensure the rest of the test still sets/derives the expected hostname, since the expected debug log asserts [hostname: \"modsecurity.org\"]).
| "method": "", | |
| "method": "GET", |
| "uri": "", | ||
| "method": "", | ||
| "body": [ | ||
| "" | ||
| ] |
There was a problem hiding this comment.
These test cases assert HTTP outcomes (e.g., 403/200) but the newly added request fields use empty uri and method, which can produce an invalid HTTP request. Prefer a sane default like \"method\": \"GET\" and \"uri\": \"/\" (or omit these fields if the harness provides defaults) to keep the transaction structurally valid.
| "uri": "/", | ||
| "method": "POST", | ||
| "body": [ | ||
| "-----------------------------69343412719991675451336310646\n", |
There was a problem hiding this comment.
This test is explicitly named multipart-crlf, but the multipart boundary lines are terminated with \\n instead of \\r\\n while other lines use CRLF. If the intent is to test strict CRLF behavior, these boundaries should also end with \\r\\n (and the request Content-Length should be updated accordingly).
| "1.1\r\n", | ||
| "1.2\r\n", | ||
| "1.3\r\n", | ||
| "-----------------------------69343412719991675451336310646\n", |
There was a problem hiding this comment.
This test is explicitly named multipart-crlf, but the multipart boundary lines are terminated with \\n instead of \\r\\n while other lines use CRLF. If the intent is to test strict CRLF behavior, these boundaries should also end with \\r\\n (and the request Content-Length should be updated accordingly).
| "2.1\r\n", | ||
| "2.2\r\n", | ||
| "2.3\r\n", | ||
| "-----------------------------69343412719991675451336310646--\n" |
There was a problem hiding this comment.
This test is explicitly named multipart-crlf, but the multipart boundary lines are terminated with \\n instead of \\r\\n while other lines use CRLF. If the intent is to test strict CRLF behavior, these boundaries should also end with \\r\\n (and the request Content-Length should be updated accordingly).
| for (const auto &[name, tests] : test2) { | ||
| std::ofstream ofs{name}; |
There was a problem hiding this comment.
Using the unordered_map key (name) as the output path makes formatting behavior depend on how keys are constructed in load_test_json. Since you already set u->filename = file during load, it would be more robust to open tests[0]->filename (or the original file value) for writing, rather than relying on the map key.
| std::string filename; | ||
| std::string name; | ||
|
|
||
| std::vector<RegressionTest> tests; |
There was a problem hiding this comment.
Storing tests by value (std::vector<RegressionTest>) can cause expensive copies/moves when building or manipulating the collection, especially now that individual tests have multiple vectors/strings used for formatting. Consider storing std::vector<std::unique_ptr<RegressionTest>> (consistent with from_yajl_node ownership patterns elsewhere) or otherwise ensure construction avoids unnecessary copying.
| std::vector<RegressionTest> tests; | |
| std::vector<std::unique_ptr<RegressionTest>> tests; |
|
Hi @hnakamur, finally I was able to start to review this PR, but it's very huge... 😃, so I asked Copilot (mainly to review the tests' changes). It seems like everything is okay, Copilot made one suggestion - would you mind to take a look at that? And thank you again. |



what
formatsubcommand toregression_testscommand.Content-Lengthheader by running(cd test; UPDATE_CONTENT_LENGTH=1 ./regression_tests format)why
references