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