granttrace 2.5.3__tar.gz → 2.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. granttrace-2.6.0/CHANGELOG.md +611 -0
  2. granttrace-2.6.0/CODE_OF_CONDUCT.md +83 -0
  3. granttrace-2.6.0/CONTRIBUTING.md +109 -0
  4. {granttrace-2.5.3 → granttrace-2.6.0}/MANIFEST.in +5 -2
  5. granttrace-2.6.0/PKG-INFO +194 -0
  6. granttrace-2.6.0/README.md +167 -0
  7. granttrace-2.6.0/README.zh-CN.md +140 -0
  8. {granttrace-2.5.3 → granttrace-2.6.0}/SECURITY.md +14 -9
  9. granttrace-2.6.0/VERIFICATION.md +381 -0
  10. {granttrace-2.5.3 → granttrace-2.6.0}/api_sentinel.py +737 -633
  11. {granttrace-2.5.3 → granttrace-2.6.0}/config.schema.json +147 -4
  12. {granttrace-2.5.3 → granttrace-2.6.0}/core/__init__.py +4 -4
  13. granttrace-2.6.0/core/auditor.py +1500 -0
  14. granttrace-2.6.0/core/authorization.py +212 -0
  15. granttrace-2.6.0/core/bopla.py +308 -0
  16. granttrace-2.6.0/core/config_scaffold.py +411 -0
  17. granttrace-2.6.0/core/config_validation/__init__.py +5 -0
  18. granttrace-2.6.0/core/config_validation/base.py +196 -0
  19. granttrace-2.6.0/core/config_validation/bola.py +199 -0
  20. granttrace-2.6.0/core/config_validation/identities.py +363 -0
  21. granttrace-2.6.0/core/config_validation/readbacks.py +621 -0
  22. granttrace-2.6.0/core/config_validation/spec_checks.py +248 -0
  23. granttrace-2.6.0/core/config_validator.py +215 -0
  24. {granttrace-2.5.3 → granttrace-2.6.0}/core/demo.py +31 -9
  25. {granttrace-2.5.3 → granttrace-2.6.0}/core/diff.py +440 -172
  26. {granttrace-2.5.3 → granttrace-2.6.0}/core/evidence.py +183 -18
  27. {granttrace-2.5.3 → granttrace-2.6.0}/core/generator.py +156 -122
  28. {granttrace-2.5.3 → granttrace-2.6.0}/core/onboarding.py +1 -1
  29. {granttrace-2.5.3 → granttrace-2.6.0}/core/parameters.py +114 -16
  30. granttrace-2.6.0/core/parser.py +878 -0
  31. granttrace-2.6.0/core/remote_refs.py +873 -0
  32. {granttrace-2.5.3 → granttrace-2.6.0}/core/reporter.py +696 -526
  33. {granttrace-2.5.3 → granttrace-2.6.0}/core/reproduction.py +35 -8
  34. granttrace-2.6.0/core/request_builder.py +652 -0
  35. granttrace-2.6.0/core/results.py +302 -0
  36. {granttrace-2.5.3 → granttrace-2.6.0}/core/sarif.py +58 -2
  37. {granttrace-2.5.3 → granttrace-2.6.0}/core/transactions.py +69 -2
  38. granttrace-2.6.0/core/transport.py +158 -0
  39. granttrace-2.6.0/core/yaml_safety.py +98 -0
  40. {granttrace-2.5.3 → granttrace-2.6.0}/docs/advanced.md +12 -5
  41. granttrace-2.6.0/docs/assets/report-finding.png +0 -0
  42. granttrace-2.6.0/docs/assets/report-preview.png +0 -0
  43. granttrace-2.6.0/docs/authorization-coverage-audit.md +282 -0
  44. granttrace-2.6.0/docs/bopla-readonly.md +59 -0
  45. {granttrace-2.5.3 → granttrace-2.6.0}/docs/business-scenarios.md +1 -1
  46. granttrace-2.6.0/docs/case-studies/crapi.md +240 -0
  47. granttrace-2.6.0/docs/case-studies/vampi.md +253 -0
  48. granttrace-2.6.0/docs/comparison.md +80 -0
  49. granttrace-2.6.0/docs/configuration.md +232 -0
  50. granttrace-2.6.0/docs/parameter-serialization.md +38 -0
  51. granttrace-2.6.0/docs/pr42-independent-review.md +145 -0
  52. granttrace-2.6.0/docs/pr42-state-authority-review.md +98 -0
  53. granttrace-2.6.0/docs/pr43-integration-plan.md +66 -0
  54. granttrace-2.6.0/docs/pr43-integration-review.md +180 -0
  55. granttrace-2.6.0/docs/remote-references.md +123 -0
  56. {granttrace-2.5.3 → granttrace-2.6.0}/docs/windows-portable.md +30 -17
  57. granttrace-2.6.0/examples/README.md +65 -0
  58. granttrace-2.6.0/examples/crapi/no-chatbot.compose.yml +10 -0
  59. granttrace-2.6.0/examples/crapi/prepare_config.py +185 -0
  60. {granttrace-2.5.3 → granttrace-2.6.0}/examples/sample_report.html +157 -159
  61. {granttrace-2.5.3 → granttrace-2.6.0}/examples/sample_result.json +666 -647
  62. granttrace-2.6.0/examples/vampi/prepare_config.py +105 -0
  63. granttrace-2.6.0/examples/vampi/run_vampi.py +22 -0
  64. granttrace-2.6.0/granttrace.egg-info/PKG-INFO +194 -0
  65. granttrace-2.6.0/granttrace.egg-info/SOURCES.txt +174 -0
  66. {granttrace-2.5.3 → granttrace-2.6.0}/pyproject.toml +76 -76
  67. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/build_windows_portable.py +3 -3
  68. granttrace-2.6.0/scripts/verify_authorization_coverage.py +335 -0
  69. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/verify_examples.py +46 -22
  70. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/verify_install.py +10 -10
  71. granttrace-2.6.0/scripts/verify_pr42_adversarial.py +70 -0
  72. granttrace-2.6.0/scripts/verify_pr43_integration.py +275 -0
  73. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/verify_windows_portable.py +2 -2
  74. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_auditor_integration.py +11 -1
  75. granttrace-2.6.0/tests/test_auth_cookie_references.py +312 -0
  76. granttrace-2.6.0/tests/test_auth_header_references.py +368 -0
  77. granttrace-2.6.0/tests/test_authorization_maintenance.py +184 -0
  78. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_authorization_policy_preflight.py +2 -2
  79. granttrace-2.6.0/tests/test_bopla_collection_grouping.py +67 -0
  80. granttrace-2.6.0/tests/test_bopla_integration.py +549 -0
  81. granttrace-2.6.0/tests/test_bopla_pending_exports.py +154 -0
  82. granttrace-2.6.0/tests/test_bopla_policy.py +212 -0
  83. granttrace-2.6.0/tests/test_bopla_policy_counterexamples.py +372 -0
  84. granttrace-2.6.0/tests/test_bopla_reports.py +190 -0
  85. granttrace-2.6.0/tests/test_bopla_transport_safety.py +296 -0
  86. granttrace-2.5.3/tests/test_rc2_security_hardening.py → granttrace-2.6.0/tests/test_cli_security_hardening.py +395 -395
  87. granttrace-2.6.0/tests/test_code_review_regressions.py +162 -0
  88. granttrace-2.6.0/tests/test_committed_examples.py +80 -0
  89. granttrace-2.6.0/tests/test_config_scaffold.py +433 -0
  90. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_curl_report.py +3 -0
  91. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_demo.py +24 -3
  92. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_diff.py +1 -1
  93. granttrace-2.6.0/tests/test_english_reasons.py +128 -0
  94. granttrace-2.6.0/tests/test_expanded_detection.py +599 -0
  95. granttrace-2.6.0/tests/test_expanded_report_boundaries.py +90 -0
  96. granttrace-2.6.0/tests/test_header_cookie_array_object.py +1424 -0
  97. granttrace-2.6.0/tests/test_header_cookie_boundaries.py +177 -0
  98. granttrace-2.6.0/tests/test_header_cookie_parameters.py +991 -0
  99. granttrace-2.6.0/tests/test_header_cookie_transport.py +184 -0
  100. granttrace-2.6.0/tests/test_late_private_value_redaction.py +361 -0
  101. granttrace-2.6.0/tests/test_mass_assignment_flow.py +160 -0
  102. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_merge_patch_recovery.py +1 -0
  103. granttrace-2.6.0/tests/test_module_boundaries.py +80 -0
  104. granttrace-2.6.0/tests/test_not_found_denial.py +207 -0
  105. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_onboarding_cli.py +20 -2
  106. granttrace-2.6.0/tests/test_output_snapshot.py +166 -0
  107. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_parameter_serialization.py +13 -3
  108. granttrace-2.6.0/tests/test_parser_remote_refs.py +536 -0
  109. granttrace-2.6.0/tests/test_parser_replacement_auth.py +476 -0
  110. granttrace-2.5.3/tests/test_release_transactions.py → granttrace-2.6.0/tests/test_patch_readback_strictness.py +3 -0
  111. granttrace-2.6.0/tests/test_pr42_adversarial.py +396 -0
  112. granttrace-2.6.0/tests/test_pr42_state_authority.py +307 -0
  113. granttrace-2.6.0/tests/test_pr43_authorization_evidence.py +374 -0
  114. granttrace-2.6.0/tests/test_pr43_evidence_paths.py +77 -0
  115. granttrace-2.6.0/tests/test_pr43_put_safety.py +390 -0
  116. granttrace-2.6.0/tests/test_problem_details_denials.py +97 -0
  117. granttrace-2.6.0/tests/test_query_auth_parameters.py +173 -0
  118. granttrace-2.6.0/tests/test_rate_limit_retry.py +225 -0
  119. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_read_only_path_guards.py +8 -8
  120. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_read_only_safety.py +2 -2
  121. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_read_safety_cache.py +3 -3
  122. granttrace-2.6.0/tests/test_remote_ref_host_validation.py +205 -0
  123. granttrace-2.6.0/tests/test_remote_refs.py +557 -0
  124. granttrace-2.6.0/tests/test_remote_refs_hardening.py +1161 -0
  125. granttrace-2.6.0/tests/test_remote_refs_premerge_audit.py +397 -0
  126. granttrace-2.6.0/tests/test_remote_refs_review_hardening.py +251 -0
  127. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_sarif.py +8 -2
  128. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_sarif_cli.py +24 -1
  129. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_scan_accounting.py +1 -1
  130. granttrace-2.6.0/tests/test_small_review_items.py +213 -0
  131. granttrace-2.5.3/tests/test_v22_auditor_hardening.py → granttrace-2.6.0/tests/test_transaction_transport_hardening.py +3 -2
  132. granttrace-2.6.0/tests/test_transport.py +153 -0
  133. granttrace-2.6.0/tests/test_unconfigured_query_parameters.py +91 -0
  134. granttrace-2.5.3/tests/test_release_identity.py → granttrace-2.6.0/tests/test_version_identity.py +26 -0
  135. granttrace-2.6.0/tests/test_yaml_alias_expansion.py +214 -0
  136. granttrace-2.5.3/CHANGELOG.md +0 -311
  137. granttrace-2.5.3/CONTRIBUTING.md +0 -65
  138. granttrace-2.5.3/PKG-INFO +0 -192
  139. granttrace-2.5.3/README.md +0 -165
  140. granttrace-2.5.3/VERIFICATION.md +0 -172
  141. granttrace-2.5.3/core/auditor.py +0 -1344
  142. granttrace-2.5.3/core/config_scaffold.py +0 -254
  143. granttrace-2.5.3/core/config_validator.py +0 -1590
  144. granttrace-2.5.3/core/parser.py +0 -519
  145. granttrace-2.5.3/docs/assets/report-preview.png +0 -0
  146. granttrace-2.5.3/docs/configuration.md +0 -143
  147. granttrace-2.5.3/docs/parameter-serialization.md +0 -19
  148. granttrace-2.5.3/examples/README.md +0 -36
  149. granttrace-2.5.3/granttrace.egg-info/PKG-INFO +0 -192
  150. granttrace-2.5.3/granttrace.egg-info/SOURCES.txt +0 -98
  151. granttrace-2.5.3/tests/test_config_scaffold.py +0 -197
  152. {granttrace-2.5.3 → granttrace-2.6.0}/LICENSE +0 -0
  153. {granttrace-2.5.3 → granttrace-2.6.0}/config.example.json +0 -0
  154. {granttrace-2.5.3 → granttrace-2.6.0}/core/demo_assets/__init__.py +0 -0
  155. {granttrace-2.5.3 → granttrace-2.6.0}/core/demo_assets/demo-config.json +0 -0
  156. {granttrace-2.5.3 → granttrace-2.6.0}/core/demo_assets/mock-data.json +0 -0
  157. {granttrace-2.5.3 → granttrace-2.6.0}/core/demo_assets/openapi.json +0 -0
  158. {granttrace-2.5.3 → granttrace-2.6.0}/core/models.py +0 -0
  159. {granttrace-2.5.3 → granttrace-2.6.0}/core/scan_safety.py +0 -0
  160. {granttrace-2.5.3 → granttrace-2.6.0}/docs/authorization-audit-hardening.md +0 -0
  161. {granttrace-2.5.3 → granttrace-2.6.0}/docs/history/release-checklist-history.md +0 -0
  162. {granttrace-2.5.3 → granttrace-2.6.0}/docs/history/release-verification-history.md +0 -0
  163. {granttrace-2.5.3 → granttrace-2.6.0}/docs/release-checklist.md +0 -0
  164. {granttrace-2.5.3 → granttrace-2.6.0}/granttrace.egg-info/dependency_links.txt +0 -0
  165. {granttrace-2.5.3 → granttrace-2.6.0}/granttrace.egg-info/entry_points.txt +0 -0
  166. {granttrace-2.5.3 → granttrace-2.6.0}/granttrace.egg-info/requires.txt +0 -0
  167. {granttrace-2.5.3 → granttrace-2.6.0}/granttrace.egg-info/top_level.txt +0 -0
  168. {granttrace-2.5.3 → granttrace-2.6.0}/mock_server/__init__.py +0 -0
  169. {granttrace-2.5.3 → granttrace-2.6.0}/mock_server/server.py +0 -0
  170. {granttrace-2.5.3 → granttrace-2.6.0}/openapi.json +0 -0
  171. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/benchmark_read_safety.py +0 -0
  172. {granttrace-2.5.3 → granttrace-2.6.0}/scripts/verify_business_scenarios.py +0 -0
  173. {granttrace-2.5.3 → granttrace-2.6.0}/setup.cfg +0 -0
  174. {granttrace-2.5.3 → granttrace-2.6.0}/test_suite.py +0 -0
  175. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_authorization_evidence_hardening.py +0 -0
  176. /granttrace-2.5.3/tests/test_release_bola.py → /granttrace-2.6.0/tests/test_bola_rejection_evidence.py +0 -0
  177. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_business_authorization.py +0 -0
  178. /granttrace-2.5.3/tests/test_rc3_hardening.py → /granttrace-2.6.0/tests/test_cli_config_preflight.py +0 -0
  179. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_cli_report_boundaries.py +0 -0
  180. /granttrace-2.5.3/tests/test_release_config.py → /granttrace-2.6.0/tests/test_config_readback_preflight.py +0 -0
  181. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_config_validation.py +0 -0
  182. /granttrace-2.5.3/tests/test_release_evidence.py → /granttrace-2.6.0/tests/test_credential_echo_redaction.py +0 -0
  183. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_diff_hardening.py +0 -0
  184. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_evidence.py +0 -0
  185. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_first_run_guidance.py +0 -0
  186. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_onboarding.py +0 -0
  187. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_parameter_compatibility.py +0 -0
  188. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_parser_generator_hardening.py +0 -0
  189. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_report_usability.py +0 -0
  190. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_reproduction.py +0 -0
  191. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_schema_regressions.py +0 -0
  192. {granttrace-2.5.3 → granttrace-2.6.0}/tests/test_spec_config_cross_checks.py +0 -0
@@ -0,0 +1,611 @@
1
+ # Changelog
2
+
3
+ ## 2.6.0 - 2026-11-09
4
+
5
+ ### Added
6
+
7
+ - Read-only Broken Authentication (CWE-306, SARIF `GT-AUTH-001`) and Broken
8
+ Function Level Authorization (CWE-285, `GT-BFLA-001`) checks, and private-data
9
+ checks for collection endpoints (CWE-639). Confirmation requires explicitly
10
+ configured `private_data_paths` and role policy; names and keywords alone stay
11
+ leads (#43).
12
+ - PUT mass-assignment checks that use complete replacement snapshots and verified
13
+ rollback. Like PATCH, they run only with independent authoritative resource
14
+ state, which only internal test fixtures provide (the bundled demo tests
15
+ PATCH); external CLI targets stay blocked before any write (#43).
16
+ - Evidence-bound read-only property authorization (BOPLA, CWE-200) driven by
17
+ explicit per-operation `bopla` field rules and resource bindings (#44).
18
+ - GET header and cookie parameters, including header arrays and objects, sent
19
+ from `parameter_values`; authentication headers and cookies stay
20
+ identity-scoped and cookie arrays/objects are rejected under RFC 6265
21
+ (#45, #46). Swagger 2 header values are validated before transport (#47).
22
+ - Opt-in remote `$ref` resolution over HTTPS (`--allow-remote-refs` with
23
+ `--remote-ref-host`): exact host allowlist, SSRF and DNS-rebinding defences,
24
+ no redirects, size/count/depth/time limits, and no fetching in offline modes.
25
+ See [docs/remote-references.md](docs/remote-references.md) (#48).
26
+ - `--init-config` drafts the remaining inputs a scan needs, as placeholders
27
+ that still block validation until replaced. Required GET business headers and
28
+ cookies get one value per requesting identity (owner, visitor and anonymous)
29
+ in `parameter_values`; required authentication headers go to owner's and
30
+ visitor's `identities.*.headers`, and required authentication cookies to their
31
+ `identities.*.parameters` (#74 stopped drafting optional authentication
32
+ headers). PUT operations get parameter values and a readback
33
+ draft like PATCH, with the extra PUT rules in the checklist. Optional
34
+ parameters, ignored headers such as `Accept` and unsupported cookie forms
35
+ are not drafted, and the checklist says why for each. A draft completed with
36
+ real values now plans every drafted GET check, where previously its required
37
+ headers and cookies were missing. The checklist no longer marks parameters of
38
+ operations GrantTrace does not test, such as DELETE, as included in the
39
+ draft (#73).
40
+ - A case study of a scan of VAmPI, a deliberately vulnerable API, in its
41
+ vulnerable and secure modes: which of its vulnerabilities GrantTrace confirms,
42
+ which it misses and why, and the request log of the read-only scan. Helper
43
+ scripts in `examples/vampi/` reproduce it. See
44
+ [docs/case-studies/vampi.md](docs/case-studies/vampi.md) (#81).
45
+ - `bola.<operation>.not_found_is_denial` reads a 404 as a denial, for APIs
46
+ that hide other users' objects with "not found" instead of 403. A Visitor or
47
+ Anonymous 404 counts only when the Owner received a valid response to the
48
+ same request, the body is empty or only says the object was not found (a
49
+ full-message grammar with at most one word naming the resource type, in a
50
+ known error envelope or Problem Details), and none of the Owner's values
51
+ appears in it; any other 404 keeps its default meaning, `INCONCLUSIVE`.
52
+ BOLA, Broken Authentication, BFLA and collection checks of the operation
53
+ apply it; BOPLA field rules do not. A 404 denial gives `SECURE` with
54
+ confidence 0.95, below an explicit 401 or 403, and the evidence records the
55
+ setting. Secure-mode VAmPI's book lookup now reports `SECURE` instead of
56
+ `INCONCLUSIVE` (#82).
57
+ - The VAmPI case study confirms the debug endpoint's password exposure with a
58
+ BOPLA field rule: the Owner's password in `/users/v1/_debug` may be read by
59
+ the Owner only, although the specification leaves the endpoint open, so both
60
+ the Visitor and Anonymous results are `CONFIRMED` (`GT-BOPLA-001`) in both
61
+ modes. `examples/vampi/prepare_config.py --debug-field-rule` writes the rule;
62
+ it runs as a separate scan because BOPLA's privacy boundary omits response
63
+ details from the whole report. The configuration guide now points to field
64
+ rules for private fields on operations without an authentication
65
+ requirement (#83).
66
+ - A case study of a read-only scan of OWASP crAPI 1.1.6: GrantTrace confirms
67
+ another user's mechanic report (challenge 2), the order lookup without
68
+ authentication (challenge 14), an administrator user list any user can read,
69
+ and, with BOPLA field rules, post authors' email addresses and vehicle IDs
70
+ (challenge 4). Challenge 1 stays `SUSPICIOUS` because crAPI's identity service
71
+ answers requests without a token with a Java `toString()` instead of JSON.
72
+ `examples/crapi/` holds the setup script and a Compose override that runs
73
+ crAPI without its chatbot. See
74
+ [docs/case-studies/crapi.md](docs/case-studies/crapi.md) (#85).
75
+ - A comparison of GrantTrace's approach with Autorize, AuthMatrix, ZAP's Access
76
+ Control Testing add-on and Akto, from their documentation: where requests come
77
+ from, what is expected, how a result is decided, and when another tool fits
78
+ better. It compares approaches, not detection rates. See
79
+ [docs/comparison.md](docs/comparison.md) (#86).
80
+
81
+ ### Changed
82
+
83
+ - Synchronize package, runtime, Windows distribution and release-workflow
84
+ versions to `2.6.0`, a minor release for the checks and options added since
85
+ 2.5.3. The remote `$ref` fetcher's User-Agent now follows the runtime version
86
+ instead of a hard-coded `2.5.3`. Refresh release documentation and the example
87
+ reports.
88
+ - Rewrite the README as an English project page, with a Chinese translation in
89
+ `README.zh-CN.md`: what GrantTrace does and a quick start first, a table of the
90
+ checks with what each needs, and a plain list of what is not supported. Mass
91
+ assignment is described as demo-only, as it is for external APIs. The report
92
+ screenshot is retaken from the 2.6.0 demo, a confirmed-finding screenshot is
93
+ added, and the README no longer states a release status that each release had
94
+ to update. Chinese documentation links back to the Chinese README (#79).
95
+ - Report BOLA reasons in English, like every other check. The JSON `reason`,
96
+ finding `details` and per-response `reason` evidence of BOLA checks were the
97
+ only Chinese reasons; the HTML report shows the same text. Verdicts,
98
+ `reason_category` and evidence fields are unchanged, and Chinese denial
99
+ messages returned by a target API are still recognized. Consumers that
100
+ matched the Chinese text should match the verdict or `reason_category`.
101
+ Offline validation messages no longer append a Chinese note. The HTML
102
+ report's interface text stays Chinese (#57).
103
+ - Store every text file with LF line endings (`.gitattributes` now normalizes
104
+ them; the Windows portable build still writes CRLF for its batch launcher),
105
+ and name 13 test modules after the behavior they cover instead of the PR or
106
+ release that added them. No runtime change (#58).
107
+ - Regenerate the example reports in `examples/` from the built-in demo. They
108
+ were still the 2.5.3 output, with Chinese BOLA reasons and without the newer
109
+ statistics, and showed PATCH results that a CLI scan of an external target no
110
+ longer produces, because such scans stop PATCH checks before any write.
111
+ `scripts/verify_examples.py --update-examples` now copies a fresh
112
+ `granttrace demo` run after verifying the CLI scans, and a new test fails when
113
+ the committed examples no longer match a fresh demo run. No runtime change (#70).
114
+
115
+ ### Performance
116
+
117
+ - Parse each response once and reuse comparison data in BOLA evaluation, cache
118
+ key normalization, precompile evidence scrubbing patterns and skip redundant
119
+ path resolution while resolving schemas. Outputs are unchanged; on 150 KB
120
+ responses and 300-operation specifications these paths run about twice as
121
+ fast (#50).
122
+ - Reuse response assessments across BOPLA field rules: ten rules on a 496 KB
123
+ response took 271 ms and now take 14 ms, with identical decisions (#55).
124
+
125
+ ### Fixed
126
+
127
+ - Recognize RFC 9457 (RFC 7807) Problem Details bodies as clean 401/403 denials.
128
+ connexion sends them as `application/problem+json`, for example `{"type":
129
+ "about:blank", "title": "Unauthorized", "status": 401, "detail": "No
130
+ authorization token provided"}`, and ASP.NET Core and Spring can be configured
131
+ to. GrantTrace treated these members as possible business data, so a scan of
132
+ VAmPI, a deliberately vulnerable API, reported its book BOLA as `SUSPICIOUS`
133
+ instead of `CONFIRMED`, and Broken Authentication on its protected reads as
134
+ `INCONCLUSIVE` instead of `SECURE`: the anonymous denial could not serve as a
135
+ clean baseline. A problem body now counts as a denial only when every member
136
+ is `type`, `title`, `status`, `detail` or a tracing ID, `status` is 401 or
137
+ 403, `type` is `about:blank` or an HTTP RFC status link, and `title` and
138
+ `detail` are denial messages. Any other member or text keeps it suspicious,
139
+ including `instance`: the check does not know the request path, so it cannot
140
+ tell whether the URI names the requested resource or another user's. Ordinary
141
+ JSON envelopes also accept a numeric `status` of 401 or 403 and messages such
142
+ as "No authorization token provided" (#80).
143
+ - Refuse checks of operations that send a credential in the query string, before
144
+ any request. Each URL is built from the resource owner's parameter values and
145
+ sent by every identity, so an `apiKey` scheme `in: query` (or the RFC 6750
146
+ `access_token` parameter) made the visitor and anonymous requests carry the
147
+ owner's key: against a correctly secured API they appeared to read the owner's
148
+ resource, giving false `SUSPICIOUS` or `CONFIRMED` results. Such checks are now
149
+ `INCONCLUSIVE` (`invalid_input`) with a reason saying query-string credentials
150
+ are not supported, and `--init-config` no longer drafts them as resource
151
+ parameters. Ordinary query parameters, including names such as `page_token`,
152
+ are unaffected (#75).
153
+ - Stop refusing GET checks over an optional authentication header that neither
154
+ owner nor visitor configures. A header parameter classified as authentication
155
+ (for example `X-Session-Id`, or an API-key scheme's header) blocked the check
156
+ as `INCONCLUSIVE` unless both identities sent it, even when the specification
157
+ marks it optional, and the reason wrongly said a value was "supplied via
158
+ parameter values". It is now omitted, like an optional authentication cookie.
159
+ A value from `parameter_values` and a header configured for only one of owner
160
+ and visitor are still refused, and a missing required one is refused with a
161
+ reason that says to configure it under `identities.*.headers` (#74).
162
+ - Stop sending invented values for optional query parameters that nobody
163
+ configured. Every declared query parameter got a generated value, so a scan
164
+ could request `?as_user=sample_text&status=active&include_deleted=false`:
165
+ such values can filter out the tested resource, make the target reject the
166
+ request or change its behavior, so the comparison no longer measured
167
+ authorization. An unconfigured optional query parameter is now omitted, or
168
+ sent with its declared `default`, as header and cookie parameters already
169
+ were. Required parameters and resource identifiers such as `owner_id` keep
170
+ their previous values (#76).
171
+ - Use an identity's `id` for its resource parameter exactly or not at all.
172
+ Lenient integer parsing turned `"007"`, `"1_001"` or `" 1002 "` into 7, 1001
173
+ or 1002, and an id outside the schema (such as `"abc"`, or `"0"` below a
174
+ minimum) was silently replaced by the specification's example value, so the
175
+ check tested a resource the Owner does not own. Such ids now follow the
176
+ canonical rules of `parameter_values`, and a check that cannot use them is
177
+ `INCONCLUSIVE` (`invalid_input`) before any request (#55).
178
+ - Ignore non-string media types instead of crashing with `AttributeError`, for
179
+ example a Swagger 2 `consumes: [123, "application/json"]` (#55).
180
+ - Reject header parameter values with leading or trailing whitespace, which
181
+ servers strip inconsistently, so the tested value always matches the
182
+ configured one; whitespace inside a value is still allowed (#55).
183
+ - Publish secret values discovered while building request headers by atomic
184
+ replacement. The in-place update raced with evidence sanitization in other
185
+ workers and could drop a value from later redaction (#50).
186
+ - Report the specific "without precision loss" diagnostic for number parameter
187
+ strings instead of the generic message that replaced it (#50).
188
+ - Require TLS 1.2 or later for remote schema fetches (#50).
189
+ - Retry rate-limited reads instead of recording them as inconclusive. GET
190
+ requests answered with HTTP 429 (or 503 with `Retry-After`) are retried up
191
+ to twice, honoring `Retry-After` in seconds or as an HTTP date (otherwise
192
+ waiting 1 s, then 2 s), and every worker pauses meanwhile. A requested wait
193
+ beyond 30 s fails closed with the original response. PATCH/PUT are never
194
+ retried. The new `rate_limit_retries` statistic counts retries; a scan of
195
+ the bundled mock target that rate-limits each path's first request now
196
+ reaches the same verdicts as an unlimited one (#53).
197
+ - Enforce the remote `$ref` fetch timeout as an absolute deadline. Socket
198
+ timeouts applied per receive, so a server dripping header or body bytes held
199
+ a 0.3 s fetch for 3 s or longer; a close-delimited body cut off at the
200
+ deadline is no longer accepted as complete (#52).
201
+ - Reject remote documents that end before their declared Content-Length, and
202
+ turn malformed HTTP responses and over-nested JSON into per-reference
203
+ resolution failures instead of errors that aborted the whole scan (#52).
204
+ - Check the IPv4 destination embedded in 6to4, Teredo and NAT64 addresses and
205
+ block IPv4-compatible, local-use NAT64 and site-local IPv6 ranges. CPython
206
+ releases before its 2024 `ipaddress` update (e.g. 3.9.19, 3.12.3) treated
207
+ 6to4 addresses embedding 169.254.169.254 or 127.0.0.1 as global (#52).
208
+ - Report a path item whose remote `$ref` fails as `INCONCLUSIVE`
209
+ (`unresolved_reference`), as documented, instead of a skipped "UNKNOWN"
210
+ method that `--fail-on-error` did not count (#52).
211
+ - Reject `--remote-ref-host` values that can never match a `$ref` URL host:
212
+ a scheme, port, path, credentials, wildcard, whitespace, non-ASCII
213
+ characters (use the IDNA form) or an empty value. Such values were accepted
214
+ and then authorized nothing, so every remote reference failed later as
215
+ "not in the authorized allowlist". The CLI exits 2 and names the value. IPv6
216
+ literals are compared in canonical form, with or without brackets.
217
+ - Bound YAML anchor/alias expansion in local specifications, referenced YAML
218
+ files and remote `$ref` documents. A ~1 KB alias "bomb" previously stalled
219
+ parsing for 13 s or more (merge keys inside `yaml.safe_load` itself); aliases
220
+ may now add at most max(250,000, 10 x the document's own nodes) nodes, and
221
+ recursive aliases are rejected before any object is built or request is sent (#51).
222
+ - Fail closed before external CLI PATCH tests when authoritative resource state
223
+ cannot be independently observed; write flags, mappings and a declared strong
224
+ readback cannot supply that proof. Existing CLI/config syntax remains accepted.
225
+ - Check initial, post-write and restored HTTP documents against actual backing
226
+ state in the owned disposable Demo. Retain global write halt on unavailable
227
+ or contradictory restoration evidence, including queued concurrent callers.
228
+ - Preserve and retest both original unmarked-cache counterexamples; distinguish
229
+ generic HTTP blocking from state-backed fixture detection statistics.
230
+
231
+ - PR #42 follow-up review: reject explicitly aged/stale state evidence, require
232
+ previously observed business structure before confirming persistence, and
233
+ serialize direct write-audit calls so waiting callers observe recovery failures.
234
+ - Add independent adversarial regressions and disclose two unresolved unmarked
235
+ stale-response probes; distinguish statement, branch and combined code coverage.
236
+ - Require complete HTTP 200 JSON state readbacks without Content-Range before
237
+ using them as PATCH snapshots, persistence evidence or restoration evidence.
238
+ Preserve generic write acknowledgement handling, recovery and fail-closed write halting.
239
+ - Retain strong Owner-object matches in 4xx/5xx response bodies as suspicious
240
+ leads only, without changing confirmation or SARIF export requirements.
241
+ - Include explicitly readOnly fields with ordinary names in mutation candidates;
242
+ configured field mappings, write opt-in, allowlists and reversible snapshots still gate execution.
243
+ - Prefer a declared JSON consumes format for Swagger 2 bodies and explain more
244
+ existing preflight exclusions in offline plans.
245
+ - Add fixed-truth loopback acceptance scenarios, regression tests and a source-linked
246
+ capability audit with before/after measurements. No new vulnerability class is implemented.
247
+
248
+ ### Maintenance
249
+
250
+ - Restructure the largest modules and functions without changing behavior
251
+ (#59 to #69). Snapshot tests of the JSON, HTML and console output of mock-target
252
+ scans came first and passed unchanged through the series; a deliberate output
253
+ change regenerates them with `GRANTTRACE_UPDATE_SNAPSHOTS=1` (#59).
254
+ `core/auditor.py` shrank from 2283 to 1499 lines: HTTP transport moved to
255
+ `core/transport.py`, request construction to `core/request_builder.py`, and
256
+ result recording and coverage to `core/results.py` (#61, #62, #63).
257
+ `core/config_validator.py` shrank from 1735 to 250 lines: its checks moved to
258
+ the `core/config_validation/` package, one module per configuration section,
259
+ and `ConfigValidator` and its result types are still imported from
260
+ `core.config_validator` (#65). The mass-assignment check, request header
261
+ construction, readback validation, schema value validation, the CLI `main`,
262
+ BOLA evaluation and the HTML report were split into smaller steps (#62, #63,
263
+ #64, #66, #67, #68, #69). Moved code is unchanged apart from names. Most
264
+ splits were compared with the previous code over large random inputs, and the
265
+ CLI over 34 command lines, with identical results; new tests cover the
266
+ per-field branches of the mass-assignment check. The seven hash-pinned write
267
+ methods are untouched, and a new test fails if production code uses another
268
+ module's private member (#60).
269
+ - Split `ConfigValidator.validate` (220 lines) into named steps with one
270
+ section runner instead of five copies of the same error handling. A
271
+ differential run over 40,000 mutated configurations gave identical results
272
+ (#77).
273
+ - Code that imports `core` directly needs these changes; the CLI and
274
+ `granttrace demo` are unaffected:
275
+ - Helpers used across modules lost their leading underscore, and the old
276
+ names were removed: `ResponseDiffEngine.assess_response`,
277
+ `assessment_evidence`, `normalise_key`, `is_request_metadata_key` and
278
+ `denial_body_is_clean`; `AuthorizationEvidence.assess`, `valid`,
279
+ `private_values` and `clean_denial`; `SmartDataGenerator.parameter_schema`
280
+ and `is_resource_identifier`; `APISentinelAuditor.identity_headers`. The new
281
+ `APISentinelAuditor.secret_values()` returns an immutable snapshot of the
282
+ published secrets (#60).
283
+ - `RETRYABLE_METHODS`, `RATE_LIMIT_RETRIES`, `RATE_LIMIT_BACKOFF` and
284
+ `MAX_RETRY_WAIT` moved from `APISentinelAuditor` to
285
+ `core.transport.HttpTransport`. The redirect handler is
286
+ `core.transport.NoRedirectHandler` (was `core.auditor._NoRedirectHandler`),
287
+ and the auditor's opener is `_transport.opener` (was `_opener`) (#61).
288
+ - `request_delay`, `request_timeout` and `max_response_bytes` are read-only
289
+ properties of `APISentinelAuditor`. Pass them to the constructor: assigning
290
+ them afterwards raises `AttributeError` (#61).
291
+ - `_http_request` and `_authoritative_patch_state` are documented extension
292
+ points and keep their names and signatures (#60).
293
+ - Documentation: the v2.5.3 post-release acceptance records (#36 to #41), user
294
+ documentation synced with merged behavior (#54), the contributing guide's
295
+ output checks (#72) and the first release-preparation record (#78). Before
296
+ release, SECURITY.md, the command-line reference and the configuration guide
297
+ now state that write checks against an external target stop before any write;
298
+ the package description no longer lists mass assignment, which only the
299
+ built-in demo performs; the command-line reference documents `--workers` and
300
+ `--timeout`; a Code of Conduct (Contributor Covenant 2.1) is added; and the
301
+ Windows guide describes the released state (#87).
302
+
303
+ ## 2.5.3 - 2026-10-15
304
+
305
+ ### Fixed
306
+
307
+ - [PR #33](https://github.com/ysc070528/granttrace/pull/33): recognize complete
308
+ authentication and permission denial messages, including JWT denials, without
309
+ treating rejected responses containing business data as clean denials. Explain
310
+ Owner, Visitor self-resource and Anonymous evidence and missing prerequisites;
311
+ retain conservative BOLA / IDOR confirmation requirements.
312
+ - Validate selected BOLA policies before HTTP requests and accept the existing
313
+ `items[].id` trusted-evidence selector syntax in configuration validation.
314
+ - Count actual transport attempts and distinct method/path operations for
315
+ attempted and conclusive coverage. Exclude zero-request preflight outcomes
316
+ and recovery rows from endpoint coverage; explain skip and evidence categories
317
+ in reports. `SUSPICIOUS` and `INCONCLUSIVE` remain non-conclusive.
318
+ - Apply read-only side-effect checks using operation identifiers, paths,
319
+ summaries and descriptions during BOLA preflight, dry-run planning and final
320
+ HTTP execution. Reject unsafe independent readbacks before any PATCH.
321
+ - [PR #34](https://github.com/ysc070528/granttrace/pull/34): validate each concrete
322
+ GET / HEAD path, including the target base path, before route-cache lookup and
323
+ transport. Reject ambiguous encodings, invalid UTF-8, dot/matrix-dot segments,
324
+ repeated slashes, boundary encoded slashes, backslashes and control characters.
325
+ Apply the same guard to BOLA, offline plans and PATCH readbacks without rewriting
326
+ URLs; ordinary supported encoded identifiers remain supported.
327
+
328
+ ### Changed
329
+
330
+ - Reuse cached immutable read-safety metadata and route patterns from PR #33
331
+ while continuing to validate every concrete URL before requests.
332
+ - Synchronize package, runtime, Windows distribution and release-workflow
333
+ versions to `2.5.3`; refresh release documentation and generated loopback
334
+ examples. This release preparation introduces no new detector or API behavior.
335
+
336
+ Static read-safety checks do not prove that every GET is harmless. Verification
337
+ scope and remaining post-release acceptance are recorded in [VERIFICATION.md](VERIFICATION.md).
338
+
339
+ ## 2.5.2 - 2026-10-05
340
+
341
+ ### Maintenance
342
+
343
+ - Documentation / distribution metadata maintenance release: package the current
344
+ README for the PyPI project page, retaining the corrected Windows download,
345
+ unsigned-program notice, macOS / Linux installation and workflow explanation.
346
+ - Align package/runtime versions and Windows portable filenames, launcher,
347
+ bundled instructions and release workflow metadata at `2.5.2`.
348
+ - No changes to BOLA / IDOR / Mass Assignment detection, the security model,
349
+ default read-only behavior, CLI semantics or core implementation.
350
+
351
+ ## 2.5.1 - 2026-10-05
352
+
353
+ ### Fixed
354
+
355
+ - Reject unsafe Merge Patch probes before writes when the original state cannot be restored exactly.
356
+ - Preserve array record associations during BOLA comparison to avoid overstating confirmed authorization bypasses.
357
+ - Harden report target/metadata redaction for known credentials and prevent report outputs from overwriting specification, configuration, or loaded local `$ref` inputs.
358
+ - Improve local and conditional schema resolution plus configuration-to-spec operation validation.
359
+ - Preserve legacy v2.5.0 scalar parameter configurations while applying strict schema-aware normalization and validation for canonical integer, number, and boolean values.
360
+ - Preserve Swagger 2.0 `uniqueItems` parameter constraints during schema extraction so duplicate configured arrays fail validation before requests.
361
+
362
+ ## 2.5.0 - 2026-10-04
363
+
364
+ ### Added
365
+
366
+ - Export SARIF 2.1.0 with `--export-sarif`, alongside HTML and JSON reports.
367
+ Only existing CONFIRMED findings produce results: BOLA / IDOR maps to
368
+ `GT-BOLA-001` / `CWE-639`, and Mass Assignment to `GT-MASS-001` / `CWE-915`.
369
+ A safely represented OpenAPI file inside the workspace supplies the artifact
370
+ location for GitHub Code Scanning; no source lines or endpoint files are invented.
371
+ - Add safe cURL reproduction templates and copy buttons to confirmed HTML finding
372
+ cards. Use the actual tested URL and confirmed injected payload where safe,
373
+ Visitor credential placeholders, POSIX shell quoting and `curl --globoff`.
374
+ Clipboard fallback supports offline reports; manual selection works without
375
+ JavaScript. Real credentials never enter the templates, including when sensitive
376
+ report evidence is enabled.
377
+ - Guide configuration onboarding from draft generation and manual review through
378
+ validation, a local dry-run and a read-only first real scan. Distinguish
379
+ config-only from spec-aware validation, summarize dry-run counts, and format
380
+ next-step commands safely for POSIX shells or PowerShell.
381
+
382
+ ### Changed
383
+
384
+ - Align README, configuration and advanced guidance with the first API onboarding
385
+ flow and the SARIF / cURL outputs, without changing configuration formats.
386
+ - Explain validation scope, warnings and dry-run write eligibility more clearly.
387
+ An active PATCH configuration is separate from enabling active execution;
388
+ the recommended first real scan remains read-only.
389
+ - Promote the release source to `2.5.0` across package metadata, runtime version
390
+ and generated examples; prepare the release checklist and OIDC workflow for
391
+ the new tag without publishing it during release preparation.
392
+
393
+ ### Security / Safety
394
+
395
+ - Preserve BOLA / IDOR verdicts and Mass Assignment detection criteria, default
396
+ read-only auditing, and the existing TLS / HTTP / redirect / proxy boundaries.
397
+ - Active PATCH still requires explicit `--allow-write-tests`, an explicit write
398
+ allowlist, independent GET readback, original-state snapshots, rollback and
399
+ rollback verification. Failed recovery still halts further writes.
400
+ - SARIF, cURL templates and onboarding output do not expose real credentials;
401
+ onboarding also omits configured resource values. Workspace-external specs
402
+ never expose absolute local paths in SARIF.
403
+ - Validation and dry-run remain offline; dry-run sends zero requests. No active
404
+ POST / PUT testing or automated OAuth / login is added.
405
+
406
+ ### Quality
407
+
408
+ - Retain the 486-test baseline, Python 3.9 / 3.12 / 3.14 CI, blocking mypy and Ruff,
409
+ Runtime dependency audit, CodeQL and the branch-aware coverage gate of 80%.
410
+ - Fresh release-prep acceptance passes all 486 tests with **82.78%** branch-aware
411
+ local coverage, mypy reporting no issues in 18 source files, Ruff and the runtime
412
+ dependency audit. All six bundled business scenarios match their expected
413
+ outcomes; JSON / YAML scans restore the full mock database. A fresh wheel
414
+ installed outside the checkout passes both demo modes and verifies version
415
+ `2.5.0`, read-only 0 PATCH, active rollback and local server shutdown. See
416
+ [VERIFICATION.md](VERIFICATION.md) for the exact scope and remote check results.
417
+
418
+ ## 2.4.1 - 2026-10-03
419
+
420
+ ### Added
421
+
422
+ - Add `granttrace demo` with packaged OpenAPI, configuration and fictional mock
423
+ data, so an installed wheel can demonstrate identity comparison, BOLA / IDOR,
424
+ Mass Assignment, independent readback and rollback verification outside a Git
425
+ checkout without user credentials or external API access.
426
+ - Start the disposable mock on a dynamic loopback port, close it on completion
427
+ or failure, and retain HTML / JSON reports in a unique output directory.
428
+ - Add `--output-dir` and optional `--read-only` controls for the built-in demo.
429
+
430
+ ### Changed
431
+
432
+ - Put the single-command installed-package demo before the source-checkout
433
+ walkthrough and retain configuration onboarding and safety boundaries. During
434
+ release preparation, distinguish the upcoming package from the published stable
435
+ version and do not claim an unpublished PyPI release is available.
436
+ - Give missing spec/config files and offline configuration failures a concise
437
+ next step; an empty write allowlist still sends no PATCH requests.
438
+ - Promote the 2.4.1.dev0 development package to 2.4.1 consistently across runtime,
439
+ package metadata and generated reports; update the release acceptance checklist.
440
+
441
+ ### Quality
442
+
443
+ - Resolve the existing 20 mypy errors in six files using accurate annotations and
444
+ type narrowing, without new suppression directives or weaker mypy settings.
445
+ - Make mypy a blocking CI check and add a minimum 80% branch-aware coverage gate.
446
+ - Add weekly Dependabot checks for pip dependencies and GitHub Actions, without
447
+ automatic merging; exclude the release workflow from dependency updates.
448
+ - Verify installed demo resources, source-independent startup, both demo modes,
449
+ complete database restoration and local server shutdown.
450
+
451
+ ### Security / Safety
452
+
453
+ - The demo accepts no external target or user credentials. Its active PATCH checks
454
+ run only against bundled, disposable data on a dynamic `127.0.0.1` server.
455
+ - Keep auditing users' own APIs read-only by default; `granttrace demo --read-only`
456
+ sends no PATCH requests.
457
+ - Preserve the BOLA / IDOR and Mass Assignment detection criteria, explicit write
458
+ allowlists, independent GET readback, original-state snapshots and rollback
459
+ verification. Failed recovery still blocks subsequent writes.
460
+ - Keep the existing `granttrace --spec ...` CLI, TLS / HTTP / redirect / proxy
461
+ safety boundaries and evidence minimisation unchanged.
462
+
463
+ ## 2.4.0 - 2026-10-03
464
+
465
+ ### Added
466
+
467
+ - Generate offline OpenAPI configuration drafts and missing-input checklists;
468
+ reject unresolved drafts and refuse to overwrite existing files.
469
+ - Add offline HTML report search/status filters and compact severity labels.
470
+ - Support strict OpenAPI style/explode and Swagger collectionFormat parameter
471
+ serialization in scans/readbacks, including arrays and lowercase booleans;
472
+ decline unsupported or ambiguous formats before sending requests.
473
+ - Add explicit per-pair expected_visitor_access for legitimate sharing/admin
474
+ reads, recorded as AUTHORIZED, and six local authorization truth fixtures with
475
+ false-positive/false-negative accounting.
476
+ - Add mandatory Ruff checks, real unittest branch coverage with text/XML/JSON
477
+ evidence, runtime dependency auditing with pip-audit, and a Python CodeQL
478
+ workflow. Keep mypy advisory while recording existing type debt.
479
+ - Add simple issue templates and contribution guidance with private vulnerability
480
+ reporting and reminders to exclude credentials and sensitive target data.
481
+
482
+ ### Changed
483
+
484
+ - Promote the previously identified 2.4.0.dev0 development build to 2.4.0 across
485
+ runtime, package metadata and reports; retain api_sentinel.py and
486
+ APISentinelAuditor compatibility.
487
+ - Use granttrace_report.html when no output path is supplied and align package
488
+ description, version status and GrantTrace branding.
489
+ - Keep a concise five-minute README walkthrough, add identity/readback/restoration
490
+ highlights, and preserve the visible report preview and detailed guide links.
491
+ - Explain identity/resource access, changed fields, restoration and next steps
492
+ before raw evidence. JSON report schema is version 2.
493
+ - Remove tests' dependence on untracked config.json; automate JSON/YAML mock
494
+ restoration and clean wheel installation outside the checkout in CI.
495
+ - Maintain reproducible release verification and local-output ignore rules;
496
+ remove an unused demo image while preserving the report preview.
497
+ - Include example configuration, guides and verification scripts in the source
498
+ distribution so its documented local checks can be reproduced.
499
+
500
+ ### Security / Safety
501
+
502
+ - Preserve default read-only auditing and explicit allowlisted JSON PATCH checks;
503
+ active POST/PUT checks and automated authentication are not added.
504
+ - Preserve independent GET readback, original-state snapshots, finally-protected
505
+ restoration and rollback verification. Failed recovery halts subsequent writes.
506
+ - Preserve TLS verification by default, explicit non-loopback HTTP opt-in and
507
+ minimized/redacted evidence by default.
508
+ - Retain denial, anonymous-leak and invalid-baseline boundaries without changing
509
+ the BOLA / IDOR or Mass Assignment detection criteria during release preparation.
510
+
511
+ Historical release tags and assets, including v2.3.1, remain unchanged.
512
+
513
+ ## 2.3.1 - Verified authorization, snapshot and credential fixes
514
+
515
+ - Require trustworthy, clean anonymous rejection before a visitor-denial branch
516
+ can produce endpoint-level SECURE; leaked business data remains suspicious.
517
+ - Reject non-standard JSON constants and overflowing floats in response parsing.
518
+ Validate the original snapshot and finite request payloads before any PATCH;
519
+ preserve recovery when a post-write readback is invalid.
520
+ - Redact component values from request Cookie headers, including names such as
521
+ path/domain/secure/version, quoted/encoded echoes and known numeric credentials.
522
+ - Align readback parameter arrays, elements and override mappings between the
523
+ editor schema, semantic validator and runtime.
524
+ - Load the same JSON/YAML specification authentication context in configuration
525
+ validation and scanning; reject explicit invalid specifications cleanly.
526
+ - Validate the effective CLI write allowlist against its own readback mappings.
527
+ - Add 45 regression tests across four release modules; all 223 tests pass with
528
+ real PyYAML installed. Repeat complete CLI mock audits for JSON and YAML and
529
+ confirm full database restoration.
530
+ - Build/install the 2.3.1 wheel and smoke-test its installed console entry point;
531
+ refresh sample reports and record current verification separately from history.
532
+
533
+ ## 2.3.0 (v2.3.0-final) - Configuration validation, authoritative identity rules, and release hardening
534
+
535
+ - **Authoritative Configuration Validator (`core/config_validator.py`)**:
536
+ - Implemented offline semantic validation engine for `config.json` without external network requests.
537
+ - Added `--validate-config` CLI flag for pre-flight validation (exit code 0 for valid, 2 for invalid), without target-network requests or state-changing target actions.
538
+ - Normal CLI scanning automatically runs the authoritative preflight check, rejecting invalid configurations before creating the auditor or sending any HTTP requests.
539
+ - Enforced single canonical format for operation keys (`<METHOD> /<path>` with strictly single space), consistent case handling, and spelling error suggestions (Levenshtein distance).
540
+ - Implemented symmetric two-way path collision detection (`paths_collide`) between `ignore_readback_paths` and written/readback paths across both validator and transaction rollback.
541
+ - Unified authentication header recognition rules between Validator and Auditor, standardizing `session`, `credential`, custom `auth_header_names`, and OpenAPI-declared security schemes.
542
+
543
+ - **Schema and Exemplary Assets**:
544
+ - Added standard `config.schema.json` (JSON Schema Draft-07) for editor autocomplete, hover documentation, and structural validation.
545
+ - Added comprehensive `config.example.json` with `$schema` linkage, sample identities, readbacks, and BOLA policies.
546
+
547
+ - **Security and Robustness Hardening**:
548
+ - Bound recursion depth (`MAX_RECURSION_DEPTH = 15`) and explicitly reject non-standard JSON numeric values (`NaN`, `Infinity`).
549
+ - Strict credential sanitization across all diagnostic outputs (`Actual`, `Expected`, errors) and stripped CR/LF/control characters to mitigate known log-injection paths.
550
+
551
+ - **Core Detection Behavior Compatibility**:
552
+ - No intentional behavior changes were made to BOLA decisions, snapshot recovery, diff, generator, or parser logic in this release; all existing regression tests continue to pass.
553
+
554
+ - **Test Suite Expansion**:
555
+ - Total automated tests expanded from 118 to 178 (all 178 passing, 0 failures, 0 errors).
556
+ - Added 22 offline configuration validation tests (`tests/test_config_validation.py`).
557
+ - Added 20 security and sanitization tests (`tests/test_rc2_security_hardening.py`).
558
+ - Added 18 strict regression counterexample tests (`tests/test_rc3_hardening.py`).
559
+
560
+ - **Packaging Hygiene and Metadata**:
561
+ - Standardized Python package version in `pyproject.toml` to PEP 440 compliant `2.3.0`, with GitHub / ZIP delivery tag designated as `v2.3.0-final`.
562
+ - Purged all build artifacts, temporary test reports (`API_Security_Report.html`, `result.json`), and caches (`__pycache__`, `*.pyc`, `.pytest_cache`, `.git`) from the distribution archive.
563
+
564
+ ## 2.2.0 - Regression-driven safety fixes
565
+
566
+ - Snapshot/recover complete written fields, objects and arrays using original
567
+ business values; compare the full readback state, including derived changes.
568
+ - Recover after mutation/readback exceptions, guard recovery's own exceptions,
569
+ and stop later writes on failed verification or asynchronous acceptance.
570
+ - Require configured strong readback consistency for unchanged-write SECURE.
571
+ - Do not mistake 403-with-data, historical denial text, anonymous private
572
+ increments, or undeclared public access for access-control enforcement.
573
+ - Compare effective authentication headers; exclude request/trace echoes from
574
+ identity evidence and support explicit trusted response resource_id_paths.
575
+ - Probe readOnly privilege fields while excluding them from ordinary baselines.
576
+ - Recursively validate samples, intersect allOf constraints and reject invalid
577
+ baselines. Resolve 3.1 ref siblings in their original contexts; reject ambiguous
578
+ 3.0/Swagger structural siblings and missing pointers instead of losing fields.
579
+ - Propagate supported media types, rejecting unsupported JSON Patch arrays.
580
+ - Bound/redact bodies, URLs, known credentials, error text and result metadata.
581
+ - Add zero-check CI failure, coverage/suspicious gates, no-network dry-run and
582
+ case-sensitive CLI allowlist replacement.
583
+
584
+ Migration: PUBLIC needs explicit policy; unchanged active checks need strong
585
+ readback consistency. Rewrite 3.0 structural ref siblings as allOf. Full-state
586
+ verification may require explicitly identifying harmless volatile fields. These
587
+ checks do not establish a universal rollback or privacy guarantee.
588
+
589
+ ## 2.1.0 - Safety hardening
590
+
591
+ - Made read-only auditing the default and limited active mutations to explicitly
592
+ allowlisted JSON `PATCH` operations.
593
+ - Added independent read-before/write/read-after/rollback verification, retrying
594
+ readback and treating asynchronous or ambiguous outcomes as errors.
595
+ - Reworked BOLA decisions around owner, cross-visitor, anonymous, and distinct
596
+ visitor-self baselines. Matching JSON structure alone is never confirmation.
597
+ - Added explicit `CONFIRMED`, `SECURE`, `PUBLIC`, `SUSPICIOUS`, `INCONCLUSIVE`,
598
+ `SKIPPED`, and `ERROR` results with honest attempted/conclusive coverage.
599
+ - Enabled TLS verification by default, blocked redirects, capped response sizes,
600
+ added global throttling, and restricted non-loopback clear-text HTTP.
601
+ - Added default evidence minimisation, secret/PII redaction, hashes, and HTML
602
+ escaping.
603
+ - Expanded OpenAPI parsing to JSON/YAML, safe local external references,
604
+ recursive schemas/compositions, and parameter override semantics.
605
+ - Added constraint-aware parameters, valid request baselines, and one-field
606
+ nested mass-assignment mutations.
607
+ - Added packaging metadata, CI, an Apache-2.0 license, security guidance, and a
608
+ standard-library regression suite.
609
+
610
+ The bundled mock remains intentionally vulnerable in one BOLA route and one
611
+ mass-assignment route so the end-to-end flow can be verified safely on loopback.